DataOps 5 — CI/CD & tự động hoá pipeline
Từ "deploy bằng tay" tới "everything as code"
Trong nhiều đội dữ liệu ngân hàng, "lên production" nghĩa là một người mở SQL client, dán đoạn model mới vào schema prod, chạy tay từng câu, rồi sửa DAG trực tiếp trên Airflow UI. Không ai chắc bản đang chạy trùng bản trong Git. Một hôm người đó nghỉ phép, số liệu báo cáo dư nợ sai, và không ai biết deploy nào gây ra vì không có dấu vết.
Bài này thuộc series DataOps. Sau khi đã đưa mọi thứ vào Git (analytics as code) và có testing & chất lượng chạy tự động, bước tiếp theo là CI/CD: biến quy trình thủ công, dễ sai đó thành một dây chuyền tự động, có kiểm thử và phê duyệt. Ta mượn nguyên si tư tưởng CI/CD của kỹ thuật phần mềm (xem nền tảng ở DevOps CI/CD) rồi áp vào tài sản dữ liệu: SQL, dbt model, pipeline, DAG.
Hai chữ cần phân biệt ngay:
- CI — Continuous Integration (tích hợp liên tục): mỗi khi có thay đổi (một Pull Request), hệ thống tự động kiểm tra thay đổi đó — lint, biên dịch, chạy test — để bắt lỗi trước khi merge.
- CD — Continuous Delivery/Deployment (chuyển giao/triển khai liên tục): sau khi merge, thay đổi được tự động đưa lên các môi trường theo trình tự dev → staging → prod, an toàn và tái lập.
Nguyên tắc bao trùm là everything as code: model, pipeline, DAG, cấu hình môi trường, hạ tầng — tất cả là code trong Git, và mọi thao tác deploy là chạy code, không ai "sửa tay" trên production.
Continuous Integration: cổng chặn ở mỗi Pull Request
CI là tuyến phòng thủ đầu tiên. Mục tiêu: không một dòng SQL lỗi nào lọt vào main. Khi một analyst mở PR sửa một dbt model, pipeline CI tự động chạy một chuỗi kiểm tra và chặn merge nếu bất kỳ bước nào fail.
Các bước điển hình trong CI cho dữ liệu
| Bước | Làm gì | Bắt lỗi gì |
|---|---|---|
| Lint / format SQL | sqlfluff lint, kiểm tra quy ước đặt tên | Sai style, tên bảng lộn xộn, SQL khó đọc |
| Compile | dbt compile — dịch Jinja+SQL thành SQL thuần | Ref sai, macro hỏng, model không dịch được |
| Unit test logic | Test biến đổi trên input giả định | Sai công thức (phân loại nợ, tính lãi) |
| Data test | dbt tests: unique, not_null, relationships, test tuỳ biến trên môi trường test | Vi phạm ràng buộc, khoá trùng, quan hệ đứt |
| Slim CI | Chỉ chạy model đã đổi + downstream | Tiết kiệm chi phí, phản hồi nhanh |
| Human review | Người thứ hai đọc diff, approve | Lỗi logic nghiệp vụ máy không bắt được |
Phần data test nối trực tiếp với bài testing & chất lượng: CI chính là nơi các test đó được chạy tự động trên mỗi PR, thay vì để analyst nhớ chạy tay.
Slim CI — chỉ chạy phần đổi & downstream
Chạy lại toàn bộ warehouse mỗi PR thì vừa chậm vừa tốn tiền. Slim CI (thuật ngữ dbt: state-aware / defer) chỉ build những model đã thay đổi trong PR cộng với các model phụ thuộc phía sau (downstream), so với trạng thái của main. Cách làm: lưu artifact manifest.json của lần build production gần nhất, rồi:
dbt build --select state:modified+ --defer --state ./prod-manifest
state:modified+ = "các model đổi và mọi thứ downstream"; --defer = các model không đổi thì trỏ tới bảng đã có sẵn ở prod thay vì dựng lại. Một PR sửa 1 model trong dự án 400 model có thể chỉ build 6 model thay vì 400 — CI từ 40 phút xuống 2 phút.
Kiểm tra một bất biến dữ liệu trong CI
Ngoài dbt tests, ta hay viết các truy vấn kiểm tra bất biến (invariant) chạy trên sandbox/staging: một câu SELECT trả về các dòng vi phạm — nếu có dòng nào, CI fail. Ví dụ bất biến "không tài khoản nào được có số dư âm ở loại tiền VND":
-- ▶ Chạy được
SELECT a.id AS account_id, a.account_no, a.balance, a.currency
FROM accounts a
JOIN customers c ON c.id = a.customer_id
WHERE a.currency = 'VND'
AND a.balance < 0;
Trong CI, wrapper của bước test sẽ đếm số dòng trả về; > 0 nghĩa là bất biến bị phá và pipeline dừng lại. Đây là mẫu "test kiểu assertion" rất phổ biến: mỗi rule nghiệp vụ (số dư, nhóm nợ, ngày hạch toán) thành một truy vấn "phải trả về rỗng".
Continuous Delivery/Deployment: promote qua môi trường
Sau khi PR pass CI và được merge vào main, tới lượt CD đưa thay đổi lên chạy. Nguyên tắc promote tuần tự qua các môi trường, chất lượng tăng dần độ tin cậy:
- Continuous Delivery: mỗi thay đổi luôn ở trạng thái sẵn sàng lên prod, nhưng cú bấm cuối cần người phê duyệt. Đây là mô hình phù hợp ngân hàng.
- Continuous Deployment: bỏ luôn bước bấm tay — merge là tự động lên prod. Hiếm khi áp cho lớp báo cáo tài chính; hay dùng cho môi trường thấp (dev/staging) hoặc pipeline nội bộ ít rủi ro.
Deploy cái gì, và deploy thế nào
CD cho dữ liệu thường phải triển khai ba loại artifact:
- dbt project:
dbt build(hoặcdbt run+dbt test) trên schema prod. Vì dbt tạo bảng bằngcreate or replace, bản thân nó idempotent — chạy lại nhiều lần cho cùng kết quả. - Pipeline / job: Spark job, script ELT — đóng gói (container/artifact có version) rồi nạp lên nơi chạy.
- DAG Airflow: đây là điểm dễ sai nhất. Deploy DAG như code, không sửa tay trên UI. File DAG nằm trong Git; CD đồng bộ chúng vào thư mục
dags/(qua git-sync, S3/GCS bucket, hay build image). Xem thêm Airflow overview.
Idempotent deploy là yêu cầu cốt lõi: chạy lại một deploy phải cho ra cùng trạng thái, không nhân đôi bảng, không lỗi "đã tồn tại". Nhờ vậy, deploy hỏng giữa chừng có thể chạy lại an toàn.
Blue-green & rollback
Với báo cáo ngân hàng, "prod tải sai số liệu 30 phút" là sự cố nghiêm trọng. Blue-green deployment giảm rủi ro: dựng bản mới (green) song song với bản đang chạy (blue) trên schema/bảng tạm, chạy smoke test trên green, rồi hoán đổi (swap con trỏ / rename schema) chỉ khi green đã đúng. Nếu sai, giữ nguyên blue — người dùng không thấy gián đoạn.
Rollback phải rẻ và nhanh: vì mọi thứ là code, git revert commit hỏng rồi để CD deploy lại bản tốt gần nhất. Điều kiện để rollback dễ: deploy idempotent + versioning artifact (biết chính xác "bản tốt gần nhất" là commit/tag nào).
Môi trường & tách biệt
CI/CD chỉ an toàn khi các môi trường tách biệt rạch ròi. Tối thiểu ba tầng:
| Môi trường | Dữ liệu | Schema | Ai dùng | Mục đích |
|---|---|---|---|---|
| dev | Mẫu nhỏ / synthetic | dev_<user> riêng từng người | Developer | Viết & thử model nhanh |
| staging | Bản sao gần prod (đã che PII) | staging | CI/CD, QA | Chạy full test, giống prod |
| prod | Dữ liệu thật | prod | Người dùng cuối, báo cáo | Phục vụ nghiệp vụ |
Nguyên tắc bắt buộc trong ngân hàng:
- Không bao giờ test trên dữ liệu prod thật. Data test chạy ở staging với bản sao đã masking PII (xem che dữ liệu PII). Tuyệt đối không đọc/ghi thẳng bảng khách hàng thật từ pipeline CI.
- Schema riêng theo môi trường và theo người. dbt hỗ trợ sẵn qua
targettrongprofiles.yml: mỗi target trỏ vào một schema khác nhau, cùng một code chạy ở đâu ra đấy. - Quyền tối thiểu: account CI chỉ được quyền ở schema test/staging; deploy prod dùng account riêng, kiểm soát chặt.
Quản lý secret & config theo môi trường
Tuyệt đối không hardcode mật khẩu DB, API key, host trong code hay commit vào Git. Thay vào đó:
- Secret (mật khẩu, token) → secret manager (Vault, cloud KMS, GitHub/GitLab CI secrets), inject vào lúc chạy qua biến môi trường.
- Config theo môi trường (tên host, schema, cỡ warehouse) → file cấu hình có version trong Git nhưng tham số hoá theo môi trường, ví dụ dbt
targethoặc profile riêng dev/staging/prod.
Cùng một dòng code, chỉ đổi biến môi trường là chạy đúng ở mọi tầng. Đây là điều kiện để "everything as code" không rò rỉ bí mật.
Gates: các cổng chất lượng bắt buộc
Một dây chuyền CI/CD chững chạc là chuỗi gate — mỗi cổng phải xanh mới đi tiếp:
- Test gate: lint + compile + unit test + data test đều pass.
- Quality gate: ngưỡng coverage test, không có test
error(chỉ chấp nhậnwarn), lineage hợp lệ. - Approval gate: với prod ngân hàng, bắt buộc người phê duyệt — thường là reviewer khác tác giả, đôi khi thêm data steward. Bước này cho phép kiểm soát tuân thủ trước khi số liệu ra thật.
Không gate nào được bỏ qua bằng thao tác tay ngoài quy trình; muốn "hotfix khẩn" cũng phải đi qua CI (có thể fast-track nhưng vẫn ghi vết).
Ví dụ pipeline CI (GitHub Actions)
Dưới đây là minh hoạ file CI chạy khi mở PR — lint, compile, và slim-test dbt. Đây là YAML, không phải SQL chạy được; các lệnh chỉ mang tính minh hoạ:
# .github/workflows/dbt-ci.yml
name: dbt CI
on:
pull_request:
branches: [ main ]
jobs:
ci:
runs-on: ubuntu-latest
env:
DBT_HOST: ${{ secrets.DBT_STAGING_HOST }}
DBT_PASSWORD: ${{ secrets.DBT_STAGING_PASSWORD }} # từ secret manager
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.11" }
- run: pip install dbt-postgres sqlfluff
- name: Lint SQL
run: sqlfluff lint models/
- name: Compile
run: dbt compile --target ci
# Lấy manifest của prod để so trạng thái (slim CI)
- name: Tải prod manifest
run: aws s3 cp s3://dbt-artifacts/prod/manifest.json ./prod/
- name: Build & test model đổi + downstream
run: dbt build --select state:modified+ --defer --state ./prod --target ci
Trên GitLab CI thì tương đương nhưng dùng stages: và rules: — ý tưởng giống hệt: lint → compile → slim build/test, chặn merge nếu fail. Bước deploy prod tách sang workflow khác, kích hoạt khi merge vào main và có environment: production với reviewer bắt buộc.
Đo lường: DORA cho dữ liệu
"Không đo thì không cải thiện được." Ta mượn bốn chỉ số DORA (DevOps Research and Assessment) của kỹ thuật phần mềm, diễn giải cho tài sản dữ liệu:
| Chỉ số DORA | Nghĩa cho data | Ví dụ mục tiêu |
|---|---|---|
| Deployment frequency | Tần suất deploy model/pipeline lên prod | Từ 1 lần/tháng → nhiều lần/tuần |
| Lead time for change | Thời gian từ commit → chạy trên prod | Từ 3 ngày → dưới 1 giờ |
| Change failure rate | Tỷ lệ deploy gây lỗi (số sai, pipeline gãy) | Dưới 10% |
| Time to restore | Thời gian khôi phục sau sự cố (rollback) | Dưới 30 phút |
Bốn chỉ số này là "sức khoẻ" của quy trình giao hàng dữ liệu. Cách quan sát và phản ứng sự cố khi đã có số liệu này được nói kỹ ở observability & incident, còn cách gây dựng thói quen đo lường trong đội ở thực hành đội nhóm. Với pipeline mô hình ML, mẫu CI/CD tương tự áp cho model — xem MLOps pipelines.
Use case thực tế
Bối cảnh: Đội dữ liệu NCB có dự án dbt ~380 model phục vụ báo cáo dư nợ, phân loại nợ nhóm 1–5, và bộ chỉ tiêu quản trị rủi ro. Trước đây deploy thủ công: analyst dán SQL vào schema prod, sửa DAG trên Airflow UI. Trung bình mỗi tháng có 1–2 sự cố "số liệu sai sau khi ai đó đổi model", mỗi lần mất 2–4 giờ điều tra.
Triển khai CI/CD:
- CI trên mỗi PR (GitHub Actions):
sqlfluff lint→dbt compile→ slim CIdbt build --select state:modified+ --defer. PR sửa 1 model chỉ build 5–9 model thay vì 380 → CI từ ~35 phút xuống ~3 phút. Data test (not_null,relationships, các assertion nghiệp vụ như "số dư VND không âm", "tổng dư nợ = tổng theo nhóm nợ") chạy trên staging đã masking PII. Fail → chặn merge. - CD promote dev → staging → prod. Deploy staging tự động sau merge; deploy prod cần approval của trưởng nhóm + data steward (approval gate) do là báo cáo gửi NHNN.
- Blue-green cho bảng báo cáo lớn: dựng schema
prod_green, chạy smoke test 4 truy vấn đối chiếu tổng, rồi swap. Rollback =git revert+ deploy lại, dưới 15 phút. - Secret chuyển vào Vault; DAG đồng bộ từ Git qua git-sync, cấm sửa UI.
Kết quả sau 1 quý (số minh hoạ): deployment frequency từ ~2 lần/tháng lên ~12 lần/tháng; lead time từ ~2 ngày xuống ~2 giờ; change failure rate từ ~25% xuống ~8%; time to restore từ ~3 giờ xuống ~15 phút. Quan trọng nhất: mọi thay đổi số liệu đều có dấu vết PR + approval, đáp ứng yêu cầu thanh tra.
Ghi nhớ
- CI/CD cho dữ liệu = áp CI/CD phần mềm (devops-04) vào SQL/dbt/pipeline/DAG. Nền tảng là analytics as code.
- CI ở mỗi PR: lint → dbt compile → unit test → data test trên môi trường test → review; chặn merge nếu fail.
- Slim CI (
state:modified+ --defer) chỉ chạy model đổi & downstream — nhanh, rẻ. - CD promote dev → staging → prod; production ngân hàng dùng Continuous Delivery có approval gate, không auto-deploy.
- Deploy DAG/dbt như code, không sửa tay UI; deploy phải idempotent; dùng blue-green + rollback để an toàn.
- Tách biệt môi trường: schema riêng, dữ liệu test đã masking, không test trên prod thật.
- Secret vào secret manager, config tham số hoá theo môi trường — không hardcode.
- Gates: test → quality → approval; versioning artifact để rollback chính xác.
- Đo bằng DORA cho data: deployment frequency, lead time, change failure rate, time to restore — dẫn sang observability và thực hành đội.
Bài viết liên quan
CSV/JSON/Parquet/Avro, lưu trữ theo hàng vs cột, nén, và OLTP vs OLAP.
Data Engineering là gì, vai trò trong vòng đời dữ liệu, và bức tranh hệ sinh thái công cụ.
Vì sao xử lý phân tán, mô hình Spark (RDD/DataFrame), lazy evaluation, shuffle và tối ưu.
Đảm bảo chất lượng & minh bạch dữ liệu bằng dbt: data tests dựng sẵn (unique, not_null, relationships, accepted_values), singular test, unit test, và tài liệu tự sinh kèm lineage graph.