CI/CD
CI/CD .... ủa từ đâu ra vậy ?
Detect Bug Earlier
The Old Story
- Thuở xa xưa developer rất ít khi merge code, 1 người sẽ giữa code hiện tại của mình cho đến khi code xong 1 tính năng rồi mới merge và push lên Github
- Giả sử chúng ta có 1 team với 2 developer A và B. Một ngày đẹp trời nó team này nhân 1 dự án lớn toàn tính năng khủng. Thế là sau khi nhận dự án A và B bắt đầu chia nhau ra code dần các tính năng
- Vì là tính năng khủng nên cả A và B đều mất khoảng tg rất lâu mới có thể hoàn thành (2 tháng), tuy nhiên vì trước h ko code thói quen thường xuyên push và merge code nên phải 2 tháng sau khi quá dev tính năng kết thúc A và B mới có thể ngồi lại cùng nhau để merge code
- Tuy nhiên quá trình merge code này đã trở nên cực kì phức tạp vì lượng code mà 2 bên thay đổi quá lớn. Giới dev thường hay đồn là Merge Hell :)))
First Approach
- Để giái quyết vấn đề trên. Team của A và B đã quyết định lập ra 1 khế ước là họ cần push code và merge code mỗi ngày. Trước khi ai leave office thì đều phải push code của ngày hôm đó lên
- Cách giải quyết trên tạm ổn, họ đã không còn gặp Merge Hell nữa, tuy nhiên lúc này lại có 1 vấn đề khác xảy ra
- 1 ngày đẹp trời B đang dev, nhưng vì vợ B có việc gấp và cần B phải về. Do đang dev nên B đã push code vội trước khi leave office mà quên xoá bug đang tồn động trong code lên
- Đang tiếc thay bug này không dễ phát hiện, điều đó khiến A pull code của B nhưng không phát hiện bug và bị bug kiến code trở nên sai hướng và mất rất nhiều thời gian để về đúng hướng trở lại
Final Approach
- Như thế ta có thể trong TH trên ta cần 1 lớp hàng rào, khi B push code lên, code của B cần được tự động test để loại bỏ bug trước khi được merge vào source code cho toàn team sử dụng
- Để làm được như vậy ta cần 1 server luôn lăng nghe sự thay đổi khi có developer nào đó push hoặc commit code ⇒ Người ta gọi server đó là CI Server
Deploy Easier
- Anh A là devops của 1 công ty X, vì là startup nên quá trình deploy và build cũng khá dễ
- Anh A chỉ cần chờ code được merge từ team Dev và deploy nó lên trên mt production
- Không lâu sau đó, công ty X ngày càng phát triển và họ cần có 1 đội ngũ QA để test ứng dụng trước khi release
- Lúc này công việc của anh A vẫn chưa khó khắn lắm thay vì deploy ngay lên MT production thì h anh A sẽ deploy lên MT QA trước để Tester test
- Một lần nữa cty X lại phát triển, nhiều cty thứ 3 muốn hợp tác với cty X.
- Lúc này để thuận tiện, với mỗi cty thứ 3 anh A phải cung cấp 1 mt test riêng. Và khi có cập nhật về code, anh A sẽ phải deploy trên từng mt đó
- Sẽ ra sao nếu có 100 cty thứ 3 muốn hợp tác với cty X. Anh A sẽ phải deploy lên 100 MT ⇒ Chính vì khó khăn này anh A cần có 1 cách nào đó giúp anh A có thể xây dựng kịch bản và tự động hoá quá trình deploy ⇒ Các tool CI/CD sẽ giúp anh A làm việc này
CI/CD ra đời đã thay đổi thế nào trong giới công nghệ ?
Kể từ khi các qui trình CI / CD ra đời cũng là lúc các team Dev nhận ra rằng họ cần một người có thể giúp họ không chỉ triển khai qui trình này, mà còn có thể update và maintain nó khi cần thiết và từ đó 1 vị trí mới trong các team lập trình được vinh danh ⇒ Shout out for DevOps developer.
Và cũng kể từ khi CI / CD ra đời một số miếng bánh dần hé lộ ra để các công ty công nghệ như Github / Gitlab / CircleCI nhảy vào với tư tưởng là chúng tôi có giúp bạn có được 1 qui trình CI /CD chỉ trong vài click chuột
Và cũng chính vì lý do đó từ đây chúng ta có 2 trường phái sử dụng CI / CD rõ rệt
- Tự build 1 flow CI / CD (CI / CD with Jenkins)
- Sử dụng các dịch vụ có sẵn của Github / Gitlab
CI/CD in Jenkins vs CI/CD in Github
CI/CD in Jenkins
Overview
- Jenkins là 1 open source giúp chúng ta build 1 quy trình CI / CD
Advantage
- Vì là open source nên chúng ta ko phải trả phí cho việc sử dụng Jenkins
- Vì tự tay chúng ta build CI/CD nên Jenkins cho chúng ta có thể custom được tất qui trình CI/CD theo ý mình
- CI Server có thể lắng nghe từ nhiều nguồn source code khác nhau Github / Gitlab / Bitbucket
Disadvantage
- Khó cho người mới bắt đầu vì qui trình config phức tạp
- Chúng ta không phải trả chi phí cho việc sử dụng Jenkins, tuy nhiên chúng ta phải trả tiền để thuê server build code của chúng ta và chạy test
Dành cho ai
- Các công ty, doanh nghiệp muốn làm chủ 100% qui trình CI / CD riêng
- Có đội ngũ Devops dày dặn kinh nghiệm để develop và maintain 1 qui trình CI / CD
CI/CD in Github (GIthub Action)
Overview
- Github Action là 1 dịch vụ của Github, giúp chúng ta có ngay được 1 flow CI/CD chỉ từ 1 file config và không cần phải làm thêm bất kì thứ gì cả (thuê server, maintain server ...)
- Tuy nhiên chúng ta sẽ trả phí cho Github Action thời gian chúng ta dành để build project
- Cấu hình server mạnh sẽ giúp chúng ta build nhanh hơn vì thế mức giá trên 1 phút build cũng sẽ cao hơn
Advantage
- Ko phải config nhiều, chỉ cần code 1 file là xong
- Tính tiền theo phút ⇒ pay as you go, thậm chí có free version, phù cho người mới học về Devops ⇒ ko phải đau đầu thuê 1 server
Disadvantage
- Phụ thuộc vào Github, source code trước h lưu ở Gitlab hay Bitbucket ko chơi được với em này
- Vì server build code được cung cấp bởi Github nên khó custom, không phù hợp với 1 số dự án lớn
- Free version đồng nghĩa với máy yếu và thời gian build lâu hơn
Example
Scenario 1
- Một công ty công nghệ đang phát triển 1 codebase rất là lớn
- Mỗi lần build toàn bộ cái web này phải tốn hơn 50 server
- Mỗi lần test công ty này cần hơn 100 server để tạo ra 1 triệu user ảo nhầm giả lập lại trường hợp website của họ khi có 1 triệu user vào cùng 1 lúc sẽ handle thế nào
- Khi fail thì gửi mail đến các phòng bạn liên quan
Scenario 2
- Một công ty startup ko có tiền thuê Devops, tuy nhiên CEO vẫn muốn công ty ko bị lệ thuộc vào Devops mà cần phải đưa ra sản phầm càng nhanh càng tốt
- Vì là startup nên codebase cũng nhỏ ko cần quá nhiều resource để build
- Vì là startup nên test chưa phải là mục tiêu cao nhất, cái quan trọng là có thể mang được idea đến cho user
CI/CD Github Hand-on Actions
Requirement
- Môi trường NodeJS → để code 1 simple web
- Tài khoản Herouku dùng để deploy
- Tài khoản Github để chạy Github Actions
B1) Khởi tạo project Nodejs đơn giản
- Để khởi tạo project Nodejs các bạn gõ theo các lệnh dưới đây
yarn init // Khởi tạo 1 project Nodejs -> sau khi chạy xong dòng này chúng ta sẽ có được 1 file package.json đơn giản yarn add express // Install web framework để build simple web với Nodejs yarn add mocha supertest // Install 2 testing tool là mocha và supertest để thực hiện phase test yarn add nodemon // Install package này để thực hiện việc chạy live test server
- Sau khi đã khởi tạo và cài đặt các thư viện cần thiết xong ta tiến thành
tạo
file index.js với nội dung như sau
const express = require("express"); const port = process.env.PORT || 8000; const app = express(); app.get("/", (req, res) => { res.send("Welcome to CI/CD Exercise of CS101"); }) app.listen(port, () => { console.log("Server is listening"); }); module.exports = app;
- Từ đoạn code trên ta có thể thấy ta đang tạo 1 web với configuration sau
đây
- Web được chạy ở port mặc định là 8000
- Trang index của web trả về 1 đoạn text là Welcome to CI/CD Exercise of CS101
- Sau đó ta thêm các script cần thiết để có khởi động web lên (Dưới đây là
file
package.json sau khi ta đã thêm script)
{ "name": "github-actions", "version": "1.0.0", "main": "index.js", "license": "MIT", "scripts": { // Added script here "test": "mocha ./test/* --exit", // script used for testing phase "start": "node index.js", // script used for start in production environment "dev": "nodemon index.js" // script used for start in dev environment }, "dependencies": { "express": "^4.17.1", "mocha": "^9.1.3", "nodemon": "^2.0.14", "supertest": "^6.1.6" } }
- Cuối cùng ta gõ lệnh yarn dev để tiến hành chạy web
yarn dev
- Sau khi chạy xong ta sẽ có được hình như dưới đây
- Và bây giờ ta tiến hành đoạn code để test app của chúng ta
const request = require("supertest"); const app = require("../index"); describe("GET /", () => { it("responds with Welcome to CI/CD Exercise of CS101!", (done) => { request(app).get("/").expect("Welcome to CI/CD Exercise of CS101", done); }); });
- Bạn cũng có thể chạy yarn test để test thử app của chúng ta. Nếu thành công
sẽ
hiện ra như hình dưới đây
yarn test
- Ngoài ra bạn có thể thêm .gitignore để ignore đi một số folder nặng nhưng
lại
không cần thiết. Bạn cũng có thể sử dụng file code .gitignore như ở dưới đây
node_modules/ yarn.lock
B2) Tạo Github Actions đầu tiên
- Tạo 1 Github Repo. Sau khi tạo xong ta sẽ thấy trang dưới đây (Nếu ko có README)
- Gõ các lệnh sau để push code lên Github
- Sau khi push code thành công repo của chúng ta sẽ trông giống như vậy
- Và bây giờ chúng ta hãy cùng workflow đầu tiên trong Github Actions. Để tạo được workflow đầu tiên ta cần tạo 1 folder có tên là .github và tạo thêm 1 folder workflows bên trong folder .github
- Sau đó ta tạo 1 file tên là app.yml chứa toàn bộ thông tin config của
workflow
và copy thông tin config ở dưới đây
name: Node.js CI on: // Đầu tiên chúng ta cần setup workflow listener cho workflows, khi nào thì workflows bắt đầu chạy push: // Ở đây ta đang setup cho workflow sẽ chạy khi chúng ta push code lên branch main branches: [main] jobs: // Sau khi đã setup xong workflow listener, ta tiến hành setup các job cho workflows build: // Trong workflow đơn giản này ta chỉ có 1 job duy nhất tên là build. 1 job trong workflows sẽ bao gồm nhiều steps runs-on: ubuntu-latest // Đầu tiên ta cần chọn môi trường để chạy job - Ở đây chúng ta đang setup workflow sẽ chạy trên máy ảo có HĐH ubuntu-latest cho job này steps: // Dưới đây là các step ta sẽ có trong job - uses: actions/checkout@v2 // 1. Checkout code mới nhất từ github repo - name: Use Node.js // 2. Setup nodejs lên trên máy ảo dùng để chạy job uses: actions/setup-node@v2 with: node-version: '14.x' - run: npm install // 3. Tiến hành install các library từ node - run: npm run build --if-present // 4. Build web của chúng ta - run: npm test // 5. Tiến hành chạy web được build
- Sau khi đã tạo xong file config cho workflow ta tiến hành push chúng lên để
github hiểu nó với các lệnh dưới đây
git add . git commit -m "add workflow" git push origin main
- Sau đó ta thay đổi nội dung file README.md
(hoặc
bất cứ 1 file nào trong src code) để tiến hành commit và push 1 lần nữa cho việc test workflow
git add . git commit -m "test workflow" git push origin main
- Ta có thể kiểm tra workflow đã đươc test thành công chưa bằng cách vào mục Actions của Github và ta sẽ thấy kết quả của các lần test sẽ hiện ra như dưới đây
B3) Setup với Heroku và thêm deployment cho workflow
- Đến phần này chúng ta đã hoàn tất build thành công workflow cho bản thân mình. Tuy nhiên hiện tại workflow chỉ thực hiện đúng 1 job là build web. Nếu ta muốn deploy web thì cần phải làm gì ?
- Ở phần này mình sẽ hướng dẫn các bạn config 1 job deploy trong Github Actions, cụ thể hơn chúng ta sẽ tiến hành deploy web lên Heroku
- Để tạo Heroku đầu tiên ta cần truy cập vào https://www.heroku.com/. Sau đó chọn Signup và hoàn thành form
- Sau khi tạo xong Heroku ta sẽ vào được trang chủ với giao diện như dưới đây
- Sau khi đã tạo được tài khoản Heroku ta tiến hành thêm job deploy vào
workflow
name: Node.js CI on: push: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Use Node.js uses: actions/setup-node@v2 with: node-version: "14.x" - run: npm install - run: npm run build --if-present - run: npm test // Adding job below here deploy: needs: build runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: akhileshns/heroku-deploy@v3.12.12 with: // Để deploy lên heroku ta cần 3 thành phần sau heroku_api_key: ${{secrets.HEROKU_API_KEY}} /* Ở đây chúng ta không muốn lộ HEROKU_API_KEY ở trong code nên ta sẽ dùng Github Secrets Key để giúp chúng ta giấu đi thông tin về API Key */ heroku_app_name: "gdscxsab-cicd-lab01" heroku_email: "gdscxsab@gmail.com"
- Để lấy được HEROKU_API_KEY ta cần trang settings của Account
- Sau đó ta vào trang Settings của Github Repo và chọn Secrets
- Tiến hành thêm 1 secret với name là HEROKU_API_KEY và content là API Key của chúng ta
- Xong sau đó chúng ta sẽ tiến hành push code và test thử job deploy này