162 lines
5.9 KiB
Markdown
162 lines
5.9 KiB
Markdown
# 22 — CI/CD
|
|
|
|
## Phân loại
|
|
|
|
**Loại tài liệu:** Explanation với workflow reference.
|
|
|
|
**Reader job:** hiểu pipeline CI, deploy và rollback hiện có, cùng khoảng trống
|
|
giữa chúng.
|
|
|
|
## Workflow hiện có
|
|
|
|
| Workflow | Trigger | Mục đích |
|
|
|---|---|---|
|
|
| `ci.yml` | mọi push và pull request | AI Ruff/pytest, ingestion pytest, web lint/build |
|
|
| `deploy.yml` | selected paths trên `master`, manual | Build/deploy EC2 Compose và chạy smoke/observability checks |
|
|
| `rollback.yml` | manual với `target_sha` | Reset/rebuild commit tốt trước đó và verify health |
|
|
| `migrate-qdrant-snapshot.yml` | manual | Bridge snapshot một lần từ production sang practice cluster |
|
|
|
|
## CI flow
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
P[push hoặc pull request]
|
|
A[AI service: Ruff + pytest]
|
|
I[Ingestion: pytest]
|
|
W[Web: lint + build]
|
|
P --> A
|
|
P --> I
|
|
P --> W
|
|
```
|
|
|
|
`ci.yml` dùng Python 3.12 và Node 20. AI dependencies được cài tương tự
|
|
Dockerfile vì project chưa có Python lockfile. `tests/conftest.py` đặt provider
|
|
mặc định về disabled, nên unit suite không cần Qdrant/AWS. Ingestion cài bằng
|
|
`pip install -e "./ingestion[dev]"`. Web dùng `pnpm install --frozen-lockfile`.
|
|
|
|
CI hiện không chạy:
|
|
|
|
- frontend/browser tests vì chưa có test runner;
|
|
- Helm lint/template;
|
|
- real datastore integration;
|
|
- dependency, secret hoặc image vulnerability scan;
|
|
- live RAG evaluation.
|
|
|
|
## Deploy flow
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
M[master path change]
|
|
S[SSH production host]
|
|
G[fetch + reset origin/master]
|
|
B[Compose build/up]
|
|
C[Caddy + migrations]
|
|
H[health/readiness/web]
|
|
R[real RAG smoke]
|
|
O[Prometheus/Tempo/Grafana checks]
|
|
M --> S --> G --> B --> C --> H --> R --> O
|
|
```
|
|
|
|
`deploy.yml` chỉ trigger tự động cho các path mà production images/config thực
|
|
sự dùng:
|
|
|
|
- `apps/ai-service/**`;
|
|
- `apps/web/**`;
|
|
- `packages/**`;
|
|
- `ingestion/data/verified/drug_entities.json`;
|
|
- `infra/docker/**`;
|
|
- `.github/workflows/deploy.yml`.
|
|
|
|
Docs-only changes không redeploy production. `workflow_dispatch` vẫn cho phép
|
|
chạy thủ công.
|
|
|
|
## Quan hệ giữa CI và deploy
|
|
|
|
CI và deploy là **hai workflow độc lập**. `deploy.yml` không có `workflow_run`
|
|
dependency hoặc `needs` trỏ đến jobs trong `ci.yml`. Do đó:
|
|
|
|
- pull request có feedback Ruff/pytest/lint/build;
|
|
- nhưng một CI run đỏ không tự động ngăn deploy workflow được trigger bởi push
|
|
lên `master`;
|
|
- branch protection/required checks có thể giảm rủi ro, nhưng trạng thái đó
|
|
không thể xác minh chỉ từ repository.
|
|
|
|
Đây là khoảng trống khác với “không có CI”: CI đã tồn tại, nhưng chưa phải
|
|
mechanical precondition của deploy.
|
|
|
|
## Verification sau deploy
|
|
|
|
`set -e` làm mỗi assertion sau đây fatal:
|
|
|
|
1. Caddy config valid và reload được.
|
|
2. Migrations chạy trong ai-service container.
|
|
3. AI `/health` và `/ready` trả thành công.
|
|
4. Web trả thành công.
|
|
5. Condition→drug query chạy trên corpus/provider thật.
|
|
6. Response là `answerable` và có citation section `chi_dinh`.
|
|
7. Prometheus ready.
|
|
8. Tempo ready với retry.
|
|
9. Grafana health, Prometheus/Tempo datasources và dashboard tồn tại.
|
|
10. Public Grafana login route truy cập được.
|
|
11. Một request có correlation ID trả `X-Trace-ID` đúng định dạng.
|
|
12. `duocthu_requests_total` query được và đúng trace có trong Tempo.
|
|
|
|
Đây là post-deploy verification mạnh, nhưng chỉ smoke một nhánh RAG; nó không
|
|
thay thế full evaluation.
|
|
|
|
## Rollback
|
|
|
|
`rollback.yml` nhận `target_sha`, verify commit, reset production checkout,
|
|
rebuild app/observability tier, chạy migrations rồi health checks. Deploy fail
|
|
không tự gọi rollback workflow.
|
|
|
|
Migrations không có down scripts. Các migration hiện hành idempotent, nhưng một
|
|
migration tương lai không tương thích ngược có thể làm code rollback không đủ để
|
|
khôi phục dịch vụ.
|
|
|
|
## Qdrant migration workflow
|
|
|
|
`migrate-qdrant-snapshot.yml` tạo snapshot hai collection:
|
|
|
|
- `duocthu_v1`;
|
|
- `duocthu_v1__manifest`.
|
|
|
|
Nó tải snapshot về runner và upload artifact giữ một ngày. Comment của workflow
|
|
xác định đây là bridge một lần, không phải regular deployment path. Sau khi
|
|
migration practice cluster đóng, workflow nên được xóa hoặc archive để giảm
|
|
credential surface.
|
|
|
|
## Trade-off hiện tại
|
|
|
|
| Thuộc tính | Hệ quả |
|
|
|---|---|
|
|
| Build trên production host | Build failure xảy ra sau khi checkout đã chuyển SHA |
|
|
| Images không có immutable release tag | Rollback phải rebuild từ commit cũ |
|
|
| CI/deploy độc lập | Red CI không tự động chặn deploy |
|
|
| Deploy in-place | Có thể có gián đoạn ngắn khi service rebuild/restart |
|
|
| Stateful services không nằm trong deploy `up` list | Code deploy không restart PostgreSQL/Qdrant |
|
|
| Post-deploy smoke dùng provider thật | Bắt được lỗi integration nhưng tốn thời gian/cost và chỉ phủ một flow |
|
|
|
|
## Target GitOps chưa hoạt động
|
|
|
|
`infra/ci/github-actions/README.md` mô tả các workflow tách nhỏ và
|
|
`bump-image-tag.yml` cho GitOps. Những file được hứa trong đó chưa tồn tại. CI
|
|
thực tế là workflow hợp nhất `ci.yml`; image registry/promotion và ArgoCD update
|
|
loop vẫn là target state.
|
|
|
|
## Ưu tiên tiếp theo
|
|
|
|
1. Làm green required checks thành điều kiện cơ học trước production deploy.
|
|
2. Build/tag/push immutable images trong CI và deploy theo tag/digest.
|
|
3. Thêm frontend tests, Helm render/lint và migration tests.
|
|
4. Thêm evaluation regression gate tách khỏi live post-deploy smoke.
|
|
5. Xóa workflow migration một lần sau khi hoàn thành nhiệm vụ.
|
|
|
|
## Liên quan
|
|
|
|
- [How to deploy and rollback](how-to/deploy-and-rollback.md)
|
|
- [Testing](18-testing.md)
|
|
- [Deployment](20-deployment.md)
|
|
- [Kubernetes and ArgoCD](21-kubernetes-and-argocd.md)
|
|
- [Production operations](24-production-operations.md)
|