Platform Engineering 2 — IaC với Terraform/OpenTofu

13 thg 7, 2026 3 lượt xem
#devops
#iac
#terraform
#infrastructure
#opentofu

Trong Platform Engineering — Tổng quan, ý tưởng cốt lõi là platform team cung cấp cho developer một golden path: con đường chuẩn, tự phục vụ, an toàn để tạo hạ tầng mà không cần trở thành chuyên gia cloud. Viên gạch nền của con đường đó chính là Infrastructure as Code (IaC) — hạ tầng được mô tả bằng code thay vì thao tác tay trên console. Bài này đi sâu vào IaC với TerraformOpenTofu, hai công cụ phổ biến nhất hiện nay, và cách chúng trở thành xương sống của một internal developer platform.

IaC là gì và tại sao quan trọng

IaC là việc mô tả toàn bộ hạ tầng — mạng (VPC, subnet), máy ảo, cluster Kubernetes, database, bucket lưu trữ, IAM role, DNS — dưới dạng file text được lưu trong Git. Thay vì "vào AWS console bấm tạo một RDS", bạn viết một đoạn code khai báo "tôi muốn một PostgreSQL 16, 2 vCPU, backup 7 ngày", commit lên Git, và công cụ IaC sẽ tạo đúng như vậy.

Lợi ích không chỉ là tiện:

  • Tái lập (reproducibility): cùng một đoạn code tạo ra hạ tầng giống hệt ở dev, staging, prod. Không còn cảnh "prod chạy được mà staging thì không" do cấu hình lệch.
  • Review và audit: mọi thay đổi hạ tầng đi qua pull request, có người review, có lịch sử ai đổi gì, khi nào, vì sao. Với ngân hàng, đây là bằng chứng tuân thủ vô giá.
  • Versioning: hạ tầng có lịch sử Git như code. Muốn biết tháng trước firewall mở port nào, chỉ cần git log. Muốn rollback, git revert.
  • Chống drift và click-ops: "click-ops" (bấm tay trên console) tạo ra hạ tầng không ai ghi lại được, dễ lệch (drift) so với thiết kế. IaC biến hạ tầng thành nguồn sự thật duy nhất trong Git.

Các khái niệm nền tảng của IaC được trình bày kỹ hơn ở DevOps — Infrastructure as CodeCloud — IaC & DevOps. Bài này tập trung vào chiều sâu Terraform/OpenTofu và góc nhìn platform.

Terraform và OpenTofu

Terraform (HashiCorp, ra mắt 2014) là công cụ IaC phổ biến nhất, dùng ngôn ngữ khai báo HCL (HashiCorp Configuration Language). Nó không gắn với một cloud cụ thể: thông qua provider, cùng một công cụ quản lý được AWS, Azure, GCP, Kubernetes, Cloudflare, thậm chí GitHub hay Datadog.

Bối cảnh OpenTofu

Tháng 8/2023, HashiCorp đổi license Terraform từ MPL 2.0 (mã nguồn mở thực thụ) sang BSL 1.1 (Business Source License) — một license "source-available" hạn chế: cấm dùng Terraform để cạnh tranh thương mại với HashiCorp. Cộng đồng phản ứng mạnh vì nhiều công ty xây dịch vụ dựa trên Terraform. Kết quả là một fork ra đời: OpenTofu, giữ nguyên MPL 2.0, được đưa vào Linux Foundation quản lý (9/2023, ban đầu tên OpenTF).

OpenTofu tương thích gần như hoàn toàn với Terraform ở cú pháp HCL và định dạng state, dùng lệnh tofu thay cho terraform. Đa số cấu hình Terraform chạy được với OpenTofu chỉ bằng đổi binary. Từ đó hai nhánh bắt đầu phân kỳ tính năng (ví dụ OpenTofu có state encryption, early variable evaluation riêng). Về platform engineering, lựa chọn giữa hai công cụ chủ yếu là bài toán license và governance — nhiều tổ chức nhạy cảm về pháp lý chuyển sang OpenTofu để tránh ràng buộc BSL. Phần còn lại của bài dùng "Terraform" như tên chung cho cả hai vì mô hình vận hành giống nhau.

Các khái niệm cốt lõi

  • Provider: plugin nói chuyện với API của một nền tảng (ví dụ hashicorp/aws). Khai báo version để tái lập.
  • Resource: đơn vị hạ tầng cần tạo và quản lý — một VPC, một bucket, một cluster.
  • Data source: đọc thông tin sẵn có mà không tạo mới — ví dụ lấy AMI mới nhất, hay tra cứu subnet đã tồn tại.
  • Vòng đời lệnh:
    • plan — Terraform so sánh code mong muốn với thực tế và in ra sẽ đổi gì (thêm/sửa/xoá) mà chưa động vào hạ tầng. Đây là bước review quan trọng nhất.
    • apply — thực thi thay đổi để hạ tầng khớp với code.
    • destroy — xoá toàn bộ tài nguyên do code này quản lý.

State file — trái tim của Terraform

Terraform lưu một state file (terraform.tfstate, định dạng JSON) ghi ánh xạ giữa resource trong code và tài nguyên thật (kèm ID, thuộc tính). State cần thiết vì:

  • Terraform biết resource aws_db_instance.core ứng với RDS db-abc123 nào để sửa/xoá đúng đối tượng.
  • Nó là cơ sở để plan tính diff và để drift detection (phát hiện ai đó sửa tay ngoài code).

State đặt cục bộ (local) chỉ hợp cho học tập. Trong nhóm phải dùng remote state — lưu ở nơi chia sẻ được như S3, Azure Blob, GCS, Terraform Cloud, hay HTTP backend của GitLab. Remote state đi kèm hai yêu cầu sống còn:

  • Locking: khi một người đang apply, state bị khoá để người khác không apply đồng thời gây hỏng. Ví dụ backend S3 có thể dùng DynamoDB (hoặc S3 native lock ở phiên bản mới) làm khoá.
  • Bảo mật: state chứa dữ liệu nhạy cảm (mật khẩu DB, private key sinh ra). Phải mã hoá at-rest, hạn chế quyền truy cập chặt.

Modules — nền của golden path

Module là cách đóng gói một nhóm resource thành đơn vị tái sử dụng, với input (biến vào) và output (giá trị ra). Ví dụ một module secure-bucket nhận tên bucket, tự động bật versioning, mã hoá, chặn public access, và trả về ARN.

Module là mắt xích biến IaC thành golden path: platform team viết các module chuẩn đã gắn sẵn network, security, tagging, logging đúng chính sách công ty; developer chỉ việc gọi module với vài tham số, không cần biết chi tiết bảo mật bên dưới. Đây chính là cơ chế "an toàn theo mặc định" (secure by default).

Cần versioning module: publish module lên registry (Terraform Registry, một Git repo có tag, hoặc registry nội bộ) và pin version khi dùng (version = "~> 3.2"). Nhờ đó nâng cấp module có kiểm soát, không phá vỡ team đang dùng bản cũ.

# MINH HOẠ — không phải cấu hình thật của NCB
module "data_bucket" {
  source  = "app.terraform.io/ncb/secure-bucket/aws"
  version = "3.2.0"

  name        = "ncb-data-team-raw"
  environment = "prod"
  # module tự bật encryption, versioning, block-public,
  # gắn tag cost-center và network policy theo chuẩn platform
}

output "bucket_arn" {
  value = module.data_bucket.arn
}

Quản lý môi trường: dev/staging/prod

Một sai lầm kinh điển là dùng chung một cấu hình cho mọi môi trường. Có hai trường phái tách môi trường:

CáchƯu điểmNhược điểm
Workspaces (cùng code, state tách theo workspace)Ít lặp codeDễ nhầm apply nhầm môi trường; khó tuỳ biến sâu; state trong cùng backend
Thư mục riêng (envs/dev, envs/prod)Cô lập rõ ràng, state và backend riêng, prod tách biệt tuyệt đốiLặp cấu hình nhiều hơn (giảm bằng module hoặc Terragrunt)

Đa số tổ chức nghiêm túc — nhất là ngân hàng — chọn thư mục riêng cho prod để cách ly rủi ro, kết hợp module dùng chung để tránh lặp. Workspaces phù hợp các biến thể nhẹ (ví dụ nhiều region cùng cấu hình).

Biến và secrets

Biến (variable) tách giá trị khỏi logic: cùng module, dev cấp 2 vCPU, prod cấp 8 vCPU. Tuyệt đối không hardcode secret (mật khẩu, token, key) vào file .tf hay commit .tfvars chứa bí mật lên Git. Thay vào đó lấy secret lúc chạy từ Vault, AWS Secrets Manager, hay biến môi trường CI. Chủ đề này được đào sâu ở Platform — Secrets & Security. Lưu ý quan trọng: kể cả khi lấy secret từ Vault, giá trị vẫn rơi vào state — nên state phải được coi là dữ liệu bí mật.

Declarative, idempotency và dependency graph

Terraform là declarative (khai báo): bạn mô tả trạng thái mong muốn ("tôi muốn 3 máy"), công cụ tự tính cách đạt tới. Ngược với imperative (mệnh lệnh): bạn viết từng bước ("tạo máy 1, rồi máy 2..."). Khác biệt thực tế:

  • Idempotency: chạy apply nhiều lần trên code không đổi thì không tạo thêm gì — kết quả hội tụ về trạng thái mong muốn. Script bash mệnh lệnh chạy hai lần dễ tạo trùng.
  • Dependency graph: Terraform tự dựng đồ thị phụ thuộc từ tham chiếu giữa resource (subnet tham chiếu VPC → VPC phải tạo trước). Nó tạo/xoá theo đúng thứ tự và song song hoá phần độc lập, bạn không phải tự sắp xếp.

IaC trong GitOps và CI/CD

Sức mạnh thật của IaC bộc lộ khi ghép vào pipeline. Mô hình chuẩn:

  1. Dev sửa HCL, mở Pull Request.
  2. CI tự động chạy planđăng kết quả diff vào PR để reviewer thấy chính xác hạ tầng sẽ đổi gì.
  3. Policy check tự động: dùng OPA/Conftest, Sentinel, hay tfsec/Checkov để chặn cấu hình vi phạm (ví dụ bucket public, thiếu tag, instance quá lớn) trước khi apply.
  4. Khi PR được approve và merge, CI chạy apply — không ai apply tay từ máy cá nhân.

Nguyên tắc này cộng hưởng với GitOps: Git là nguồn sự thật, thay đổi qua PR, tự động đồng bộ. Xem GitOps với Argo CD cho tầng ứng dụng Kubernetes và CI/CD Pipelines cho cách dựng pipeline plan/apply. Điểm cần phân biệt: Terraform mạnh cho hạ tầng bên ngoài cluster (mạng, DB, cluster nền); Argo CD/GitOps mạnh cho bên trong cluster (workload, manifest) — nhiều platform dùng cả hai.

Các công cụ liên quan

  • Pulumi: IaC bằng ngôn ngữ lập trình thật (TypeScript, Python, Go, C#) thay vì HCL. Ưu điểm là dùng vòng lặp, hàm, test như code thường; đổi lại phức tạp hơn và cần kỹ năng lập trình. Vẫn mang tính declarative qua state riêng.
  • Crossplane: biến hạ tầng thành tài nguyên Kubernetes — bạn khai báo database bằng một Custom Resource, control loop của Crossplane tự tạo qua provider. Hợp khi đã đứng trọn trên K8s và muốn quản lý mọi thứ bằng K8s API. Chi tiết vận hành K8s xem Kubernetes — Production Ops.
  • Terragrunt: lớp bọc mỏng quanh Terraform để giảm lặp (DRY) khi có nhiều môi trường/nhiều account, quản lý backend và biến chung tập trung. Không thay Terraform mà bổ trợ.

Cạm bẫy thực chiến

  • State hỏng hoặc lock kẹt: state bị sửa tay, xung đột, hoặc lock không nhả (khi apply bị kill giữa chừng) làm cả team đứng hình. Luôn dùng remote state có locking, bật versioning trên bucket state để khôi phục, và biết cách force-unlock cẩn trọng.
  • Secrets trong state: dễ quên rằng state là plaintext theo mặc định. Mã hoá at-rest, siết IAM, và cân nhắc state encryption (OpenTofu hỗ trợ native).
  • Module quá to (God module): một module ôm cả VPC lẫn DB lẫn app khiến mỗi thay đổi nhỏ phải plan toàn bộ, blast radius lớn. Chia module theo trách nhiệm, kích thước vừa phải.
  • Apply tay ngoài pipeline: ai đó apply từ laptop tạo drift so với Git, phá nguyên tắc nguồn sự thật. Chỉ cho apply qua CI với quyền hạn chế; laptop chỉ được chạy plan.
  • Không pin version: provider/module trôi version âm thầm gây khác biệt giữa các lần chạy. Luôn pin và cập nhật có kiểm soát.
  • Blast radius: một destroy nhầm workspace có thể xoá prod. Tách state theo môi trường, đặt bảo vệ (prevent_destroy), và bắt buộc approve cho prod.

Use case thực tế

Bối cảnh: Tại NCB, team dữ liệu thường xuyên cần tài nguyên mới — bucket lưu dữ liệu thô, một database phân tích, một service account, một topic message queue. Trước đây họ phải gửi ticket cho team hạ tầng, chờ trung bình 3–5 ngày làm việc; mỗi yêu cầu là một lần trao đổi qua lại về đặt tên, network, phân quyền. Cấu hình lệch nhau vì mỗi kỹ sư hạ tầng làm một kiểu, và không ít tài nguyên tạo tay (click-ops) không ai ghi lại.

Giải pháp golden path: platform team đóng gói module Terraform chuẩn cho từng loại tài nguyên phổ biến. Các module này đã gắn sẵn:

  • Network policy đúng chuẩn (subnet nội bộ, không mở public, security group theo whitelist).
  • Security mặc định: mã hoá at-rest, TLS, backup, audit log bật sẵn.
  • Tag bắt buộc: cost-center, data-classification, owner — để tính chi phí và phân loại dữ liệu phục vụ tuân thủ.

Team data không viết HCL từ đầu; họ chỉ gọi module với vài input trong một repo Git riêng, mở PR. Pipeline tự chạy plan, tfsec/policy check (Conftest với OPA) và đăng diff vào PR. Kỹ sư platform review nhanh (vì độ lệch bị policy chặn sẵn), approve; CI chạy apply với service account hạn chế. Prod tách thư mục riêng, có bước approve thủ công riêng.

Kết quả (số liệu ước lượng, minh hoạ):

Chỉ sốTrướcSau
Thời gian cấp tài nguyên3–5 ngày~30–60 phút (chờ review + apply)
Tài nguyên tạo tay (click-ops)phần lớngần như 0
Sự cố do cấu hình lệch/quên bảo mậtvài vụ/quýhiếm (policy chặn)
Bằng chứng audit thay đổi hạ tầngrời rạc, thủ côngtự động qua Git + PR

Điểm mấu chốt: platform không "mở cửa cho làm gì cũng được" mà thu hẹp lựa chọn về con đường an toàn — dev tự phục vụ nhanh, còn network/security được đảm bảo ngay trong module. Đây là hình mẫu quản trị dữ liệu ngân hàng: nhanh mà vẫn kiểm soát.

Ghi nhớ

  • IaC = hạ tầng bằng code trong Git: tái lập, review qua PR, có version, chống drift và click-ops. Là viên gạch nền của platform và golden path.
  • Terraform vs OpenTofu: OpenTofu là fork mã nguồn mở (MPL 2.0, Linux Foundation) ra đời sau khi HashiCorp đổi Terraform sang license BSL 1.1 (8/2023). Cú pháp HCL và state gần như tương thích; lệnh tofu. Lựa chọn chủ yếu vì license/governance.
  • State là trái tim: ánh xạ code ↔ tài nguyên thật, cơ sở của plan và drift detection. Nhóm phải dùng remote state có locking, coi state là dữ liệu bí mật (chứa secret).
  • Module = tái sử dụng + secure by default: platform cấp module chuẩn đã gắn network/security/tag; dev chỉ truyền input. Nhớ versioning và pin version.
  • Tách môi trường: thư mục riêng cho prod (cách ly rủi ro) là lựa chọn an toàn; workspaces cho biến thể nhẹ. Không hardcode secret — lấy lúc chạy từ Vault/Secrets Manager.
  • Declarative + idempotent + dependency graph: mô tả trạng thái mong muốn, apply nhiều lần vẫn hội tụ, thứ tự tạo/xoá tự suy ra.
  • IaC trong CI/GitOps: plan tự động đăng diff vào PR, policy check chặn vi phạm trước apply, chỉ apply qua pipeline — không apply tay.
  • Cạm bẫy: state hỏng/lock kẹt, secret trong state, module quá to, apply tay ngoài pipeline, không pin version, blast radius khi destroy nhầm.
  • Công cụ họ hàng: Pulumi (IaC bằng ngôn ngữ lập trình), Crossplane (IaC qua K8s API), Terragrunt (giảm lặp cho Terraform).

Nguồn tham khảo

Bài viết liên quan

Phân biệt Continuous Integration, Delivery và Deployment; giải phẫu một pipeline (trigger, stage, job, step, artifact) và các lớp kiểm thử xếp theo chi phí. Bài viết một workflow GitHub Actions hoàn chỉnh (build, test, Docker), so sánh với GitLab CI, quản lý secrets an toàn và chọn chiến lược release rolling/blue-green/canary kèm cách rollback.

13 thg 7, 2026 5

Bản đồ Kubernetes: control plane (API server, etcd, scheduler, controller manager), node (kubelet, kube-proxy, container runtime), mô hình khai báo & vòng điều khiển (reconciliation), và cách một Pod được tạo ra.

13 thg 7, 2026 4

Bài mở đầu series Linux cho data engineer: vì sao mọi hạ tầng dữ liệu đều chạy Linux, triết lý Unix, phân biệt terminal/shell/kernel, cấu trúc một lệnh, chuẩn thư mục FHS và cách đăng nhập server qua SSH.

13 thg 7, 2026 4

Lập lịch job trích xuất dữ liệu trên Linux: cú pháp cron 5 trường, crontab, /etc/cron.d, MAILTO, khoá chống chồng job bằng flock; job một lần với at; systemd service & timer (OnCalendar, Persistent) như thay thế cron hiện đại, journalctl và logrotate. Bài mổ xẻ vì sao script chạy tay OK mà cron fail — sự khác biệt login/non-login shell và biến môi trường — cùng cách quản lý package (apt/yum/dnf) và so sánh cron vs systemd timer vs Airflow.

13 thg 7, 2026 4

Cảm nhận của bạn

Bình luận

Bạn cần để viết bình luận.

Chưa có bình luận. Hãy là người đầu tiên chia sẻ!