Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn là kỹ sư hạ tầng ở một công ty fintech tại TP.HCM. Sếp gọi bạn lên và nói: "Tuần sau chúng ta demo cho nhà đầu tư Singapore, cần dựng một môi trường staging giống hệt production để họ test." Bạn mở console AWS, click chuột dựng VPC, tạo subnet, khởi chạy vài EC2, cấu hình security group, gắn database... Ba ngày sau, môi trường staging chạy được, nhưng nó không thật sự giống production — bạn quên mở một port, đặt sai instance type, và cái security group thì lỏng lẻo hơn bản thật. Đến lúc demo, ứng dụng lỗi vì khác cấu hình. Đây là cơn ác mộng kinh điển của việc quản lý hạ tầng bằng tay (ClickOps).
Infrastructure as Code (IaC) — Hạ tầng dưới dạng mã — sinh ra để giải quyết đúng vấn đề này. Thay vì click chuột, bạn mô tả toàn bộ hạ tầng bằng file văn bản (code), rồi để công cụ tự động tạo ra chính xác những gì bạn khai báo. Muốn dựng lại môi trường lần thứ N? Chạy lại một lệnh. Muốn biết ai đã đổi cấu hình firewall lúc 2 giờ sáng? Xem lịch sử Git.
Trong lộ trình khóa học này, các bài về Terraform cho AWS (Bài 48) và Configuration Management (Bài 49) sẽ đi sâu vào thực hành từng công cụ. Bài 47 hôm nay đóng vai trò nền tảng tư duy: hiểu IaC là gì, vì sao nó thay đổi cách chúng ta làm việc, và phân biệt được ba "ông lớn" bạn sẽ gặp nhất trong thực tế — Terraform, CloudFormation, và Pulumi.
Khái niệm cốt lõi
IaC là gì và không phải là gì
IaC là việc quản lý và cung cấp (provision) hạ tầng thông qua các file định nghĩa mà máy đọc được, thay vì thao tác thủ công qua giao diện. "Hạ tầng" ở đây bao gồm máy ảo, mạng, database, load balancer, quyền truy cập IAM — gần như mọi tài nguyên cloud.
Điểm mấu chốt: IaC coi hạ tầng giống như phần mềm. Nghĩa là code hạ tầng cũng được lưu trong Git, review qua Pull Request, chạy qua CI/CD, và có thể rollback. Đây là bước ngoặt tư duy: hạ tầng không còn là "một mớ tài nguyên ai đó dựng lên rồi không dám đụng", mà là tài sản có phiên bản, có kiểm soát.
Ba lợi ích trụ cột
Reproducible (tái lập được). Cùng một đoạn code, chạy bao nhiêu lần cũng ra kết quả giống nhau. Bạn có thể spin up một môi trường y hệt cho dev, staging, production chỉ bằng cách đổi vài biến. Không còn cảnh "máy của tôi chạy được mà server thì không".
Version control (kiểm soát phiên bản). Mọi thay đổi hạ tầng đi qua Git. Muốn thêm một server? Bạn mở PR, đồng nghiệp review, thấy chính xác dòng nào thay đổi trước khi apply. Điều này biến việc sửa firewall — vốn là hành động rủi ro cao — thành một quy trình minh bạch, có người kiểm tra chéo.
Audit (kiểm toán). Ai đổi gì, khi nào, vì sao — tất cả nằm trong lịch sử commit. Với các công ty phải tuân thủ chuẩn như ISO 27001 hay PDPL (Nghị định 13 về bảo vệ dữ liệu cá nhân tại Việt Nam), khả năng truy vết này là bắt buộc, không phải tùy chọn.
Declarative vs Imperative
Đây là khái niệm bạn cần nắm thật chắc.
Declarative (khai báo): Bạn mô tả trạng thái mong muốn — "tôi muốn có 3 server, một load balancer, một database Postgres". Công cụ tự tính toán cần làm gì để đạt trạng thái đó. Terraform và CloudFormation theo hướng này.
Imperative (mệnh lệnh): Bạn viết các bước cụ thể — "tạo server 1, rồi tạo server 2, rồi gắn load balancer". Bạn kiểm soát chi tiết hơn nhưng phải tự lo thứ tự và logic.
Đa số IaC hiện đại theo hướng declarative vì nó gọn và an toàn hơn. Bạn nói "muốn gì", công cụ lo "làm thế nào".
State — linh hồn của IaC
Để biết cần thay đổi gì, công cụ IaC phải nhớ hiện tại đang có gì. Đó là state (trạng thái). Terraform lưu state trong một file (thường đặt trên S3 hoặc GCS), CloudFormation lưu state phía AWS quản lý hộ bạn. State cho phép công cụ so sánh: "trạng thái mong muốn trong code" với "trạng thái thực tế đang chạy", rồi chỉ thay đổi phần khác biệt. Hiểu sai về state là nguyên nhân số một gây sự cố với người mới — chúng ta sẽ nói kỹ ở phần lỗi thường gặp.
Ba công cụ chính
Terraform (HashiCorp). Phổ biến nhất, đa cloud (AWS, GCP, Azure, và cả cloud Việt Nam qua provider tương thích). Dùng ngôn ngữ khai báo riêng tên là HCL (HashiCorp Configuration Language) — dễ đọc, không cần biết lập trình sâu. Điểm mạnh: trung lập với nhà cung cấp, cộng đồng khổng lồ. Lưu ý: từ 2023 Terraform đổi sang giấy phép BSL, dẫn đến sự ra đời của bản fork mã nguồn mở OpenTofu — về mặt cú pháp gần như tương thích hoàn toàn.
CloudFormation (AWS). Công cụ IaC "gốc" của AWS, dùng YAML hoặc JSON. Điểm mạnh: tích hợp sâu nhất với AWS, được AWS quản lý state hộ, miễn phí. Điểm yếu: chỉ dùng cho AWS, cú pháp YAML dài dòng khi dự án lớn.
Pulumi. Cho phép viết hạ tầng bằng ngôn ngữ lập trình thật — TypeScript, Python, Go, C#. Điểm mạnh: dùng được vòng lặp, hàm, class như code bình thường; hợp với đội đã mạnh về một ngôn ngữ. Điểm yếu: cần kỹ năng lập trình, cộng đồng nhỏ hơn Terraform.
Tình huống thực tế
Ví dụ 1 — Startup thương mại điện tử ở Hà Nội cứu vãn môi trường staging
Một startup e-commerce khoảng 25 người ở Hà Nội gặp đúng vấn đề tôi kể ở đầu bài. Họ có production trên AWS dựng bằng tay suốt hai năm. Mỗi lần cần môi trường test, một bạn DevOps phải bỏ ra 2–3 ngày dựng lại, và luôn thiếu sót đâu đó.
Nhóm quyết định "code hóa" hạ tầng bằng Terraform. Trong 6 tuần, họ viết lại toàn bộ VPC, các Auto Scaling Group, RDS Postgres, và ElastiCache thành module Terraform. Họ dùng biến environment để tách dev/staging/prod. Kết quả: thời gian dựng một môi trường mới giảm từ 2–3 ngày xuống còn 25 phút, và quan trọng hơn — staging giờ giống production 100% vì dùng chung code, chỉ khác kích thước instance.
Bài học: IaC không chỉ tiết kiệm thời gian, nó loại bỏ sai lệch cấu hình (configuration drift) giữa các môi trường — nguyên nhân của rất nhiều bug "chỉ xảy ra trên production".
Ví dụ 2 — Công ty SaaS chọn CloudFormation vì đã "all-in AWS"
Một công ty SaaS về phần mềm kế toán ở Đà Nẵng, khoảng 40 kỹ sư, dùng 100% AWS và không có ý định đa cloud. Đội của họ tranh luận: dùng Terraform hay CloudFormation?
Họ chọn CloudFormation vì ba lý do thực tế: (1) không phải quản lý state file riêng — AWS lo hộ, giảm rủi ro mất state; (2) tích hợp sẵn với các dịch vụ mới của AWS ngay khi ra mắt; (3) đội nhỏ, không muốn thêm công cụ bên thứ ba vào chuỗi kiểm toán bảo mật. Họ dùng AWS SAM (một lớp mở rộng của CloudFormation) để quản lý các hàm Lambda và API Gateway.
Sau một năm, nhận định của họ: CloudFormation "đủ dùng và ổn định" cho một shop thuần AWS. Điểm khó chịu duy nhất là file YAML dài, nên họ chia nhỏ thành nested stack.
Bài học: Không có công cụ "tốt nhất" tuyệt đối. Nếu bạn cam kết với một cloud duy nhất và muốn ít mảnh ghép nhất, công cụ native (CloudFormation với AWS, hoặc Deployment Manager/Bicep với các cloud khác) thường là lựa chọn thực dụng.
Ví dụ 3 — Đội platform dùng Pulumi vì team toàn dev Python
Một công ty logistics tại Singapore mở rộng sang thị trường Việt Nam, có một đội platform 8 người mà đa số vốn là backend developer Python. Họ thấy việc học cú pháp HCL riêng của Terraform là rào cản, và họ có nhiều logic hạ tầng phức tạp — ví dụ sinh động 30 hàng đợi (queue) theo danh sách khách hàng đọc từ một file cấu hình.
Với Pulumi, họ viết hạ tầng bằng chính Python. Vòng lặp for để tạo 30 queue chỉ mất vài dòng, tái sử dụng được hàm, viết được unit test cho logic hạ tầng bằng pytest — điều rất khó làm gọn với HCL.
Bài học: Khi hạ tầng của bạn có nhiều logic động và đội đã mạnh về một ngôn ngữ lập trình, Pulumi cho bạn sức mạnh của ngôn ngữ thật. Đổi lại, bạn cần kỷ luật để code hạ tầng không trở nên rối như code ứng dụng.
Hướng dẫn từng bước
Dưới đây là quy trình chuẩn để áp dụng IaC cho một dự án, minh họa bằng Terraform (nhưng tư duy áp dụng cho cả ba công cụ).
Bước 1 — Chọn công cụ theo bối cảnh. Đa cloud hoặc muốn kỹ năng chuyển việc dễ nhất → Terraform/OpenTofu. Thuần AWS, muốn tối giản → CloudFormation. Đội mạnh lập trình, hạ tầng nhiều logic → Pulumi.
Bước 2 — Thiết lập backend cho state. Đừng bao giờ để state file nằm trên laptop. Với Terraform, tạo một S3 bucket (hoặc GCS/Azure Blob) để lưu state, và bật state locking (dùng DynamoDB với AWS) để hai người không apply cùng lúc gây hỏng state.
Bước 3 — Viết code cho một tài nguyên nhỏ trước. Ví dụ chỉ một S3 bucket. Với Terraform, đây là đoạn HCL tối giản:
resource "aws_s3_bucket" "logs" {
bucket = "cong-ty-abc-logs-staging"
tags = {
Environment = "staging"
ManagedBy = "terraform"
}
}
Bước 4 — Chạy plan trước khi apply. Lệnh terraform plan cho bạn xem trước những gì sẽ được tạo/sửa/xóa mà chưa đụng vào thật. Đây là bước an toàn quan trọng nhất — luôn đọc kỹ output trước khi apply. Với CloudFormation, tương đương là "change set".
Bước 5 — Apply và kiểm tra. Chạy terraform apply, xác nhận, rồi kiểm tra tài nguyên đã tạo đúng trên console.
Bước 6 — Đưa vào Git và thiết lập quy trình review. Commit code, tạo PR. Thiết lập quy tắc: mọi thay đổi hạ tầng phải qua PR, phải có plan được chạy tự động bởi CI để reviewer thấy tác động.
Bước 7 — Module hóa và tham số hóa. Khi đã quen, gom các tài nguyên lặp lại thành module (ví dụ module "web-service" gồm ASG + load balancer), dùng biến để tái sử dụng cho nhiều môi trường.
Bước 8 — Tích hợp CI/CD. Cho plan chạy tự động khi mở PR, và apply chạy khi merge vào nhánh chính (thường cần một người phê duyệt thủ công ở bước apply cho môi trường production).
Lỗi thường gặp & mẹo
Sửa tay trên console rồi quên cập nhật code (drift). Đây là lỗi phổ biến nhất. Ai đó vào console đổi một security group cho "nhanh", nhưng code IaC không biết. Lần apply sau, công cụ sẽ ghi đè thay đổi tay đó, hoặc gây xung đột. Mẹo: đặt luật cứng "không click tay trên môi trường có IaC". Định kỳ chạy terraform plan để phát hiện drift.
Để state file trên máy cá nhân. Nếu state chỉ nằm trên laptop bạn, đồng nghiệp không apply được, và mất máy là mất khả năng quản lý hạ tầng. Luôn dùng remote backend (S3/GCS/Azure Blob) và bật locking.
Lưu secret trong code hoặc state. State file có thể chứa mật khẩu database ở dạng plaintext. Đừng commit state vào Git, và mã hóa bucket lưu state. Dùng dịch vụ quản lý bí mật riêng (chủ đề của Bài 28) thay vì hardcode.
Apply thẳng lên production không qua plan. Một lần chạy nhầm có thể xóa cả database. Luôn plan trước, luôn có bước phê duyệt thủ công cho production. Đặc biệt cảnh giác với những thay đổi khiến công cụ báo "destroy and recreate" — nó có thể xóa dữ liệu.
Một state khổng lồ cho toàn bộ hạ tầng. Khi mọi thứ nằm chung một state, mỗi lần apply đều chậm và rủi ro cao. Mẹo: chia hạ tầng thành các state nhỏ theo domain (mạng riêng, ứng dụng riêng, data riêng).
Mẹo tổng quát: Bắt đầu nhỏ. Đừng cố "code hóa" toàn bộ hạ tầng cũ trong một tuần. Chọn một phần ít rủi ro (ví dụ môi trường dev), làm cho tốt, rồi mở rộng dần. Đồng thời, dùng import để đưa tài nguyên đã tạo tay vào quản lý IaC thay vì xóa đi làm lại.
Bài tập thực hành
- So sánh ba công cụ theo bối cảnh của bạn. Giả sử bạn là DevOps của một công ty gọi xe Việt Nam dùng 90% AWS nhưng đang cân nhắc dùng thêm GCP cho phần AI. Viết một đoạn 200 từ lập luận nên chọn Terraform, CloudFormation hay Pulumi, nêu rõ 3 lý do.
- Viết cấu hình đầu tiên. Cài Terraform (hoặc OpenTofu) trên máy, cấu hình một S3 bucket đơn giản như ví dụ ở Bước 3. Chạy
plan, đọc kỹ output, rồiapply. Sau đó sửa tag trong code và chạy lạiplanđể quan sát Terraform nhận diện đúng phần thay đổi.
- Mô phỏng drift. Sau khi tạo bucket bằng Terraform, vào console AWS thêm một tag bằng tay. Quay lại chạy
terraform planvà ghi lại: Terraform báo gì? Nó định làm gì với tag bạn thêm tay? Rút ra bài học về lý do không nên sửa tay.
- Thiết kế quy trình. Vẽ sơ đồ quy trình review thay đổi hạ tầng qua PR cho một đội 5 người: từ lúc mở PR, chạy
plantự động, review, đến apply. Chỉ ra ở bước nào cần phê duyệt thủ công và vì sao.
Tóm tắt
Infrastructure as Code biến hạ tầng từ "một mớ tài nguyên click tay" thành code có phiên bản, review được, kiểm toán được. Ba lợi ích trụ cột là tái lập (reproducible), kiểm soát phiên bản (version control) và kiểm toán (audit) — cùng nhau chúng loại bỏ configuration drift và biến những thay đổi rủi ro thành quy trình minh bạch.
Về công cụ: Terraform/OpenTofu là lựa chọn linh hoạt, đa cloud, phổ biến nhất và dễ chuyển việc nhất. CloudFormation thực dụng cho shop thuần AWS muốn tối giản mảnh ghép. Pulumi mạnh khi đội giỏi lập trình và hạ tầng nhiều logic động. Không có công cụ "tốt nhất" tuyệt đối — chọn theo cloud bạn dùng, kỹ năng đội, và độ phức tạp hạ tầng.
Nguyên tắc vàng cho người mới: luôn dùng remote state có locking, luôn plan trước khi apply, không bao giờ sửa tay trên môi trường đã có IaC, và bắt đầu từ phần nhỏ ít rủi ro. Nắm chắc tư duy này, bạn đã sẵn sàng cho Bài 48 về Terraform thực chiến trên AWS.