CI/CD Pipeline với GitHub Actions: Tự Động Hóa Triển Khai Ngay Hôm Nay

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

Bắt Đầu Nhanh: Workflow GitHub Actions Đầu Tiên Trong 5 Phút

Nếu bạn đã từng push code rồi vội vàng SSH thủ công vào server để deploy — bạn biết cái cảm giác đó rồi. GitHub Actions giải quyết vấn đề đó cho tôi khoảng hai năm trước. Từ đó đến nay không còn cảnh rollback lúc nửa đêm vì deploy tay bị lỗi nữa.

Ý tưởng cốt lõi: viết một file YAML, commit vào repo, và GitHub sẽ tự động chạy script của bạn mỗi khi có sự kiện xảy ra — push code, tạo pull request, hay gắn tag. Không cần CI server riêng, không cần cài Jenkins, không mất thêm tiền trừ khi bạn thực sự cần.

Hai lệnh để bắt đầu:

# Tạo thư mục workflow
mkdir -p .github/workflows
touch .github/workflows/ci.yml

Dán pipeline tối giản này:

name: CI Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Lấy code về
        uses: actions/checkout@v4

      - name: Cài đặt Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Cài đặt thư viện
        run: pip install -r requirements.txt

      - name: Chạy tests
        run: pytest tests/

Commit file này, push lên GitHub, rồi vào tab Actions của repo. Bạn sẽ thấy workflow đang chạy. Đó là CI pipeline đầu tiên của bạn rồi đó.

Tìm Hiểu Sâu: Hiểu Cấu Trúc Workflow

Cấu trúc YAML trực quan hơn bạn nghĩ. Bốn khái niệm sau giải thích được 90% những gì bạn sẽ gặp hàng ngày.

Triggers (on:)

Block on: định nghĩa điều kiện kích hoạt workflow. Đây là những trigger tôi dùng thường xuyên nhất:

on:
  push:
    branches: [main]
    tags:
      - 'v*'          # Kích hoạt khi có tag phiên bản như v1.0.0
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 2 * * *'   # Chạy hàng ngày lúc 2 giờ sáng UTC
  workflow_dispatch:       # Cho phép kích hoạt thủ công từ GitHub UI

Trigger workflow_dispatch thường bị đánh giá thấp. Chỉ cần click một nút trong GitHub UI là có thể kích hoạt deployment thủ công — rất tiện cho môi trường staging khi bạn không muốn tự động hóa hoàn toàn.

Jobs và Steps

Mặc định, các job chạy song song. Các step bên trong một job chạy tuần tự. Muốn các job chạy theo thứ tự? Dùng needs::

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pytest tests/

  build:
    runs-on: ubuntu-latest
    needs: test    # Chỉ chạy nếu 'test' thành công
    steps:
      - uses: actions/checkout@v4
      - run: docker build -t myapp:latest .

  deploy:
    runs-on: ubuntu-latest
    needs: build   # Chờ 'build' thành công
    steps:
      - run: echo "Đang triển khai..."

Quản Lý Secrets

Không bao giờ hardcode thông tin xác thực vào file workflow. Vào repo → Settings → Secrets and variables → Actions để thêm secrets. Tham chiếu chúng như sau:

- name: Triển khai lên server
  env:
    SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
    SERVER_HOST: ${{ secrets.SERVER_HOST }}
  run: |
    echo "$SSH_KEY" > /tmp/deploy_key
    chmod 600 /tmp/deploy_key
    ssh -i /tmp/deploy_key -o StrictHostKeyChecking=no \
      ubuntu@$SERVER_HOST "cd /app && git pull && systemctl restart myapp"

Sử Dụng Nâng Cao: Các Pattern Hoạt Động Tốt Trong Thực Tế

Matrix Build cho Nhiều Môi Trường

Khi cần kiểm tra code chạy được trên Python 3.9, 3.10 và 3.11, tôi không viết ba job riêng lẻ. Matrix strategy xử lý điều đó:

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.9', '3.10', '3.11']
        os: [ubuntu-latest, windows-latest]

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      - run: pytest tests/

Đó là 6 job chạy song song — mọi phiên bản Python trên mọi hệ điều hành. Khi có lỗi, GitHub hiển thị chính xác tổ hợp nào bị lỗi. Python 3.11 trên Windows crash trong khi 3.9 vẫn pass? Bạn sẽ biết ngay sau một lần chạy.

Cache Dependencies

Cài đặt lại từ đầu mỗi lần chạy làm pipeline chậm đi. Hãy cache các gói pip giữa các lần chạy:

- name: Cache các gói pip
  uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
    restore-keys: |
      ${{ runner.os }}-pip-

- name: Cài đặt thư viện
  run: pip install -r requirements.txt

Cache key băm nội dung requirements.txt, nên tự động invalidate khi dependencies thay đổi. Với một project Python cỡ trung bình, điều này giúp cắt giảm thời gian cài đặt từ ~60 giây xuống còn ~5 giây.

Build Docker và Push Lên Registry

Đây là workflow build-and-push đầy đủ cho Docker Hub:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Đăng nhập vào Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      - name: Build và push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            myuser/myapp:latest
            myuser/myapp:${{ github.sha }}

Mỗi lần build đều được gắn tag bằng git commit SHA. Rollback trở nên đơn giản — bạn luôn biết chính xác commit nào đang chạy trên production.

Triển Khai Theo Môi Trường

GitHub Environments cho phép bạn thêm quy tắc bảo vệ và tách biệt secrets theo từng môi trường (staging và production):

jobs:
  deploy-staging:
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - name: Triển khai lên staging
        run: ./deploy.sh staging

  deploy-production:
    runs-on: ubuntu-latest
    environment: production   # Có thể yêu cầu phê duyệt thủ công
    needs: deploy-staging
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Triển khai lên production
        run: ./deploy.sh production

Cấu hình môi trường production yêu cầu người review, và không gì được triển khai cho đến khi ai đó click Approve trong GitHub UI. Một cửa kiểm soát thủ công. Mọi thứ còn lại vẫn tự động.

Mẹo Thực Tế Từ Các Pipeline Thực Chiến

Giữ Workflow Tập Trung

Một lỗi phổ biến là nhét tất cả mọi thứ vào một file workflow duy nhất. Hãy tách biệt: file ci.yml để test mỗi khi push, file deploy.yml chỉ kích hoạt khi có tag hoặc merge vào main. File nhỏ hơn dễ debug hơn khi có sự cố lúc 11 giờ đêm.

Dùng Điều Kiện if: để Bỏ Qua Bước Thông Minh

- name: Chỉ triển khai trên nhánh main
  if: github.ref == 'refs/heads/main' && github.event_name == 'push'
  run: ./deploy.sh

Test chạy trên mọi nhánh. Deploy chỉ kích hoạt trên main. Các nhánh feature không thể vô tình tác động đến production.

Dừng Sớm, Nhưng Đừng Quá Vội

strategy:
  fail-fast: false   # Cho phép tất cả matrix job hoàn thành dù có job bị lỗi
  matrix:
    python-version: ['3.9', '3.10', '3.11']

Hành vi mặc định là hủy tất cả matrix job ngay khi một job bị lỗi. Đặt fail-fast: false và bạn sẽ có bức tranh toàn cảnh — có thể 3.9 pass nhưng 3.11 bị lỗi. Nhiều dữ liệu hơn, sửa nhanh hơn.

Thêm Badge Trạng Thái Vào README

GitHub tự động tạo badge trạng thái cho mọi workflow. Tìm nó trong tab Actions → workflow của bạn → menu ba chấm → Create status badge. Dán vào README của bạn:

![Trạng thái CI](https://github.com/youruser/yourrepo/actions/workflows/ci.yml/badge.svg)

Theo Dõi Số Phút Runner

Gói miễn phí cho 2.000 phút mỗi tháng cho repo riêng tư. Repo công khai có số phút không giới hạn. Nếu bạn đang tiêu tốn quota nhanh vì matrix build nặng, hai điều này sẽ giúp ích: cache tốt hơn, và bộ lọc paths: để các thay đổi docs không kích hoạt toàn bộ test:

on:
  push:
    paths:
      - 'src/**'
      - 'tests/**'
      - 'requirements.txt'
    # Thay đổi ở docs/ hoặc README.md sẽ không kích hoạt pipeline

GitHub Actions biến checklist deploy thủ công 15 bước thành chỉ một cái push. Đường cong học tập nhẹ nhàng hơn bạn nghĩ — một khi hiểu được cấu trúc YAML, phần còn lại sẽ tự nhiên theo sau. Pipeline nằm ngay trong repo cũng có nghĩa là chúng được quản lý phiên bản cùng với code. Bắt đầu với phần quick-start ở trên, rồi dần dần áp dụng các pattern nâng cao khi cần.

Share: