Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng một buổi sáng thứ Hai, sếp gọi bạn vào và nói: "Đối tác vừa ký hợp đồng, cuối tuần này chúng ta phải dựng một hệ thống staging y hệt production để họ test." Ở nhiều công ty, câu trả lời sẽ là một tuần vật lộn: một bạn ngồi click AWS Console tạo EC2, một bạn khác vào Google Cloud dựng database, người thứ ba cấu hình firewall bằng tay theo trí nhớ. Ba ngày sau hệ thống chạy được, nhưng nó không hoàn toàn giống production — thiếu một rule bảo mật ở đâu đó, sai version của một service ở đâu đó. Và không ai biết chính xác sai ở chỗ nào, vì tất cả nằm trong đầu người đã dựng.
Đây chính là bài toán mà Infrastructure as Code (IaC) — Hạ tầng dưới dạng Mã — sinh ra để giải quyết. Trong các bài trước, chúng ta đã nói về văn hóa DevOps, về toolchain, về container. Bài này là bản lề: chúng ta chuyển từ triết lý sang một trong những trụ cột kỹ thuật quan trọng nhất của DevOps hiện đại. Nếu bạn muốn tự động hóa (Automation) như CALMS framework nhắc tới, bạn bắt buộc phải mô tả được hạ tầng bằng thứ máy đọc được — tức là bằng code.
Đây là bài mang tính khái niệm và tư duy. Chúng ta chưa viết Terraform hay Ansible cụ thể (những bài 11–14 sẽ lo phần đó). Mục tiêu của bài 10 là để bạn hiểu IaC là gì, tại sao nó thay đổi cuộc chơi, và tư duy đằng sau nó — nền tảng để mọi công cụ sau này không còn là "gõ lệnh cho có" mà là công cụ giải quyết một vấn đề bạn đã thấu hiểu.
Khái niệm cốt lõi
Định nghĩa
Infrastructure as Code là cách mô tả toàn bộ hạ tầng — server, mạng, database, cân bằng tải, quyền IAM, DNS — bằng các tệp code (thường là text) thay vì thao tác click chuột trên giao diện quản trị (UI). Code đó được đưa vào version control (Git), được review, được chạy qua CI/CD, giống hệt như code ứng dụng bình thường.
Điểm mấu chốt nằm ở chỗ: hạ tầng của bạn giờ đây có một nguồn sự thật duy nhất (single source of truth) — chính là các tệp code đó. Muốn biết production có bao nhiêu server, mạng cấu hình ra sao, ai có quyền gì? Bạn không hỏi "anh nào biết", bạn đọc code.
Cách tiếp cận cũ: "ClickOps" và Snowflake Server
Cách làm truyền thống hay được gọi vui là ClickOps — vận hành bằng cách click. Bạn đăng nhập vào console, bấm nút tạo tài nguyên, điền form. Nhanh và trực quan lúc đầu, nhưng nó đẻ ra hai vấn đề kinh điển:
- Snowflake server (server bông tuyết): mỗi server dựng bằng tay lại hơi khác nhau một chút, giống như không có hai bông tuyết nào giống hệt. Sau vài tháng, không ai dám đụng vào một server đang chạy tốt vì sợ "nó đang sống nhờ phép màu, đừng phá".
- Configuration drift (trôi cấu hình): trạng thái thực tế của hệ thống dần dần lệch khỏi những gì được ghi chép, vì mỗi lần "sửa gấp lúc 2 giờ sáng" lại không được cập nhật vào tài liệu.
Bốn đặc tính làm nên sức mạnh của IaC
1. Declarative (khai báo) vs Imperative (mệnh lệnh). Đa số công cụ IaC hiện đại theo hướng declarative: bạn mô tả trạng thái mong muốn ("tôi muốn có 3 server, 1 database PostgreSQL 15, 1 load balancer"), và công cụ tự tính toán cần làm gì để đạt được trạng thái đó. Ngược lại với imperative là bạn phải viết từng bước ("tạo server, rồi cài đặt, rồi cấu hình..."). Declarative giúp bạn tập trung vào cái gì thay vì làm thế nào.
2. Idempotency (bất biến khi lặp). Chạy cùng một đoạn code IaC mười lần cho ra cùng một kết quả như chạy một lần. Nếu tài nguyên đã tồn tại đúng như mô tả, công cụ sẽ không tạo trùng — nó chỉ đảm bảo trạng thái khớp. Đây là tính chất cực kỳ quan trọng: nó cho phép bạn chạy lại bất cứ lúc nào mà không sợ làm hỏng.
3. Versioned (có phiên bản). Vì hạ tầng là code trong Git, mọi thay đổi đều có lịch sử. Ai đổi rule firewall lúc 3 giờ chiều thứ Sáu? git log trả lời. Sai rồi, muốn quay lại trạng thái tuần trước? git revert rồi apply lại.
4. Reproducible (tái lập được). Cùng một bộ code cho ra cùng một hạ tầng, dù ở môi trường dev, staging hay production, dù chạy hôm nay hay sáu tháng sau.
IaC khác gì Configuration Management?
Nhiều bạn mới hay nhầm. Có thể tạm chia:
- Provisioning (cấp phát hạ tầng): tạo ra bản thân tài nguyên — máy ảo, mạng, database. Đây là địa hạt của Terraform, Pulumi, CloudFormation.
- Configuration management (quản lý cấu hình): cài đặt phần mềm, cấu hình bên trong server đã có — cài Nginx, chỉnh file config. Đây là địa hạt của Ansible, Chef, Puppet.
State — khái niệm sẽ theo bạn suốt hành trình
Công cụ IaC declarative cần biết "hiện tại tôi đang quản những tài nguyên nào" để tính ra sự khác biệt giữa hiện tại và mong muốn. Thông tin đó gọi là state (trạng thái). Bạn chưa cần hiểu sâu ngay bây giờ — bài 11 sẽ mổ xẻ Terraform state — nhưng hãy ghi nhớ rằng "code mô tả mong muốn, state ghi lại thực tế, công cụ so sánh hai thứ đó" là mô hình tư duy trung tâm của IaC.
Tình huống thực tế
Ví dụ 1: Startup fintech ở TP.HCM và cơn ác mộng "server duy nhất biết cách dựng"
Một startup fintech tại Quận 1, TP.HCM (khoảng 25 kỹ sư) khi mới khởi nghiệp dựng toàn bộ hạ tầng AWS bằng tay. Mọi thứ chạy ổn cho tới khi anh DevOps kỳ cựu — người duy nhất "thuộc lòng" cấu hình — nghỉ việc chuyển sang công ty khác. Ba tuần sau, một service thanh toán gặp sự cố lúc cao điểm, và đội còn lại phát hiện họ không biết production được cấu hình chính xác thế nào: security group nào mở port nào, database có bao nhiêu read replica, cron job backup chạy ở đâu.
Họ mất gần một tháng "khảo cổ học hạ tầng" — dò từng dịch vụ trong console để tái dựng lại bản đồ. Sau cú đau đó, ban lãnh đạo quyết định chuyển toàn bộ sang Terraform. Kết quả sau sáu tháng: thời gian dựng một môi trường mới giảm từ khoảng 3 ngày xuống còn dưới 30 phút, và quan trọng hơn — kiến thức về hạ tầng nằm trong Git repo, không nằm trong đầu một người.
Bài học: IaC không chỉ là tự động hóa, nó là chống rủi ro tri thức (bus factor). Khi hạ tầng là code, không một cá nhân nào trở thành điểm nghẽn hay điểm chết của cả hệ thống.
Ví dụ 2: Sàn thương mại điện tử và mùa sale 12/12
Một công ty thương mại điện tử tầm trung ở Đông Nam Á cần nhân đôi số lượng máy chủ trước mỗi đợt sale lớn (11/11, 12/12), rồi thu nhỏ lại sau đó để tiết kiệm chi phí. Trước đây, việc này làm bằng tay và tốn cả một ê-kíp trực xuyên đêm. Có năm họ quên gỡ 40 máy ảo sau đợt sale, "đốt" thêm khoảng 6.000 USD tiền cloud trong một tháng chỉ vì các máy nhàn rỗi mà không ai nhớ tắt.
Sau khi áp dụng IaC, toàn bộ việc scale up/down chỉ là thay đổi một con số trong file cấu hình (instance_count = 20 thành instance_count = 40), tạo một Pull Request, được review, merge và pipeline tự động áp dụng. Sau sale, đổi lại con số, merge — hệ thống tự dọn dẹp sạch sẽ. Không còn máy "mồ côi", không còn hóa đơn bất ngờ.
Bài học: Khi hạ tầng là code đi qua quy trình review, những thay đổi lớn trở nên an toàn, có kiểm soát và có thể hoàn tác. Chi phí và rủi ro con người giảm mạnh.
Ví dụ 3: Ngân hàng số và yêu cầu audit tuân thủ
Một ngân hàng số (giả định, nhưng phản ánh thực tế ngành tài chính VN) phải vượt qua các đợt audit tuân thủ định kỳ. Kiểm toán viên hỏi: "Chứng minh cho tôi thấy ai đã thay đổi quyền truy cập database production trong 6 tháng qua, và thay đổi đó có được phê duyệt không?" Với ClickOps, câu trả lời gần như bất khả thi — log của cloud provider rời rạc và khó truy vết ý định.
Với IaC, mọi thay đổi quyền IAM đều là một commit trong Git, gắn với một Pull Request có người review và approve. Toàn bộ lịch sử "ai, khi nào, thay gì, ai duyệt" nằm gọn trong Git history. Đợt audit trở thành việc xuất git log và danh sách PR đã merge.
Bài học: IaC biến hạ tầng thành đối tượng có thể kiểm toán (auditable) một cách tự nhiên — một lợi thế khổng lồ cho các ngành chịu quản lý chặt như tài chính, y tế, bảo hiểm.
Hướng dẫn từng bước
Đây là lộ trình tư duy để một tổ chức (hoặc chính bạn) bắt đầu áp dụng IaC. Chưa phải hướng dẫn cú pháp — mà là quy trình.
- Kiểm kê hạ tầng hiện tại. Liệt kê ra tất cả những gì đang chạy: bao nhiêu server, database gì, mạng thế nào, ai có quyền gì. Đây là bước "vẽ bản đồ" thường bị bỏ qua nhưng cực kỳ quan trọng.
- Chọn công cụ phù hợp. Nếu bạn cấp phát tài nguyên cloud (máy ảo, mạng), thiên về Terraform/Pulumi. Nếu cấu hình bên trong server, thiên về Ansible. Đa số tổ chức dùng kết hợp.
- Bắt đầu nhỏ và không xâm lấn. Đừng cố "code hóa" toàn bộ production ngay ngày đầu. Hãy chọn một môi trường ít rủi ro — thường là dev hoặc một dự án mới — để làm quen. Nguyên tắc vàng: môi trường mới thì làm IaC từ đầu; môi trường cũ thì import dần.
- Đưa code vào Git. Tạo repo riêng cho hạ tầng. Đây là lúc IaC bắt đầu phát huy sức mạnh: version control, review, lịch sử.
- Thiết lập vòng review. Áp dụng Pull Request cho mọi thay đổi hạ tầng. Không ai push thẳng lên nhánh chính. Mỗi thay đổi phải có người thứ hai nhìn qua.
- Tích hợp CI/CD. Cho pipeline tự động chạy "kế hoạch" (plan) khi có PR để xem trước những gì sẽ thay đổi, và tự động "áp dụng" (apply) sau khi merge. Đây là lúc hạ tầng thực sự chảy qua toolchain DevOps.
- Lặp lại và mở rộng. Từ một môi trường thành công, nhân rộng mô hình ra staging, production, rồi các dự án khác.
Lỗi thường gặp & mẹo
Lỗi: Vẫn "sửa tay" trên console sau khi đã có IaC. Đây là lỗi phổ biến và nguy hiểm nhất. Bạn có Terraform, nhưng lúc gấp lại vào console click sửa "cho nhanh". Kết quả: drift — code và thực tế lệch nhau, lần apply sau công cụ sẽ "sửa lại" và có thể xóa mất thay đổi tay của bạn. Mẹo: coi console như chỉ để đọc (read-only); mọi thay đổi phải đi qua code.
Lỗi: Commit secret (mật khẩu, API key) vào Git. Vì hạ tầng thường cần thông tin nhạy cảm, người mới hay lỡ tay đưa thẳng mật khẩu database vào file code rồi push lên Git — nơi nó tồn tại mãi mãi trong lịch sử. Mẹo: dùng biến môi trường, secret manager, và luôn có .gitignore chuẩn. Bài 40 sẽ đào sâu về secret management.
Lỗi: Viết code hạ tầng không ai review được. Một file 2000 dòng lộn xộn thì dù là code cũng vô dụng như ClickOps. Mẹo: chia nhỏ theo module, đặt tên rõ ràng, viết như bạn viết code ứng dụng chất lượng cao.
Lỗi: Bỏ qua state hoặc để nhiều người cùng chạy apply. Nếu hai người cùng apply một lúc, state có thể hỏng. Mẹo: dùng remote state có khóa (locking) — chi tiết ở bài 11.
Mẹo tổng quát: Áp dụng nguyên tắc immutable infrastructure khi có thể — thay vì sửa server đang chạy, hãy dựng server mới từ code và thay thế server cũ. Điều này loại bỏ tận gốc vấn đề snowflake server.
Bài tập thực hành
- Khảo sát ClickOps quanh bạn. Nếu bạn (hoặc công ty bạn) đang có bất kỳ tài nguyên cloud nào dựng bằng tay, hãy viết ra một danh sách: có bao nhiêu tài nguyên, ai dựng, có tài liệu không. Ước lượng sẽ mất bao lâu để dựng lại từ đầu nếu tất cả biến mất. Con số này chính là "nợ hạ tầng" của bạn.
- Phân loại declarative vs imperative. Viết ra 3 câu mô tả hạ tầng theo kiểu khai báo (ví dụ: "Tôi muốn có 3 web server chạy Ubuntu 22.04") và 3 câu tương đương theo kiểu mệnh lệnh (ví dụ: "Tạo 1 server, cài Ubuntu, lặp lại 3 lần"). Cảm nhận sự khác biệt trong tư duy.
- Thiết kế quy trình review. Giả sử bạn là DevOps lead của startup fintech ở ví dụ 1. Hãy phác thảo một quy trình bằng lời (chưa cần code) cho việc thay đổi security group của production: từ lúc ai đó đề xuất đến lúc thay đổi được áp dụng. Phải qua những bước nào, ai duyệt?
- Tình huống drift. Mô tả một kịch bản trong đó configuration drift gây ra sự cố production, và giải thích IaC lẽ ra đã ngăn được nó thế nào. Đây là bài tập tư duy giúp bạn "thấm" giá trị của idempotency và single source of truth.
Tóm tắt
- Infrastructure as Code (IaC) là việc mô tả hạ tầng bằng code thay vì click UI, để hạ tầng đi qua version control, review và CI/CD như mọi code khác.
- IaC giải quyết những căn bệnh kinh điển của ClickOps: snowflake server, configuration drift, và rủi ro tri thức nằm trong đầu một người.
- Bốn đặc tính cốt lõi: declarative (mô tả trạng thái mong muốn), idempotent (chạy lại nhiều lần vẫn an toàn), versioned (có lịch sử Git), reproducible (tái lập được).
- Phân biệt provisioning (Terraform — tạo tài nguyên) và configuration management (Ansible — cấu hình bên trong); IaC bao trùm cả hai.
- Khái niệm state — nơi công cụ ghi lại thực tế để so với mong muốn — sẽ theo bạn suốt các bài Terraform tiếp theo.
- Ba tình huống thực tế cho thấy IaC mang lại: chống rủi ro tri thức, kiểm soát thay đổi an toàn và chi phí có thể dự đoán, và khả năng kiểm toán tự nhiên.
- Cạm bẫy lớn nhất là sửa tay sau khi đã có IaC — hãy coi console là read-only, mọi thay đổi đều qua code.