# ADR-017 — Công cụ Infrastructure as Code — Terraform *Tên file: `adr/ADR-017_iac-terraform.md`* | | | |---|---| | **Status** | `Proposed` | | **Date** | 2026-09-15 | | **Người quyết** | Tech Lead + Ops/SRE (hạ tầng — `decision-radar.md §5`) — chưa ký thật | | **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) | | **Điểm radar** | **7/10** *(chấm theo `decision-radar.md §2`, kế thừa nguyên ước lượng đã ghi ở `INF_e-commerce_v1.0.md §11`: Chi phí đảo ngược=2 (>4 tuần — đổi công cụ sau khi đã có code Terraform thật cho toàn bộ hạ tầng tốn nhiều tuần viết lại + rủi ro thao tác chuyển đổi state) · Bán kính ảnh hưởng=2 (toàn bộ tài nguyên AWS của dự án) · Chạm `QAS` Must=1 (gián tiếp — nền tảng hiện thực hoá mọi `QAS` hạ tầng, không phải chính nó là một `QAS`) · Ràng buộc dài hạn=2 (chuẩn IaC nội bộ ≥1 năm) · Tranh cãi=0 → **7 ⇒ `ADR` bắt buộc**, dưới ngưỡng 8, không bắt buộc POC)* | | **Supersedes** | — | | **Superseded by** | — | | **Liên quan** | `CON-05` · `INF_e-commerce_v1.0.md §11` · `OQ-060` · `DEC-30` | > ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có > `Supersedes: ADR-017` và đổi trạng thái bản cũ thành `Superseded by`. Không sửa nội dung ADR > đã `Accepted`, không xoá ADR đã `Rejected`. --- ## 0. Ghi chú Preflight & ngoại lệ gate Viết cùng lượt với `ADR-014`/`ADR-015`/`ADR-016` dưới ngoại lệ gate ghi ở `DEC-31` (tiếp nối `DEC-01…30`) — xem `ADR-014 §0` cho bối cảnh đầy đủ. Riêng `ADR-017`: hiện thực hoá đề xuất đã ghi ở `INF_e-commerce_v1.0.md §11` (duyệt từng phần, `DEC-30`). --- ## 1. Bối cảnh Trước khi `sa-3-enablement` (GĐ3) viết code hạ tầng thật, cần chốt công cụ Infrastructure as Code (IaC) chính cho toàn dự án — tránh tình trạng mỗi thành phần hạ tầng dùng một công cụ khác nhau, không ai review/audit được nhất quán. `INF_e-commerce_v1.0.md §11` đã đề xuất Terraform và đánh dấu đây là quyết định thiết lập tiền lệ (radar ước lượng ~7, đạt ngưỡng `ADR` bắt buộc), yêu cầu SA viết `ADR` chính thức ở hoạt động `adr`. **Ràng buộc đang chi phối:** | Nguồn | Nội dung | |---|---| | `CON-05` | Năng lực đội (kỹ năng lập trình cho hạ tầng — TypeScript/Python cho CDK, hay chỉ cần HCL của Terraform) chưa xác nhận rõ | | `D9` (`design-rules.md`) | Mọi con số hạ tầng phải quy ra tiền, có nguồn, và cấu hình phải tái lập được — công cụ IaC là nền tảng để đạt điều này | **Cái đã biết chắc / cái còn là giả định:** | Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng | |---|---|---| | Terraform có cộng đồng module lớn cho ECS/RDS/ElastiCache (AWS) | 🟢 Đã kiểm chứng — thực tế công khai của hệ sinh thái Terraform | `INF §11` | | Đội có đủ kỹ năng TypeScript/Python để dùng AWS CDK hiệu quả | 🔴 Giả định chưa xác nhận | `CON-05`, `OQ-060` | | Đội có đủ kỹ năng HCL (ngôn ngữ cấu hình của Terraform) hoặc học được nhanh hơn một ngôn ngữ lập trình đầy đủ | 🔴 Giả định — Terraform HCL thường được coi là dễ tiếp cận hơn với đội chưa quen lập trình hạ tầng, nhưng chưa xác nhận với đội thật | `OQ-060` | ## 2. Phương án đã cân nhắc ### PA-1 — Terraform *(chọn)* | | | |---|---| | **Mô tả** | HashiCorp Terraform, dùng HCL để định nghĩa hạ tầng, quản lý state qua backend (đề xuất S3 + DynamoDB lock) | | **Ưu** | Đa cloud-agnostic hơn CDK (dù hiện chỉ dùng AWS — giữ tuỳ chọn mở cho tương lai); cộng đồng module lớn cho ECS/RDS/ElastiCache; không khoá vào một ngôn ngữ lập trình cụ thể (HCL là ngôn ngữ khai báo riêng, không cần biết TypeScript/Python) | | **Nhược** | HCL là một ngôn ngữ riêng cần học, dù thường được coi là dễ tiếp cận hơn ngôn ngữ lập trình đầy đủ; cần thiết lập backend state (S3 + DynamoDB lock) — thêm một phần hạ tầng nhỏ | | **Chi phí đảo ngược** | Cao (>4 tuần) nếu đổi công cụ sau khi đã có code Terraform thật cho toàn bộ hạ tầng — viết lại + rủi ro thao tác trong lúc chuyển đổi state | ### PA-2 — AWS CDK | | | |---|---| | **Mô tả** | Định nghĩa hạ tầng bằng ngôn ngữ lập trình đầy đủ (TypeScript/Python), compile ra CloudFormation | | **Ưu** | Tích hợp sâu với AWS, cho phép dùng logic lập trình (vòng lặp, hàm) trực tiếp khi định nghĩa hạ tầng | | **Nhược** | Cần kỹ năng TypeScript/Python cho hạ tầng — `CON-05` chưa xác nhận đội có; khoá vào AWS (dù hiện tại dự án chỉ dùng AWS, việc khoá vào một hãng làm giảm tuỳ chọn multi-cloud tương lai nếu cần) | | **Chi phí đảo ngược** | Cao — tương tự PA-1, đổi sau khi đã có code thật tốn nhiều tuần | ### PA-3 — AWS CloudFormation (native) | | | |---|---| | **Mô tả** | Dùng trực tiếp CloudFormation (JSON/YAML), không qua công cụ trung gian | | **Ưu** | Không cần công cụ bên thứ ba, tích hợp gốc với AWS Console/CLI | | **Nhược** | Cú pháp JSON/YAML kém module hoá hơn Terraform/CDK; cộng đồng module tái sử dụng nhỏ hơn; quản lý state kém linh hoạt hơn (CloudFormation tự quản lý state, không có backend tách rời như Terraform S3+DynamoDB, khó tách theo môi trường/nhóm tài nguyên để giảm blast radius) | | **Chi phí đảo ngược** | Trung bình-cao — viết lại theo cấu trúc module hoá tốt hơn sau này | ### Bảng so sánh | Tiêu chí | PA-1 (Terraform) | PA-2 (CDK) | PA-3 (CloudFormation) | |---|---|---|---| | Phù hợp năng lực đội hiện tại (`CON-05`, chưa xác nhận kỹ năng lập trình) | 🟡 Cần học HCL (thường dễ hơn) | 🔴 Cần TypeScript/Python | 🟡 Cần học JSON/YAML CloudFormation | | Đa cloud-agnostic (giữ tuỳ chọn tương lai) | ✅ | ❌ Khoá vào AWS | ❌ Khoá vào AWS | | Cộng đồng module tái sử dụng (ECS/RDS/ElastiCache) | ✅ Lớn | 🟡 Trung bình | 🔴 Nhỏ hơn | | Tách state theo môi trường/nhóm tài nguyên (giảm blast radius) | ✅ Linh hoạt (backend riêng) | 🟡 Qua CDK stack | 🔴 Kém linh hoạt hơn | ## 3. Quyết định > **Chọn PA-1 — Terraform làm công cụ Infrastructure as Code chính cho toàn dự án.** **Vì sao:** Cân bằng tốt nhất giữa năng lực đội chưa xác nhận rõ (`CON-05`, không đòi hỏi kỹ năng lập trình đầy đủ như CDK), hệ sinh thái module tái sử dụng lớn cho đúng các dịch vụ AWS đã chọn (ECS/RDS/ElastiCache), và khả năng tách state để giảm blast radius (yêu cầu (h) của `INF §11`). **Phạm vi áp dụng:** Toàn bộ hạ tầng AWS của dự án — network, data, compute — trong mọi môi trường (dev/stg/prod). ### Điều kiện chuyển `Proposed → Accepted` | Điều kiện | Ai xác nhận | Trạng thái hiện tại | |---|---|---| | Tech Lead xác nhận công cụ IaC (Terraform) cho P2 | Tech Lead | Mở (`OQ-060` chưa đóng) | | Ops/SRE xác nhận năng lực vận hành Terraform (đào tạo nếu cần) | Ops/SRE | Mở | | Thiết lập backend state (S3 + DynamoDB lock) thành công ở dev/stg | Ops/SRE | Chưa chạy — GĐ3 | ## 4. Phương án bị loại và lý do | Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại | |---|---|---|---| | PA-2 — AWS CDK | Cần kỹ năng TypeScript/Python cho hạ tầng mà `CON-05` chưa xác nhận đội có; khoá vào AWS làm giảm tuỳ chọn multi-cloud tương lai dù hiện chưa cần | `CON-05` | Xét lại nếu đội xác nhận có kỹ năng lập trình mạnh (TypeScript/Python) và muốn tích hợp logic lập trình phức tạp trực tiếp vào định nghĩa hạ tầng | | PA-3 — CloudFormation | Cộng đồng module nhỏ hơn, kém tái sử dụng, quản lý state kém linh hoạt hơn so với Terraform (backend S3+DynamoDB tách rời) | `INF §11` (yêu cầu tách state theo môi trường/nhóm) | Xét lại nếu tổ chức có chính sách bắt buộc chỉ dùng công cụ AWS gốc (không có ở dự án này hiện tại) | ## 5. Hệ quả **Hệ quả tích cực** - Module hoá tốt, tách state theo môi trường/nhóm tài nguyên — giảm blast radius khi `terraform apply` - Drift detection dễ tích hợp CI (`terraform plan` định kỳ, `FIT-34`) - Không khoá vào một ngôn ngữ lập trình cụ thể — giảm rào cản với đội chưa xác nhận kỹ năng TypeScript/Python **Hệ quả tiêu cực phải sống chung** - Cần đào tạo Terraform/HCL cho đội nếu chưa quen (`TCO §5`) - Cần thiết lập và vận hành backend state riêng (S3 + DynamoDB lock) — thêm một phần hạ tầng nhỏ cần quản lý (quyền truy cập, backup state) **Cái quyết định này khoá lại** | Muốn đổi về sau thì | Tốn | |---|---| | Đổi công cụ IaC sau khi đã có code Terraform thật cho toàn bộ hạ tầng | Viết lại toàn bộ + rủi ro thao tác trong lúc migrate state — nhiều tuần | **Việc phát sinh** | Việc | Chủ | Hạn | Ghi ở đâu | |---|---|---|---| | Viết Terraform module thật cho network/data/compute | Ops/SRE + Dev (GĐ3) | Trước go-live | `03-enablement/AGD_e-commerce.md` (chưa tồn tại) | | Thiết lập backend state (S3 + DynamoDB lock) | Ops/SRE | Trước khi viết module thật | GĐ3 | | Viết `FIT-34`/`FIT-35`/`FIT-36` thật | Ops/SRE (GĐ3) | GĐ3 | `03-enablement/FIT_e-commerce.md` | ## 6. Cách kiểm chứng quyết định này được tuân thủ | Cách kiểm | Công cụ | Chạy ở đâu | `FIT` | |---|---|---|---| | Drift detection — hạ tầng thật khớp Terraform state | `terraform plan` định kỳ / driftctl | CI, hàng ngày | `FIT-34` *(đã đề xuất ở `INF §11`)* | | Tag policy — mọi tài nguyên có đủ 4 tag bắt buộc | AWS Config rule / OPA | CI + AWS Config liên tục | `FIT-35` *(đã đề xuất ở `INF §11`)* | | Đúng cấu trúc hạ tầng (2 ECS service GD/HT + 1 Payment, đúng SG cô lập) | Terraform plan review + AWS Config | CI/CD | `FIT-36` *(đã đề xuất ở `INF §11`)* | ## 7. Điều kiện xét lại | Dấu hiệu | Ngưỡng | Ai theo dõi | |---|---|---| | Đội xác nhận có kỹ năng TypeScript/Python mạnh và muốn logic lập trình phức tạp trong định nghĩa hạ tầng | Ý kiến chính thức từ Tech Lead sau khi đội đã dùng Terraform một thời gian | Tech Lead | | Nhu cầu multi-cloud thật sự phát sinh | Có quyết định kinh doanh mở rộng ngoài AWS | PO + Tech Lead | ## 8. Tham chiếu - POC: Không bắt buộc (radar 7/10, dưới ngưỡng 8) - Bài đo: `FIT-34`/`FIT-35`/`FIT-36` (ứng viên GĐ3, đã đề xuất ở `INF §11`) - Tài liệu ngoài: — - Thảo luận: `INF_e-commerce_v1.0.md §11` (phát hiện + đề xuất), `OQ-060`, `DEC-30`