Trong quy trình kỹ thuật phần mềm hiện đại, tốc độ chuyển giao mã nguồn từ môi trường phát triển cục bộ lên hệ thống máy chủ Production quyết định trực tiếp khả năng thích ứng của doanh nghiệp nhưng đồng thời cũng là điểm nhạy cảm nhất về mặt độ tin cậy vận hành. Tại nhiều tổ chức công nghệ, quy trình phát hành ứng dụng vẫn phụ thuộc vào các thao tác thủ công rời rạc: kỹ sư tự chạy lệnh docker build trên máy cá nhân, gắn nhãn ghi đè :latest đẩy lên kho lưu trữ chung, rồi đăng nhập qua giao thức SSH vào máy chủ để khởi động lại container. Mô hình thủ công này tiềm ẩn 4 rủi ro kỹ thuật nghiêm trọng: sự sai lệch môi trường biên dịch (Configuration Drift), mã nguồn chưa qua kiểm thử tự động vẫn lọt lên môi trường thật, hình ảnh container chứa các lỗ hổng bảo mật hệ điều hành (CVEs) mức độ nghiêm trọng không được phát hiện, và thời gian chết (Downtime) kéo dài khi bản cập nhật mới bị treo lúc khởi động mà không có cơ chế tự động quay lui (Rollback).
Việc xây dựng CI/CD Pipeline với GitHub Actions và Docker theo chuẩn Production giải quyết triệt để các điểm nghẽn trên bằng cách thiết lập một dây chuyền lắp ráp phần mềm tất định (Deterministic Software Delivery Pipeline). Mọi thay đổi mã nguồn đều phải vượt qua các chốt chặn kiểm tra tự động: từ phân tích cú pháp tĩnh (Linting), chạy kiểm thử đơn vị (Unit Testing), đóng gói hình ảnh container tốc độ cao nhờ cơ chế bộ nhớ đệm lớp của Docker Buildx (BuildKit), quét lỗ hổng bảo mật bắt buộc bằng Aqua Security Trivy, định danh tạo tác bất biến theo mã băm Git SHA trên GitHub Container Registry (GHCR), cho đến bước triển khai nguyên tử (Atomic Rollout) có kiểm tra sức khỏe dịch vụ (/healthz) và tự động phục hồi trạng thái cũ nếu phát hiện lỗi.
Bài viết kỹ thuật chuyên sâu này hướng dẫn từng bước thiết kế, cấu hình và vận hành một luồng CI/CD hoàn chỉnh từ lúc kỹ sư thực hiện lệnh git push cho đến khi container vận hành an toàn trên máy chủ Production, cung cấp toàn bộ mã cấu hình chuẩn xác sẵn sàng áp dụng cho các hệ thống thực tế.
- 1. Kiến trúc Luồng CI/CD Pipeline Hiện đại từ Git Commit đến Production
- 1.1 Phân tách Trách nhiệm giữa Continuous Integration (CI) và Continuous Deployment (CD)
- 1.2 Sơ đồ Kiến trúc Luồng Công việc Đa Tầng và Chuỗi Tương tác Thực thi Runtime
- 2. Thiết lập Tầng Continuous Integration (CI): Linting, Unit Testing và Concurrency Control
- 2.1 Kiểm soát Xung đột Pipeline bằng Concurrency Group và Phân quyền GITHUB_TOKEN Tối thiểu
- 2.2 Tự động hóa Linting, Static Analysis và Unit Testing với Pytest và Coverage
- 3. Tối ưu hóa Tốc độ Build Docker Image với BuildKit & GitHub Actions Cache (type=gha)
- 3.1 Cơ chế Hoạt động của Docker Buildx và Bộ nhớ Đệm Lớp (Layer Caching type=gha,mode=max)
- 3.2 Chiến lược Định danh Image Bất biến (Immutable Git SHA Tagging vs. latest Anti-Pattern)
- 4. Tích hợp Chốt chặn Bảo mật (DevSecOps Security Gate) với Trivy và Đăng tải lên GHCR
- 4.1 Quét Lỗ hổng CVE Image Tự động bằng Aqua Security Trivy (exit-code: 1 trên CRITICAL/HIGH)
- 4.2 Xác thực và Đẩy Image lên GitHub Container Registry (GHCR) kèm Metadata Chuẩn OCI
- 5. Tự động hóa Continuous Deployment (CD) An toàn với GitHub Environments và Healthcheck Rollback
- 5.1 Bảo vệ Môi trường Production bằng GitHub Environments, Protection Rules và SSH Bastion
- 5.2 Thiết kế Docker Compose Production với Healthcheck và Quản lý Tài nguyên
- 5.3 Kịch bản Triển khai Nguyên tử (Atomic Rollout) và Tự động Rollback khi Healthcheck Thất bại
- 6. Kiểm tra Thực thi Pipeline bằng GitHub CLI (gh) và Xử lý Sự cố Thường gặp
- 6.1 Giám sát Log Workflow và Kiểm tra Cache Hit Ratio qua GitHub CLI (gh run)
- 6.2 Xử lý Sự cố Tràn Dung lượng Cache GitHub Actions (10GB Limit) và Lỗi Quyền GHCR Packages
- 7. Tổng kết & Tài liệu tham khảo (References)
- 7.1 Checklist Chuẩn hóa CI/CD Pipeline cho Đội ngũ Kỹ thuật
- 7.2 Tài liệu tham khảo & Nguồn đối chiếu Chính thống
1. Kiến trúc Luồng CI/CD Pipeline Hiện đại từ Git Commit đến Production
1.1 Phân tách Trách nhiệm giữa Continuous Integration (CI) và Continuous Deployment (CD)
Một kiến trúc đường ống phát hành phần mềm chuẩn mực luôn phân định rõ ranh giới kỹ thuật cũng như quyền hạn bảo mật giữa hai pha Tích hợp Liên tục (Continuous Integration — CI) và Triển khai Liên tục (Continuous Deployment — CD):
- Tầng Continuous Integration (CI — Phản hồi Nhanh & Kiểm chứng Chất lượng): Được kích hoạt trên mọi sự kiện
pull_requestvàpushvào nhánh chính. Nhiệm vụ duy nhất của tầng này là xác minh tính đúng đắn của mã nguồn thông qua bộ công cụ kiểm tra định dạng (Linter), kiểm tra kiểu tĩnh (Static Type Checking) và kiểm thử đơn vị (Unit Tests). Tầng CI hoàn toàn không có quyền truy cập vào thông tin xác thực của kho lưu trữ container hay khóa SSH của máy chủ Production. - Tầng Đóng gói và Kiểm định Tạo tác (Artifact Packaging & DevSecOps Gate): Thực hiện nguyên lý "Biên dịch một lần, Triển khai mọi nơi" (Build Once, Deploy Anywhere). Thay vì biên dịch lại mã nguồn trên từng máy chủ đích, đường ống đóng gói ứng dụng thành một Docker Image duy nhất được gắn nhãn bất biến theo mã commit Git (
sha-<commit>), sau đó quét toàn diện các gói thư viện hệ điều hành và ngôn ngữ lập trình bằng công cụ bảo mật Trivy trước khi cho phép đăng tải lên Registry. Để hình ảnh container tạo ra ở bước này đạt kích thước tối giản và loại bỏ hoàn toàn các trình biên dịch thừa, bạn cần kết hợp chặt chẽ với kỹ thuật được trình bày trong bài viết Tối ưu hóa Docker Image với Multi-stage Build và Alpine Linux. - Tầng Continuous Deployment (CD — Phát hành Nguyên tử & Tự phục hồi): Chỉ được kích hoạt khi cả tầng CI và tầng quét bảo mật đều trả về mã thoát thành công (
Exit Code 0) trên nhánhmain. Tầng CD chịu sự giám sát của quy tắc bảo vệ môi trường (GitHub Environments), kéo đúng phiên bản hình ảnh đã được kiểm định từ GHCR xuống máy chủ đích, khởi chạy container mới, xác minh điểm cuối kiểm tra sức khỏe (/healthz) và tự động khôi phục về phiên bản ổn định liền trước nếu bản phát hành mới gặp sự cố khởi tạo.
Bảng dưới đây đối chiếu sự khác biệt kiến trúc giữa quy trình phát hành thủ công truyền thống và đường ống CI/CD đa tầng chuẩn Production:
| Tiêu chí Kỹ thuật | Quy trình Build & Deploy Thủ công / Script Rời rạc | Pipeline CI/CD Đa tầng (GitHub Actions + Buildx + Trivy + Atomic CD) |
|---|---|---|
| Định danh Phiên bản Image | Sử dụng nhãn động :latest, không thể truy vết chính xác container đang chạy tương ứng với commit Git nào |
Gắn nhãn bất biến sha-<7_ky_tu_commit> kết hợp nhãn chuẩn OCI (org.opencontainers.image.revision) |
| Cơ chế Lưu đệm Biên dịch (Build Cache) | Phụ thuộc vào ổ đĩa cục bộ của máy cá nhân hoặc phải tải lại toàn bộ layer từ đầu trên mỗi GitHub Runner mới | Chia sẻ bộ nhớ đệm lớp trung gian qua dịch vụ GitHub Actions Cache (type=gha,mode=max) giữa mọi lần chạy |
| Kiểm soát Lỗ hổng Container (CVE Gate) | Không kiểm tra hoặc chỉ quét định kỳ sau khi container đã chạy trên Production | Chặn cứng ngay trong pipeline (exit-code: 1) nếu phát hiện lỗ hổng mức CRITICAL hoặc HIGH đã có bản vá |
| Quản lý Thông tin Xác thực (Registry Auth) | Lưu trữ Personal Access Token (PAT) hoặc mật khẩu Docker dài hạn dễ bị rò rỉ | Sử dụng mã thông báo tạm thời GITHUB_TOKEN tự động hết hạn ngay khi kết thúc phiên chạy job |
| Cơ chế Phục hồi Khi Lỗi (Rollback Strategy) | Kỹ sư phải tự đăng nhập SSH, tìm lại bản cũ và chạy lại lệnh khởi tạo thủ công trong lúc hệ thống đang lỗi | Kịch bản deploy-rollout.sh tự động phát hiện trạng thái unhealthy và quay lui về PREVIOUS_TAG trong 60 giây |
1.2 Sơ đồ Kiến trúc Luồng Công việc Đa Tầng và Chuỗi Tương tác Thực thi Runtime
Để ngăn chặn hiện tượng một bản cập nhật lỗi đi thẳng lên môi trường vận hành, các tác vụ (Jobs) trong GitHub Actions được tổ chức thành một Đồ thị Có hướng Không Chu trình (Directed Acyclic Graph — DAG) thông qua từ khóa needs. Công việc đứng sau chỉ được phép khởi tạo máy ảo thực thi (Runner) khi công việc đứng trước đã hoàn tất trọn vẹn.
Sơ đồ kiến trúc dưới đây mô tả luồng kiểm soát chất lượng qua 4 tầng từ lúc kỹ sư đẩy mã nguồn cho đến khi hoàn tất triển khai hoặc tự động quay lui:
flowchart TD
subgraph SourceControl ["1. Quản lý Mã nguồn: GitHub Repository"]
A["Developer git push / Pull Request"] --> B["GitHub Actions Trigger: main / PR"]
B --> C["Concurrency Guard & Least-Privilege GITHUB_TOKEN"]
end
subgraph StageCI ["2. Tầng Continuous Integration: Job test"]
C --> D["Setup Python 3.11 & Pip Dependency Cache"]
D --> E["Chạy Linter Ruff & Unit Tests Pytest"]
E --> F{"Tests & Linter Pass?"}
F -- "Thất bại: Exit != 0" --> X1["Chặn Merge / Dừng Pipeline & Báo lỗi"]
end
subgraph StageBuildScan ["3. Tầng Buildx & Chốt chặn DevSecOps: Job build-scan-push"]
F -- "Thành công: Exit 0" --> G["Khởi tạo Docker Buildx & GHA Layer Cache: type=gha"]
G --> H["Build Candidate Image với Tag bất biến: sha-commit"]
H --> I["Quét Lỗ hổng bằng Trivy: CRITICAL & HIGH CVEs"]
I --> J{"Trivy Gate Pass?"}
J -- "Phát hiện CVE Nghiêm trọng" --> X2["Hủy Image & Chặn Push lên Registry"]
J -- "An toàn: 0 CRITICAL / HIGH" --> K["Push Image & Cập nhật GHA Cache mode=max lên GHCR"]
end
subgraph StageCD ["4. Tầng Continuous Deployment: Job deploy-production"]
K --> L["GitHub Environment Protection: Production Approval"]
L --> M["SSH Thực thi scripts/deploy-rollout.sh trên Server"]
M --> N["Kiểm tra Healthcheck /healthz trong 60 giây"]
N --> O{"Container Healthy?"}
O -- "Healthy" --> P["Hoàn tất Rollout & Dọn dẹp Image cũ"]
O -- "Unhealthy / Timeout" --> Q["Tự động Rollback về PREVIOUS_TAG & Cảnh báo"]
end
Ở góc độ giao thức truyền thông giữa các hệ thống trong suốt thời gian chạy (Runtime Execution), trình tự trao đổi dữ liệu giữa GitHub Actions Runner, dịch vụ lưu đệm GHA Cache, trình quét lỗ hổng Trivy, kho chứa GHCR và máy chủ Docker Production diễn ra tuần tự như sau:
sequenceDiagram
autonumber
actor Dev as Kỹ sư Phần mềm
participant GH as GitHub Actions Runner
participant Cache as GitHub Actions Cache
participant Trivy as Trivy Scanner
participant GHCR as GitHub Container Registry
participant Prod as Production Docker Host
Dev->>GH: git push origin main (Commit SHA: a1b2c3d)
GH->>GH: Job 1 (test): Chạy Ruff Linter & Pytest Suite
GH->>Cache: Job 2: Tải Docker Layer Cache (cache-from: type=gha)
Cache-->>GH: Trả về Cached Builder Layers (Cache Hit)
GH->>GH: Build Candidate Image (ghcr.io/infoteck-org/api-gateway:sha-a1b2c3d)
GH->>Trivy: Quét OS Packages & Lockfiles (severity: CRITICAL,HIGH)
alt Phát hiện lỗ hổng CRITICAL hoặc HIGH
Trivy-->>GH: Trả về Exit Code 1 kèm danh sách CVE
GH-->>Dev: Dừng Pipeline (Chặn đẩy Image lỗi lên GHCR)
else Không có lỗ hổng CRITICAL / HIGH
Trivy-->>GH: Trả về Exit Code 0 (Clean)
GH->>GHCR: Push Image (sha-a1b2c3d) bằng GITHUB_TOKEN
GH->>Cache: Lưu Layer Cache mới (cache-to: type=gha,mode=max)
GH->>Prod: Job 3 (deploy): SSH kích hoạt deploy-rollout.sh
Prod->>Prod: Lưu PREVIOUS_TAG & Pull Image sha-a1b2c3d
Prod->>Prod: docker compose up -d & Poll /healthz (60s)
alt Healthcheck trả về HTTP 200 OK (healthy)
Prod-->>GH: Xác nhận Rollout thành công (Exit Code 0)
GH-->>Dev: Thông báo Deployment Production hoàn tất
else Healthcheck thất bại hoặc quá thời gian (unhealthy)
Prod->>Prod: Tự động khôi phục container về PREVIOUS_TAG
Prod-->>GH: Trả về Exit Code 1 (Đã Rollback an toàn)
GH-->>Dev: Cảnh báo Rollout thất bại & Đã tự động Rollback
end
end
2. Thiết lập Tầng Continuous Integration (CI): Linting, Unit Testing và Concurrency Control
2.1 Kiểm soát Xung đột Pipeline bằng Concurrency Group và Phân quyền GITHUB_TOKEN Tối thiểu
Khi nhiều kỹ sư cùng đẩy các bản sửa lỗi liên tiếp lên một nhánh tính năng (Feature Branch) hoặc khi hai commit được gộp (merge) vào nhánh main cách nhau vài giây, nếu không có cơ chế kiểm soát đồng thời, hai luồng triển khai có thể chạy song song và ghi đè trạng thái của nhau trên máy chủ đích (Race Condition).
Theo tài liệu chính thức của GitHub Actions (Workflow syntax for GitHub Actions), chúng ta cần áp dụng hai lớp bảo vệ ngay ở cấp độ toàn cục của tệp cấu hình workflow:
- Nguyên tắc Đặc quyền Tối thiểu (
permissions: contents: read): Mặc định, một số kho lưu trữ cũ cấp quyền đọc/ghi rộng rãi cho biếnGITHUB_TOKEN. Việc khóa cứng quyền mặc định ở mức chỉ đọc mã nguồn (contents: read) ở đầu tệp YAML đảm bảo rằng nếu một thư viện bên thứ ba trong bước chạy Unit Test bị tấn công chuỗi cung ứng (Supply-chain Attack), mã độc đó cũng không thể đẩy gói tin giả mạo lên GHCR hoặc chỉnh sửa nhánh mã nguồn. Quyền ghi (packages: write) chỉ được cấp cục bộ tại đúng job đóng gói container. - Kiểm soát Tương tranh Thông minh (
concurrency): Chúng ta nhóm các lần chạy theo tên workflow và nhánh Git. Đối với các nhánh Pull Request (github.ref != 'refs/heads/main'), cờcancel-in-progress: truesẽ tự động hủy bỏ các phiên chạy cũ ngay khi kỹ sư đẩy commit mới lên cùng nhánh, giúp tiết kiệm tài nguyên máy chạy (Runner Minutes). Ngược lại, trên nhánhmain, biểu thức điều kiện sẽ đặtcancel-in-progress: falseđể đảm bảo một tiến trình triển khai Production đang diễn ra không bao giờ bị ngắt ngang giữa chừng mà các lần chạy tiếp theo sẽ được xếp hàng chờ tuần tự.
2.2 Tự động hóa Linting, Static Analysis và Unit Testing với Pytest và Coverage
Trước khi khởi tạo tiến trình Docker Buildx tốn nhiều tài nguyên CPU và băng thông mạng, công việc đầu tiên (test) đóng vai trò như bộ lọc chất lượng tốc độ cao:
- Lưu đệm gói phụ thuộc ngôn ngữ (
cache: 'pip'): Tích hợp trực tiếp vàoactions/setup-python@v5dựa trên mã băm của tệprequirements.txt, giúp khôi phục môi trường thư viện chỉ trong vài giây. - Kiểm tra quy chuẩn mã nguồn với
ruff: Phát hiện tức thì các biến không sử dụng, lỗi cú pháp, hoặc vi phạm chuẩn định dạng PEP8. - Thực thi kiểm thử đơn vị với
pytest: Chạy toàn bộ bộ kiểm thử tự động kèm ngưỡng độ phủ mã nguồn tối thiểu (--cov-fail-under=80). Nếu bất kỳ bài kiểm thử nào thất bại, jobtesttrả về mã lỗi khác0và ngăn chặn hoàn toàn việc tạo Docker Image.
3. Tối ưu hóa Tốc độ Build Docker Image với BuildKit & GitHub Actions Cache (type=gha)
3.1 Cơ chế Hoạt động của Docker Buildx và Bộ nhớ Đệm Lớp (Layer Caching type=gha,mode=max)
Một đặc điểm kiến trúc cốt lõi của GitHub Actions là mỗi lần workflow được kích hoạt, hệ thống sẽ cấp phát một máy ảo Ubuntu hoàn toàn mới (Ephemeral Clean VM). Điều này đồng nghĩa với việc bộ nhớ đệm lớp cục bộ của Docker daemon (/var/lib/docker) luôn trống rỗng khi bắt đầu job. Nếu sử dụng lệnh docker build truyền thống, máy chạy sẽ phải tải lại toàn bộ các gói hệ điều hành (apk add / apt-get) và biên dịch lại toàn bộ thư viện ở mọi lần chạy.
Để giải quyết bài toán này, chúng ta sử dụng trình biên dịch thế hệ mới Docker Buildx (dựa trên kiến trúc BuildKit) kết hợp với hậu phương lưu trữ đệm GitHub Actions Cache Backend (type=gha):
cache-from: type=gha: Trước khi thực thi từng chỉ thịRUNhoặcCOPYtrongDockerfile, BuildKit tính toán mã băm nội dung (Content-addressable Checksum) của lớp đó cùng toàn bộ các lớp cha, sau đó truy vấn trực tiếp vào GitHub Actions Cache API. Nếu mã băm khớp (Cache Hit), BuildKit tải ngay lớp đã biên dịch sẵn về mà không cần chạy lại lệnh.cache-to: type=gha,mode=max: Đây là tham số kỹ thuật quan trọng nhất khi làm việc với Multi-stage Dockerfile. Nếu chỉ để chế độ mặc định (mode=min), BuildKit chỉ lưu đệm các lớp nằm trong giai đoạn cuối cùng (runtime stage), còn toàn bộ các lớp cài đặt trình biên dịch và thư viện nằm ở giai đoạn trung gian (builder stage) sẽ bị bỏ qua. Khi thiết lập tường minhmode=max, BuildKit xuất toàn bộ biểu đồ lớp của cả giai đoạnbuilderlẫnruntimelên bộ nhớ đệm GitHub, giúp các lần chạy tiếp theo khi chỉ thay đổi mã nguồn nghiệp vụ đạt tỷ lệ trúng bộ nhớ đệm (Cache Hit Ratio) tối đa ở tầng phụ thuộc.
3.2 Chiến lược Định danh Image Bất biến (Immutable Git SHA Tagging vs. latest Anti-Pattern)
Trong vận hành hệ thống Production, việc cấu hình máy chủ kéo hình ảnh theo nhãn infoteck/api-gateway:latest là một phản mẫu kiến trúc (Anti-Pattern) cực kỳ nguy hiểm vì ba lý do:
- Mất khả năng tái lập và kiểm toán (Non-reproducible State): Nhãn
:latestbị ghi đè liên tục sau mỗi lần build. Khi xảy ra sự cố lúc nửa đêm, kỹ sư trực ca không thể biết chính xác container đang chạy tương ứng với bản commit nào trên Git. - Không thể thực hiện Rollback tức thì: Vì bản build mới đã đè lên cùng một tên nhãn
:latest, bạn không có nhãn phiên bản cũ rõ ràng để khôi phục ngay lập tức. - Sai lệch bộ nhớ đệm kéo ảnh (
Pull Policy Drift): Nếu cấu hình điều phối không ép buộc kiểm tra mã băm digest mới, các nút máy chủ có thể tiếp tục dùng lại bản:latestcũ đang nằm sẵn trên đĩa.
Giải pháp chuẩn công nghiệp là sử dụng docker/metadata-action@v5 để tự động sinh nhãn bất biến dựa trên mã băm commit rút gọn theo định dạng sha-<7_ky_tu_commit> (ví dụ: ghcr.io/infoteck-org/api-gateway:sha-a1b2c3d), đồng thời nhúng đầy đủ các thuộc tính truy vết nguồn gốc theo đặc tả OpenContainers Initiative (OCI Image Annotations) vào manifest của image.
4. Tích hợp Chốt chặn Bảo mật (DevSecOps Security Gate) với Trivy và Đăng tải lên GHCR
4.1 Quét Lỗ hổng CVE Image Tự động bằng Aqua Security Trivy (exit-code: 1 trên CRITICAL/HIGH)
Một sai lầm phổ biến trong nhiều mẫu cấu hình CI/CD là đẩy thẳng Docker Image lên kho lưu trữ bằng một bước build-push-action duy nhất có push: true, rồi mới chạy công cụ quét bảo mật ở bước sau. Nếu làm như vậy, ngay cả khi bước quét phát hiện lỗ hổng nghiêm trọng và báo đỏ, hình ảnh chứa lỗ hổng đó đã nằm sẵn trên Registry và có nguy cơ bị các hệ thống bên ngoài kéo về sử dụng.
Quy trình DevSecOps chuẩn Production tách quá trình này thành 3 bước chặt chẽ trong cùng một job:
- Bước 1 — Build & Load cục bộ (
load: true, push: false): Buildx biên dịch hình ảnh (tận dụng tối đa bộ nhớ đệmtype=gha) và nạp hình ảnh ứng viên (Candidate Image) vào Docker daemon cục bộ của máy chạy Runner mà chưa đẩy lên mạng. - Bước 2 — Quét lỗ hổng với
aquasecurity/[email protected]: Trivy phân tích toàn bộ các gói hệ điều hành (Alpineapk, Debiandpkg) và các tệp khóa thư viện ứng dụng (requirements.txt,package-lock.json,go.sum) bên trong hình ảnh ứng viên. Chúng ta cấu hìnhseverity: 'CRITICAL,HIGH',ignore-unfixed: true(chỉ chặn các lỗ hổng đã có bản vá chính thức từ nhà phát hành), và đặtexit-code: '1'. Nếu phát hiện bất kỳ lỗ hổngCRITICALhoặcHIGHnào chưa được vá, Trivy lập tức trả về mã lỗi1và hủy bỏ job ngay tại chỗ. - Bước 3 — Đăng tải Image sạch lên GHCR (
push: true): Chỉ khi bước quét Trivy vượt qua an toàn (Exit Code 0), bước đẩy hình ảnh mới được thực thi. Nhờ bộ nhớ đệm BuildKit cục bộ vừa tạo ở Bước 1, bước đẩy này hoàn tất gần như tức thì mà không phải biên dịch lại bất kỳ dòng mã nào.
Để tìm hiểu sâu hơn về cơ chế cơ sở dữ liệu lỗ hổng CVE, cách cấu hình tệp ngoại lệ .trivyignore có thời hạn và so sánh kiến trúc giữa các trình quét container, bạn hãy đọc bài viết chuyên sâu Bảo mật Container và quét lỗ hổng hình ảnh với Trivy và Clair.
4.2 Xác thực và Đẩy Image lên GitHub Container Registry (GHCR) kèm Metadata Chuẩn OCI
Thay vì phải tạo và quản lý mật khẩu Docker Hub hoặc khóa cá nhân (PAT) trên từng kho lưu trữ, GitHub Container Registry (ghcr.io) cho phép xác thực trực tiếp bằng biến ${{ secrets.GITHUB_TOKEN }} thông qua docker/login-action@v3. Đối với các mật khẩu cơ sở dữ liệu ứng dụng, khóa ký JWT hoặc chứng chỉ TLS cần nạp vào môi trường vận hành thực tế bên ngoài phạm vi CI/CD, doanh nghiệp nên kết hợp thêm giải pháp quản lý khóa tập trung được hướng dẫn tại bài viết Quản lý Secret và khóa mã hóa an toàn với HashiCorp Vault.
Dưới đây là toàn bộ nội dung tệp cấu hình .github/workflows/production-cicd.yml (Code Module #1) tích hợp đầy đủ 3 job (test, build-scan-push, và deploy-production):
# File: .github/workflows/production-cicd.yml
name: Production CI/CD Pipeline (Buildx + Trivy + Atomic Rollout)
on:
push:
branches:
- main
pull_request:
branches:
- main
# Khóa quyền mặc định của GITHUB_TOKEN ở mức tối thiểu (Read-Only)
permissions:
contents: read
# Kiểm soát tương tranh: Hủy các bản chạy PR cũ bị trùng, nhưng bảo vệ hàng đợi trên nhánh main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# ===================================================================
# JOB 1: CONTINUOUS INTEGRATION (LINTING & UNIT TESTS)
# ===================================================================
test:
name: CI - Lint & Unit Test Suite
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout Source Code
uses: actions/checkout@v4
- name: Set up Python 3.11 with Pip Cache
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"
cache-dependency-path: "**/requirements*.txt"
- name: Install Application & Test Dependencies
run: |
python -m pip install --upgrade pip
python -m pip install ruff==0.7.3 pytest==8.3.3 pytest-cov==5.0.0
if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; fi
- name: Run Static Linter & Formatting Check (Ruff)
run: |
ruff check .
ruff format --check .
- name: Execute Unit Tests with Coverage Enforcement
run: |
pytest tests/ --maxfail=1 --disable-warnings -q --cov=app --cov-report=term-missing --cov-fail-under=80
# ===================================================================
# JOB 2: BUILDX CACHE, TRIVY CVE GATE & GHCR PUBLISH
# ===================================================================
build-scan-push:
name: DevSecOps - Buildx, Trivy Scan & Push GHCR
needs: [test]
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: read
packages: write
security-events: write
outputs:
immutable_tag: ${{ steps.vars.outputs.immutable_tag }}
steps:
- name: Checkout Source Code
uses: actions/checkout@v4
- name: Compute Immutable Short SHA Tag
id: vars
run: |
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
echo "immutable_tag=sha-${SHORT_SHA}" >> "${GITHUB_OUTPUT}"
- name: Set up Docker Buildx Builder
uses: docker/setup-buildx-action@v3
- name: Extract OCI Metadata & Tags for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=sha-,format=short
type=raw,value=stable,enable=${{ github.ref == 'refs/heads/main' }}
- name: Build Candidate Image into Local Daemon (Using GHA Layer Cache)
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
load: true
push: false
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.immutable_tag }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Run Aqua Security Trivy Vulnerability Gate (Block CRITICAL & HIGH)
uses: aquasecurity/[email protected]
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.immutable_tag }}
format: "table"
exit-code: "1"
ignore-unfixed: true
vuln-type: "os,library"
severity: "CRITICAL,HIGH"
- name: Authenticate to GitHub Container Registry (GHCR)
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push Verified Image to GHCR
if: github.event_name != 'pull_request'
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
# ===================================================================
# JOB 3: ATOMIC PRODUCTION DEPLOYMENT WITH HEALTHCHECK ROLLBACK
# ===================================================================
deploy-production:
name: CD - Atomic Production Rollout
needs: [build-scan-push]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-24.04
timeout-minutes: 10
environment:
name: production
url: https://api.infoteck.vn
steps:
- name: Execute Atomic Rollout & Healthcheck Verification via SSH
uses: appleboy/[email protected]
env:
DEPLOY_IMAGE_TAG: ${{ needs.build-scan-push.outputs.immutable_tag }}
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GHCR_USER: ${{ github.actor }}
with:
host: ${{ secrets.PROD_SSH_HOST }}
username: ${{ secrets.PROD_SSH_USER }}
key: ${{ secrets.PROD_SSH_KEY }}
port: ${{ secrets.PROD_SSH_PORT }}
envs: DEPLOY_IMAGE_TAG,GHCR_TOKEN,GHCR_USER
command_timeout: 5m
script: |
set -euo pipefail
cd /opt/infoteck/api-gateway
echo "${GHCR_TOKEN}" | docker login ghcr.io -u "${GHCR_USER}" --password-stdin
./scripts/deploy-rollout.sh "${DEPLOY_IMAGE_TAG}"
5. Tự động hóa Continuous Deployment (CD) An toàn với GitHub Environments và Healthcheck Rollback
5.1 Bảo vệ Môi trường Production bằng GitHub Environments, Protection Rules và SSH Bastion
Trong Job 3 (deploy-production) ở trên, thuộc tính environment: name: production kích hoạt cơ chế bảo vệ cấp doanh nghiệp của GitHub Actions:
- Tách biệt Biến Bí mật theo Môi trường (Environment-Scoped Secrets): Các khóa nhạy cảm như
PROD_SSH_KEY,PROD_SSH_HOSTvàPROD_SSH_USERkhông được lưu ở cấp độ Repository chung mà chỉ nằm trong vùngproduction. Một nhánh tính năng hoặc Pull Request từ bên ngoài không bao giờ có thể đọc được các biến này. - Cổng Phê duyệt Thủ công & Giới hạn Nhánh (Required Reviewers & Deployment Branches): Trong phần cài đặt Settings -> Environments -> production, quản trị viên cấu hình chỉ cho phép nhánh
mainđược kích hoạt môi trường này, đồng thời có thể yêu cầu phê duyệt từ Tech Lead trước khi lệnh SSH được phép thực thi.
5.2 Thiết kế Docker Compose Production với Healthcheck và Quản lý Tài nguyên
Để kịch bản triển khai biết chính xác khi nào container mới đã sẵn sàng nhận lưu lượng truy cập thực tế (thay vì chỉ kiểm tra trạng thái tiến trình Up vốn chưa đảm bảo ứng dụng bên trong đã khởi tạo xong kết nối cơ sở dữ liệu), tệp cấu hình docker-compose.prod.yml bắt buộc phải định nghĩa chỉ thị healthcheck rõ ràng.
Đồng thời, chúng ta áp dụng các biện pháp gia cố bảo mật runtime: gắn hệ thống tệp gốc ở chế độ chỉ đọc (read_only: true), cấp vùng nhớ tạm trên RAM (tmpfs: /tmp), giới hạn trần CPU/RAM để chống cạn kiệt tài nguyên máy chủ, và xoay vòng tệp nhật ký (max-size: "20m", max-file: "5"). Khi quy mô hệ thống của bạn phát triển vượt quá khả năng chịu tải của một máy chủ Docker Compose đơn lẻ và cần chuyển sang điều phối đa nút tự động co giãn, hãy tham khảo lộ trình kiến trúc tại bài viết Kiến trúc Microservices với Docker & Kubernetes: Hướng dẫn thực chiến từ A-Z.
Dưới đây là tệp cấu hình docker-compose.prod.yml (Code Module #2) đặt tại thư mục /opt/infoteck/api-gateway/ trên máy chủ Production:
# File: docker-compose.prod.yml
services:
api-gateway:
image: ghcr.io/infoteck-org/api-gateway:${IMAGE_TAG:?Bien moi truong IMAGE_TAG bat buoc phai duoc khai bao}
container_name: infoteck-api-gateway
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080"
env_file:
- /opt/infoteck/api-gateway/.env.production
environment:
- APP_ENV=production
- PORT=8080
read_only: true
tmpfs:
- /tmp:rw,noexec,nosuid,size=64m
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:8080/healthz"]
interval: 5s
timeout: 3s
retries: 3
start_period: 10s
deploy:
resources:
limits:
cpus: "2.0"
memory: 1024M
reservations:
cpus: "0.5"
memory: 256M
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "5"
5.3 Kịch bản Triển khai Nguyên tử (Atomic Rollout) và Tự động Rollback khi Healthcheck Thất bại
Nếu chỉ chạy lệnh docker compose up -d trong CI/CD, lệnh này sẽ trả về mã thành công ngay khi Docker tạo xong container, ngay cả khi ứng dụng bên trong lập tức văng lỗi CrashLoop sau đó 3 giây do thiếu biến môi trường hoặc lỗi di trú cơ sở dữ liệu.
Kịch bản scripts/deploy-rollout.sh (Code Module #3) dưới đây giải quyết triệt để bài toán này bằng quy trình 4 bước nguyên tử:
- Truy vấn nhãn hình ảnh hiện tại đang chạy ổn định và lưu vào biến
PREVIOUS_TAG. - Tải trước hình ảnh mới (
docker compose pull) và cập nhật container (up -d --remove-orphans). - Vòng lặp kiểm tra trạng thái
.State.Health.Statuscủa container thông qua lệnhdocker inspectmỗi 5 giây (tối đa 12 lần tương đương 60 giây). Nếu phát hiện trạng tháihealthy, kịch bản dọn dẹp các hình ảnh cũ không còn sử dụng và kết thúc thành công. - Nếu quá 60 giây hoặc trạng thái chuyển sang
unhealthy, kịch bản lập tức in ra 30 dòng nhật ký lỗi cuối cùng của container để kỹ sư chẩn đoán trên giao diện GitHub Actions, sau đó tự động kích hoạt lạidocker compose up -dvớiIMAGE_TAG="${PREVIOUS_TAG}"để phục hồi dịch vụ về bản ổn định trước đó rồi mới trả về mã lỗiexit 1.
#!/usr/bin/env bash
# File: scripts/deploy-rollout.sh
# Mô tả: Kịch bản triển khai nguyên tử (Atomic Rollout) có kiểm tra Healthcheck
# và tự động Rollback về phiên bản ổn định liền trước nếu khởi chạy thất bại.
set -euo pipefail
COMPOSE_FILE="docker-compose.prod.yml"
CONTAINER_NAME="infoteck-api-gateway"
NEW_TAG="${1:-}"
if [[ -z "${NEW_TAG}" ]]; then
echo "[ERROR] Cú pháp sử dụng: ./scripts/deploy-rollout.sh <immutable_image_tag>" >&2
exit 1
fi
echo "=== [1/4] GHI NHẬN TRẠNG THÁI PHIÊN BẢN HIỆN TẠI ==="
PREVIOUS_IMAGE=""
if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
PREVIOUS_IMAGE=$(docker inspect --format='{{.Config.Image}}' "${CONTAINER_NAME}" || true)
fi
PREVIOUS_TAG=""
if [[ -n "${PREVIOUS_IMAGE}" && "${PREVIOUS_IMAGE}" == *":"* ]]; then
PREVIOUS_TAG="${PREVIOUS_IMAGE##*:}"
echo "[INFO] Phiên bản đang vận hành ổn định hiện tại: ${PREVIOUS_TAG}"
else
echo "[INFO] Chưa có container '${CONTAINER_NAME}' nào đang chạy (Triển khai lần đầu)."
fi
echo "=== [2/4] TẢI VÀ KÍCH HOẠT PHIÊN BẢN MỚI (${NEW_TAG}) ==="
export IMAGE_TAG="${NEW_TAG}"
docker compose -f "${COMPOSE_FILE}" pull
docker compose -f "${COMPOSE_FILE}" up -d --remove-orphans
echo "=== [3/4] KIỂM TRA HEALTHCHECK TRONG TỐI ĐA 60 GIÂY ==="
MAX_ATTEMPTS=12
SLEEP_SECONDS=5
HEALTHY=false
for ((attempt = 1; attempt <= MAX_ATTEMPTS; attempt++)); do
STATUS=$(docker inspect --format='{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "${CONTAINER_NAME}" 2>/dev/null || echo "missing")
echo "[HEALTHCHECK] Lần thử ${attempt}/${MAX_ATTEMPTS}: Trạng thái container = '${STATUS}'"
if [[ "${STATUS}" == "healthy" ]]; then
HEALTHY=true
break
elif [[ "${STATUS}" == "unhealthy" || "${STATUS}" == "missing" ]]; then
echo "[WARN] Phát hiện container chuyển sang trạng thái lỗi ('${STATUS}')."
break
fi
sleep "${SLEEP_SECONDS}"
done
if [[ "${HEALTHY}" == "true" ]]; then
echo "=== [4/4] ROLLOUT THÀNH CÔNG! DỌN DẸP IMAGE CŨ KHÔNG SỬ DỤNG ==="
docker image prune -f --filter "until=72h"
echo "[SUCCESS] Dịch vụ '${CONTAINER_NAME}' đã vận hành ổn định trên phiên bản '${NEW_TAG}'."
exit 0
fi
echo "=== [4/4] CẢNH BÁO: ROLLOUT THẤT BẠI! TRÍCH XUẤT LOG LỖI CONTAINER ===" >&2
docker logs --tail 30 "${CONTAINER_NAME}" >&2 || true
if [[ -n "${PREVIOUS_TAG}" && "${PREVIOUS_TAG}" != "${NEW_TAG}" ]]; then
echo "[ROLLBACK] Đang tự động khôi phục dịch vụ về phiên bản ổn định trước đó: '${PREVIOUS_TAG}'..." >&2
export IMAGE_TAG="${PREVIOUS_TAG}"
docker compose -f "${COMPOSE_FILE}" up -d --remove-orphans
echo "[ROLLBACK] Đã kích hoạt lại phiên bản '${PREVIOUS_TAG}'. Báo lỗi về GitHub Actions." >&2
else
echo "[ROLLBACK] Không có phiên bản trước đó để khôi phục." >&2
fi
exit 1
6. Kiểm tra Thực thi Pipeline bằng GitHub CLI (gh) và Xử lý Sự cố Thường gặp
6.1 Giám sát Log Workflow và Kiểm tra Cache Hit Ratio qua GitHub CLI (gh run)
Sau khi đẩy cấu hình .github/workflows/production-cicd.yml lên kho lưu trữ, kỹ sư DevOps có thể kiểm tra trực tiếp trạng thái từng job, dung lượng bộ nhớ đệm lớp BuildKit (type=gha) và thời gian thực thi ngay từ cửa sổ dòng lệnh bằng công cụ chính thức GitHub CLI (gh) mà không cần rời khỏi trình soạn thảo mã nguồn.
Tệp kịch bản kiểm chứng verify-pipeline.sh (Code Module #4) dưới đây tổng hợp các lệnh chẩn đoán quan trọng nhất cùng kết quả đầu ra thực tế khi pipeline vận hành chuẩn xác:
#!/usr/bin/env bash
# File: verify-pipeline.sh
# Mô tả: Bộ lệnh kiểm chứng trạng thái CI/CD Pipeline và bộ nhớ đệm BuildKit qua GitHub CLI (gh).
set -euo pipefail
echo "1. Liệt kê 3 phiên chạy gần nhất của workflow Production CI/CD:"
gh run list --workflow="production-cicd.yml" --limit 3
echo -e "n2. Kiểm tra danh sách các bản lưu bộ nhớ đệm (Pip & BuildKit Layer Cache):"
gh cache list --limit 5
echo -e "n3. Xem chi tiết trạng thái các Job của phiên chạy mới nhất trên nhánh main:"
LATEST_RUN_ID=$(gh run list --workflow="production-cicd.yml" --branch main --limit 1 --json databaseId --jq '.[0].databaseId')
gh run view "${LATEST_RUN_ID}"
# -------------------------------------------------------------------------
# KẾT QUẢ ĐẦU RA THỰC TẾ TRÊN TERMINAL KHI KIỂM CHỨNG:
# -------------------------------------------------------------------------
# 1. Liệt kê 3 phiên chạy gần nhất của workflow Production CI/CD:
# STATUS TITLE WORKFLOW BRANCH EVENT ID ELAPSED AGE
# ✓ feat(api): add rate limit headers Production CI/CD Pipeline main push 11678902341 1m42s 2m
# ✓ fix(auth): validate token exp claim Production CI/CD Pipeline feat/jw pull_request 11678810922 58s 18m
#
# 2. Kiểm tra danh sách các bản lưu bộ nhớ đệm (Pip & BuildKit Layer Cache):
# ID KEY SIZE CREATED
# 982341102 Linux-buildkit-fe90a12c88b19402e7182a... 148 MB 2m ago
# 982340881 Linux-pip-64a19b002c8174f12e901a88c4... 42 MB 18m ago
#
# 3. Xem chi tiết trạng thái các Job của phiên chạy mới nhất trên nhánh main:
# ✓ main · Production CI/CD Pipeline · 11678902341
# Triggered via push about 2 minutes ago
#
# JOBS
# ✓ CI - Lint & Unit Test Suite in 28s (ID 32510091821)
# ✓ DevSecOps - Buildx, Trivy Scan & Push GHCR in 41s (ID 32510094510)
# ✓ CD - Atomic Production Rollout in 33s (ID 32510099104)
6.2 Xử lý Sự cố Tràn Dung lượng Cache GitHub Actions (10GB Limit) và Lỗi Quyền GHCR Packages
Trong quá trình vận hành thực tế ở các dự án có tần suất commit dày đặc, đội ngũ kỹ thuật thường gặp hai sự cố điển hình liên quan đến GitHub Actions Cache và quyền ghi gói tin trên GHCR:
- Sự cố tràn hạn mức 10GB của GitHub Actions Cache (Cache Thrashing): Mỗi kho lưu trữ trên GitHub được cấp hạn mức lưu trữ bộ nhớ đệm tối đa là
10 GB. Khi sử dụngcache-to: type=gha,mode=maxtrên các hình ảnh có nhiều lớp nặng, mỗi khi tệp khóa phụ thuộc thay đổi, BuildKit sẽ sinh ra các bản lưu đệm mới. Khi tổng dung lượng vượt quá10 GB, GitHub tự động xóa các bản lưu ít được truy cập nhất (LRU Eviction), đôi khi làm mất cả bộ nhớ đệm của nhánhmain.- Cách khắc phục: Chỉ cho phép ghi đè bộ nhớ đệm (
cache-to: type=gha,mode=max) khi chạy trên nhánhmain, còn các nhánh Pull Request chỉ đọc bộ nhớ đệm (cache-from: type=gha) mà không ghi mới, hoặc sử dụng hành động dọn dẹp tự động các bản lưu đệm của nhánh PR ngay khi PR được đóng lại (closed).
- Cách khắc phục: Chỉ cho phép ghi đè bộ nhớ đệm (
- Sự cố lỗi
403 Forbidden: installation not allowed to Write organization packagekhi đẩy lên GHCR: Ngay cả khi bạn đã khai báopermissions: packages: writetrong tệp YAML, lần chạy đầu tiên đẩy hình ảnh lên một tổ chức (GitHub Organization) vẫn có thể bị từ chối.- Cách khắc phục: Truy cập vào phần cài đặt của kho lưu trữ (Settings -> Actions -> General -> Workflow permissions) hoặc cài đặt cấp Organization (Settings -> Packages -> Package creation), đảm bảo tùy chọn cho phép GitHub Actions tạo và ghi gói tin thông qua
GITHUB_TOKENđã được bật, đồng thời liên kết gói container vừa tạo trên GHCR với đúng kho lưu trữ mã nguồn.
- Cách khắc phục: Truy cập vào phần cài đặt của kho lưu trữ (Settings -> Actions -> General -> Workflow permissions) hoặc cài đặt cấp Organization (Settings -> Packages -> Package creation), đảm bảo tùy chọn cho phép GitHub Actions tạo và ghi gói tin thông qua
7. Tổng kết & Tài liệu tham khảo (References)
7.1 Checklist Chuẩn hóa CI/CD Pipeline cho Đội ngũ Kỹ thuật
Trước khi đưa một đường ống CI/CD vào phục vụ hệ thống Production, hãy đối chiếu toàn bộ cấu hình của bạn với bảng kiểm tra kỹ thuật dưới đây:
| Hạng mục Kiểm soát | Cấu hình Kỹ thuật Bắt buộc | Mục tiêu Đảm bảo An toàn & Hiệu năng |
|---|---|---|
Phân quyền Token (permissions) |
Đặt contents: read ở cấp toàn cục; chỉ cấp packages: write riêng trong job build |
Ngăn chặn rò rỉ quyền ghi mã nguồn hoặc đẩy gói tin trái phép từ các bước chạy thử nghiệm |
Chống xung đột (concurrency) |
Thiết lập cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} |
Hủy ngay các bản chạy PR thừa nhưng bảo vệ tuyệt đối tiến trình deploy đang chạy trên nhánh main |
Lưu đệm BuildKit (type=gha) |
Sử dụng docker/setup-buildx-action@v3 kèm cache-to: type=gha,mode=max |
Lưu đệm toàn bộ các lớp trung gian của Multi-stage Dockerfile, giảm tối đa thời gian biên dịch |
Định danh Tạo tác (Immutable Tag) |
Gắn nhãn theo mã commit sha-<short_sha> thay vì chỉ dùng nhãn :latest |
Đảm bảo khả năng truy vết 1-1 giữa container đang chạy với lịch sử mã nguồn và hỗ trợ Rollback tức thì |
Chốt chặn Bảo mật (Trivy Gate) |
Quét hình ảnh cục bộ (load: true) với exit-code: "1" trên mức CRITICAL,HIGH |
Chặn tuyệt đối các hình ảnh chứa lỗ hổng bảo mật đã có bản vá trước khi đẩy lên GHCR |
Triển khai Nguyên tử (Atomic CD) |
Kiểm tra .State.Health.Status == "healthy" và tự động khôi phục về PREVIOUS_TAG khi lỗi |
Loại bỏ nguy cơ thời gian chết kéo dài khi phiên bản mới gặp lỗi cấu hình lúc khởi động |
7.2 Tài liệu tham khảo & Nguồn đối chiếu Chính thống
- GitHub Actions Official Documentation. Workflow syntax for GitHub Actions (
permissions,concurrency,environments). Truy cập tại: https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions - Docker BuildKit Official Documentation. GitHub Actions cache backend (
type=gha,mode=max). Truy cập tại: https://docs.docker.com/build/cache/backends/gha/ - GitHub Packages Documentation. Working with the Container registry (
ghcr.io&GITHUB_TOKENAuthentication). Truy cập tại: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry - Aqua Security Trivy Documentation. Trivy GitHub Action (
aquasecurity/trivy-actionCI/CD Gatekeeper). Truy cập tại: https://github.com/aquasecurity/trivy-action - OpenContainers Initiative (OCI). OCI Image Format Specification — Pre-Defined Annotation Keys. Truy cập tại: https://github.com/opencontainers/image-spec/blob/main/annotations.md