Tại sao cần “CI/CD as Code”?
Trong nhiều năm qua, YAML được xem là tiêu chuẩn de facto cho việc cấu hình CI/CD: từ GitHub Actions, GitLab CI đến CircleCI hay Drone. Tuy nhiên, YAML dần trở thành “kẻ cản bước” thay vì là công cụ hỗ trợ.
YAML: cấu hình hay mã nguồn?
YAML không hỗ trợ kiểm tra cú pháp nghiêm ngặt, thiếu khả năng tái sử dụng (reuse), và gần như không thể viết test hoặc debug logic pipeline. Khi pipeline có bug, bạn phải push commit, đợi chạy CI, đọc log — một quy trình chậm và tốn kém.
Trong khi đó, mô hình “CI/CD as Code” đề xuất dùng ngôn ngữ lập trình thực thụ (Python, Go, TypeScript…) để mô tả pipeline. Lúc này pipeline không còn là “cấu hình” mà là mã nguồn có thể test, debug, reuse, chia module và versioning như mọi phần mềm khác.
Lợi ích chính khi viết CI/CD bằng code:
- IDE hỗ trợ tốt: autocomplete, refactor, rename, jump-to-definition…
- Type-safe: phát hiện lỗi ngay khi code sai kiểu dữ liệu
- Có thể chạy local trước khi commit lên remote
- Viết unit test dễ dàng, đảm bảo logic pipeline luôn đúng
- Tái sử dụng được: chia nhỏ thành các hàm/module rõ ràng
- Debug chi tiết: dừng từng bước, in log cụ thể từng đoạn
Ví dụ: bạn viết 1 hàm build_image() để build Docker image, và hoàn toàn có thể test riêng hàm đó, mock external call hoặc inject biến môi trường để kiểm tra case đặc biệt.
Tổng quan Dagger 0.9
Dagger là nền tảng open-source cho phép bạn viết CI/CD pipeline bằng code, sử dụng SDK như Go, Python, TypeScript… Nó không thay thế GitHub Actions hay GitLab CI, mà giúp bạn viết phần chính của pipeline một cách cấu trúc hơn, có thể nhúng vào bất kỳ runner nào.
Điểm mới ở bản 0.9
Dagger 0.9 giới thiệu Services v2 API, hỗ trợ:
- Host-to-Container: mount file/socket từ local vào container
- Container-to-Host: ghi file ra ngoài từ container
- Dễ quản lý vòng đời service, không cần cleanup thủ công
- Tích hợp tốt hơn với Docker socket, gRPC, SSH agent…
Cùng với đó là SDK cập nhật, GraphQL engine nhanh hơn và hỗ trợ nhiều luồng xử lý (parallel DAG execution).
So với YAML CI truyền thống
| Tiêu chí | YAML (GitHub Actions) | Dagger 0.9 |
|---|---|---|
| Ngôn ngữ | YAML | Go / Python / TS |
| Tái sử dụng logic | Rất khó | Dễ chia module |
| Test pipeline | Không | Có thể unit test |
| IDE support | Kém | Đầy đủ |
| Debug local | Gần như không | Có, dễ trace |
Dagger không thay thế hoàn toàn YAML — bạn vẫn cần YAML để gọi Dagger như 1 step trong GitHub Actions. Nhưng phần quan trọng (build/test/deploy logic) sẽ nằm trong code.
Chuẩn bị môi trường
Để bắt đầu viết CI/CD bằng Dagger, bạn cần setup một số công cụ cơ bản:
Yêu cầu hệ thống:
- Docker hoặc Podman: Dagger chạy bằng container
- Dagger CLI: tool tương tác với engine
- Git: để quản lý version code pipeline
- Python / Go / TypeScript: tuỳ SDK bạn muốn dùng
- VSCode (khuyên dùng): để tận dụng autocomplete và debug tốt
Cài đặt Dagger CLI:
brew install dagger/tap/dagger
# hoặc dùng script chính thức:
curl -sSL https://dagger.io/install | sh
Khởi tạo dự án:
Với Python:
dagger init python
Với Go:
dagger init go
Lệnh trên sẽ tạo thư mục .dagger, file main.py (hoặc main.go), và một vài file boilerplate để bạn bắt đầu viết module.
Viết pipeline đầu tiên với Dagger
Tạo module và định nghĩa các hàm test, build, publish
Sau khi đã cài đặt Dagger CLI và SDK, bạn có thể khởi tạo một module mới bằng lệnh:
dagger init --sdk=python --name=hello-dagger
Lệnh này sẽ tạo ra cấu trúc thư mục và các tệp cần thiết cho dự án Dagger của bạn. Trong tệp main.py, bạn có thể định nghĩa các hàm test, build, và publish như sau:
import random
from dagger import dag, function, object_type, DefaultPath, Directory
@object_type
class HelloDagger:
@function
async def test(self, source: Directory = DefaultPath("/")) -> str:
return await (
dag.container()
.from_("python:3.11-slim")
.with_directory("/src", source)
.with_workdir("/src")
.with_exec(["pip", "install", "-r", "requirements.txt"])
.with_exec(["pytest"])
.stdout()
)
@function
def build(self, source: Directory = DefaultPath("/")) -> dagger.Container:
return (
dag.container()
.from_("python:3.11-slim")
.with_directory("/src", source)
.with_workdir("/src")
.with_exec(["pip", "install", "-r", "requirements.txt"])
.with_exec(["python", "setup.py", "install"])
)
@function
async def publish(self, source: Directory = DefaultPath("/")) -> str:
image_tag = f"ttl.sh/hello-dagger-{random.randint(1000,9999)}"
return await self.build(source).publish(image_tag)
Trong đoạn mã trên:
test: chạy các bài kiểm tra unit test bằngpytest.build: xây dựng ứng dụng Python và cài đặt nó.publish: xây dựng và đẩy image lên registry với tag ngẫu nhiên.
Chạy pipeline local và trên runner CI
Để chạy pipeline local, bạn có thể sử dụng Dagger Shell:
dagger
Sau đó, trong shell:
publish
Lệnh này sẽ thực hiện các bước test, build và publish như đã định nghĩa.
Để tích hợp vào CI như GitHub Actions, bạn có thể thêm bước sau vào workflow:
- name: Run Dagger pipeline
run: dagger call publish
Unit test cho pipeline
Tại sao cần test pipeline?
Việc viết unit test cho pipeline giúp đảm bảo rằng các bước trong quy trình CI/CD hoạt động đúng như mong đợi. Điều này đặc biệt quan trọng khi pipeline trở nên phức tạp và có nhiều bước phụ thuộc lẫn nhau.
Viết unit test cho Dagger Function bằng pytest
Bạn có thể viết các bài kiểm tra cho các hàm Dagger bằng pytest. Ví dụ:
def test_build_container():
hello = HelloDagger()
container = hello.build()
assert container is not None
Trong bài kiểm tra trên, bạn kiểm tra xem hàm build có trả về một container hợp lệ hay không.
Mock external services với Services v2 API
Dagger 0.9 giới thiệu Services v2 API, cho phép bạn dễ dàng mock các dịch vụ bên ngoài trong quá trình kiểm thử. Ví dụ, bạn có thể tạo một dịch vụ giả lập cho database hoặc API bên ngoài để kiểm tra các tương tác mà không cần phụ thuộc vào dịch vụ thực tế.
@function
def mock_service(self) -> dagger.Service:
return (
dag.container()
.from_("alpine")
.with_exec(["sh", "-c", "while true; do echo 'mock'; sleep 1; done"])
.as_service()
)
Sau đó, bạn có thể sử dụng dịch vụ này trong các bài kiểm tra của mình.
So sánh Dagger với YAML CI (GitHub Actions, GitLab CI)
Bảng đối chiếu cú pháp và khả năng mở rộng
| Tiêu chí | YAML (GitHub Actions) | Dagger 0.9 |
|---|---|---|
| Ngôn ngữ | YAML | Python / Go / TypeScript |
| Tái sử dụng logic | Khó | Dễ chia module |
| Test pipeline | Hạn chế | Hỗ trợ unit test |
| Hỗ trợ IDE | Giới hạn | Tốt (autocomplete, lint) |
| Debug local | Khó | Dễ dàng |
Trường hợp nên/không nên thay thế toàn bộ YAML
Nên sử dụng Dagger khi:
- Pipeline phức tạp và cần kiểm soát logic chi tiết.
- Muốn tái sử dụng các bước trong pipeline.
- Cần kiểm thử và debug pipeline local.
Không nên thay thế YAML khi:
- Pipeline đơn giản, chỉ gồm vài bước cơ bản.
- Đội ngũ chưa quen với việc viết pipeline bằng code.
- Muốn tận dụng các tính năng có sẵn của nền tảng CI (như GitHub Actions Marketplace).
Best practice & lưu ý
Chia nhỏ module, đặt tên component
- Tách module theo chức năng: Ví dụ, tạo các module riêng biệt cho
build,test, vàdeployđể dễ dàng quản lý và tái sử dụng. - Đặt tên rõ ràng: Sử dụng tên hàm và module mô tả rõ chức năng, giúp người đọc dễ hiểu và dễ bảo trì.
Quản lý secrets, biến môi trường
- Sử dụng
with_secret_variable: Dagger hỗ trợ truyền biến môi trường bảo mật thông quawith_secret_variable, giúp bảo vệ thông tin nhạy cảm. - Tích hợp với hệ thống quản lý secrets: Có thể tích hợp Dagger với các hệ thống như Vault hoặc sử dụng biến môi trường được mã hóa.
Tối ưu cache layer, tránh “snowball” container
- Sử dụng cache thông minh: Dagger tự động cache các bước trong pipeline. Tuy nhiên, cần cấu hình hợp lý để tránh việc cache không hiệu quả.
- Tránh tạo container lồng nhau: Việc tạo container bên trong container có thể gây ra vấn đề về hiệu suất và khó debug.
Câu hỏi thường gặp
Dagger có miễn phí không?
Có: Dagger là mã nguồn mở và hoàn toàn miễn phí để sử dụng. Bạn có thể truy cập mã nguồn tại GitHub Dagger.
Có chạy được hybrid cloud/on-prem không?
Có: Dagger được thiết kế để chạy trên nhiều môi trường khác nhau, bao gồm cả hybrid cloud và on-premises, miễn là có hỗ trợ container.
Hỗ trợ Windows runner?
Có: Dagger hỗ trợ Windows runner, tuy nhiên cần đảm bảo môi trường Docker được cấu hình đúng trên Windows.
Lộ trình lên 1.0?
Đang phát triển: Dagger đang trong quá trình hoàn thiện để ra mắt phiên bản 1.0, tập trung vào tính ổn định và mở rộng tính năng.
Tài liệu và nguồn tham khảo
- Trang chủ Dagger: https://dagger.io
- Tài liệu chính thức: https://docs.dagger.io
- Blog Dagger 0.9: https://dagger.io/blog/dagger-0-9
- Ví dụ cộng đồng: https://github.com/dagger/dagger-examples
- Dagger Discord: https://discord.gg/dagger-io
Có thể bạn sẽ thích xem: Kiểm thử UI tự động với Playwright cho Frontend Developer








