---
title: "CI/CD Pipeline: Mô hình tư duy 'Dây chuyền sản xuất'"
description: "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."
pubDate: "2023-05-25"
lang: "vi"
slug: "cicd-pipeline-github-actions"
url: "https://hoangyell.com/vi/cicd-pipeline-github-actions/"
author: "HoangYell"
translation_en: "https://hoangyell.com/cicd-pipeline-github-actions/"
categories: ["Developer Tools"]
tags: ["devops", "ci-cd", "github-actions", "docker"]
heroImage: "https://raw.githubusercontent.com/HoangGeek/store/main/webp/photo-1621839673705-6617adf9e890.webp"
---

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:

```markdy
scene type=flowchart width=1200 height=750
theme: light=doodle dark=nebula
layout TB

repo GitCommit "Git Commit (main)"
service LintTest "Lint & Unit Tests"
service DockerBuild "Docker Build & OCI Push"
service SecurityScan "Quét Bảo mật & Lỗ hổng" focal=true
service DeployStaging "Kiểm thử Staging Tự động"
service DeployProd "Phát hành Canary Production"

beat pipeline_flow "Các trạm tự động hoá" {
  show $nodes stagger=50ms
  GitCommit -> LintTest "kích hoạt webhook"
  LintTest -> DockerBuild "test vượt qua"
  DockerBuild -> SecurityScan "artifact sẵn sàng"
  SecurityScan -> DeployStaging "không phát hiện CVE"
  DeployStaging -> DeployProd "canary được duyệt"
  glow SecurityScan "Kiểm tra lỗ hổng nghiêm ngặt"
}

player:
    playback:
      loop true
    controls:
      speed true
      speeds "0.25"
      fullscreen true
      gif true
      theme true
    interaction:
      zoom true
      pan true
      click_to_play true
      double_click_to_reset true
      keyboard false
    chrome:
      badge true
      progress none
```

***

## 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

```yaml
# .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ân | Cách sửa |
|:---|:---|:---|
| **Dependency khác nhau** | CI 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ác** | CI có `DEBUG=True`. Production thì không. | Dùng `env:` trong GitHub Actions và đồng bộ với secret production. |
| **Quên chạy migration** | Code deploy xong, migration chưa chạy. | Thêm bước migration TRƯỚC bước deploy. |
| **Test pass nhưng app crash** | Test 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.

```
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%.

```
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ạ

```
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.
