Featured image of post CI/CD Pipeline: Mô hình tư duy 'Dây chuyền sản xuất'

CI/CD Pipeline: Mô hình tư duy 'Dây chuyền sản xuất'

Tại sao 'chạy trên máy tôi' vẫn xảy ra kể cả dùng Docker? Hướng dẫn chuyên sâu về CI/CD, GitHub Actions, và triển khai Blue/Green không downtime.

Mọi team đều bắt đầu với quy trình deploy giống nhau:

  1. Viết code trên laptop.
  2. Nén thành file zip.
  3. SSH vào server.
  4. Cầu nguyện đừng có lỗi.
  5. Có gì đó vỡ lúc 2 giờ sáng.

CI/CD ra đời để tự động hóa Bước 3–5, giúp nó nhất quán và bớt kinh hoàng hơn.

Đây là Hướng dẫn chuyên sâu về CI/CD. Chúng ta sẽ dùng mô hình “Dây chuyền sản xuất” để hiểu pipelines, GitHub Actions, và nghệ thuật deploy không downtime.


Phần 1: Nền tảng (Mô hình tư duy)

Cách cũ: Thợ thủ công

Trong xưởng rèn, một người làm hết mọi thứ: nung kim loại, tạo hình, làm nguội, kiểm tra, đóng gói. Anh ấy nghỉ là không có hàng. Anh ấy sai là khách nhận được hàng lỗi.

Đây chính là deploy thủ công.

Cách mới: Dây chuyền sản xuất

Nhà máy hiện đại có các trạm: Dập → Hàn → Sơn → Kiểm tra → Đóng gói. Mỗi trạm kiểm tra đầu ra của trạm trước. Nếu Kiểm tra thất bại, không có gì tới Đóng gói.

Đây là CI/CD:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
Commit Code
[Trạm 1: CI — Continuous Integration]
    ├── Chạy Test (Có phá vỡ gì không?)
    ├── Lint Code (Code có sạch không?)
    └── Build Docker Image (Có chạy được không?)
[Trạm 2: CD — Continuous Delivery]
    ├── Đẩy Image lên Registry
    └── Deploy lên môi trường Staging
[Trạm 3: CD — Continuous Deployment]  ← (Tùy chọn: tự động hoàn toàn)
    └── Deploy lên Production

Phần 2: Điều tra (Cấu trúc GitHub Actions)

GitHub Actions là công cụ CI/CD phổ biến nhất cho dev. Một “workflow” chỉ là một file YAML trong .github/workflows/.

Đọc hiểu một Pipeline

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# .github/workflows/deploy.yml

name: "Build and Deploy"

# TRIGGER: Chạy khi nào?
on:
  push:
    branches: [main]   # Chỉ khi push lên nhánh main

jobs:
  # JOB 1: CI (Test & Build)
  build:
    runs-on: ubuntu-latest  # Chạy trên máy gì (GitHub cung cấp miễn phí)
    
    steps:
      - name: "Lấy code về"
        uses: actions/checkout@v4  # Action có sẵn: Pull code về

      - name: "Chạy Tests"
        run: |
          pip install -r requirements.txt
          pytest tests/ --tb=short

      - name: "Build Docker Image"
        run: docker build -t myapp:${{ github.sha }} .

      - name: "Đẩy lên Registry"
        run: |
          docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
          docker push ghcr.io/myrepo/myapp:${{ github.sha }}

  # JOB 2: CD (Deploy) — Chỉ chạy khi build thành công
  deploy:
    needs: build  # ← Job này CHỜ build xong
    runs-on: ubuntu-latest
    
    steps:
      - name: "Deploy lên Server"
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: deploy
          key: ${{ secrets.SSH_KEY }}
          script: |
            docker pull ghcr.io/myrepo/myapp:${{ github.sha }}
            docker stop myapp || true
            docker run -d --name myapp -p 8000:8000 ghcr.io/myrepo/myapp:${{ github.sha }}

Các khái niệm cần chú ý:

  • on: — Trigger. (push, pull_request, schedule).
  • jobs: — Các đơn vị công việc độc lập, có thể chạy song song.
  • needs: — Tạo quan hệ phụ thuộc (Job B chờ Job A xong).
  • secrets: — Mật khẩu/token lưu trong GitHub Settings. Không bao giờ hardcode vào YAML!

Phần 3: Chẩn đoán (Lỗi thường gặp)

Bí ẩn “CI pass nhưng Production vỡ”

Vấn đềNguyên nhânCách sửa
Dependency khác nhauCI cài fresh. Production có rác từ trước.Docker hóa mọi thứ. Dùng immutable artifact.
Biến môi trường khácCI có DEBUG=True. Production thì không.Dùng env: trong GitHub Actions và đồng bộ với secret production.
Quên chạy migrationCode deploy xong, migration chưa chạy.Thêm bước migration TRƯỚC bước deploy.
Test pass nhưng app crashTest không cover code khởi động.Thêm smoke test: curl http://localhost:8000/health sau khi deploy xong.

Phần 4: Giải pháp (Chiến lược Deploy)

Không phải mọi cách deploy đều giống nhau. Chiến lược quyết định mức độ rủi ro.

Chiến lược 1: Rolling Deployment (Mặc định Kubernetes)

Thay thế pod cũ từng cái một. Rủi ro tối thiểu. Có lỗi thì dừng.

Chiến lược 2: Blue/Green Deployment (Không Downtime)

Chạy HAI môi trường production giống hệt nhau. “Blue” đang live. “Green” là phiên bản mới.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Load Balancer
      ├──► Blue (v1) ← LIVE (100% traffic)
      └──► Green (v2) ← Staging (0% traffic)

Sau khi deploy:
      ├──► Blue (v1) ← Dự phòng (0% traffic)
      └──► Green (v2) ← LIVE (100% traffic)
  • Lợi ích: Rollback tức thì. Green gặp lỗi thì flip switch về Blue.
  • Chi phí: Cần gấp đôi hạ tầng.

Chiến lược 3: Canary Deployment (Từng bước)

Triển khai dần dần cho một % người dùng. Không có lỗi thì tăng lên 100%.

1
2
3
4
5
Load Balancer
      ├──► v1 (90% traffic)
      └──► v2 (10% traffic "Canary") ← Thử nghiệm trên user thật

Mô hình tư duy chốt hạ

1
2
3
4
5
6
7
CI (Continuous Integration) -> Kiểm tra chất lượng. "Code này có compile và pass test không?"
CD (Continuous Delivery)    -> Đóng gói. "Artifact này đã sẵn sàng để deploy chưa?"
CD (Continuous Deployment)  -> Xuất hàng tự động. "Deploy thẳng lên production."

Blue/Green   -> Hai nhà máy. Chuyển đổi tức thì.
Canary       -> Thử nghiệm trên 10% khách hàng thật trước.
Rolling      -> Thay thế công nhân từng người một.

Quy tắc CI/CD tốt:

  1. Phản hồi nhanh: Pipeline phải báo lỗi trong vòng 5 phút.
  2. Mọi thứ là code: Config pipeline nằm trong Git. Không click chuột trên Jenkins UI.
  3. Artifact bất biến: Build một lần, deploy cùng image đó khắp nơi. Không bao giờ git pull trên server production.
Được tạo với sự lười biếng tình yêu 🦥

Subscribe to My Newsletter