Mở đầu — vì sao bài này quan trọng
Nếu bạn đã theo dõi khóa học đến đây, bạn đã học Terraform khá kỹ ở các bài trước — provider, resource, state, module, workspace và best practices. Nhưng có một câu hỏi mà gần như mọi DevOps Engineer đều gặp trong tuần đầu tiên đi làm: "Chúng ta đang dùng cả Terraform lẫn Ansible, vậy khi nào dùng cái nào?" — và câu hỏi này gây bối rối nhiều hơn bạn tưởng.
Lý do là vì trên bề mặt, cả hai công cụ trông rất giống nhau. Cả hai đều là "Infrastructure as Code", cả hai đều dùng file văn bản để mô tả hạ tầng, cả hai đều giúp bạn tự động hóa thay vì bấm chuột thủ công trên console. Nhiều bạn junior thấy hai công cụ "làm được việc giống nhau" nên chọn bừa một cái, dẫn đến những kiến trúc lộn xộn: dùng Terraform để cài phần mềm lên server (chậm, khó bảo trì), hoặc dùng Ansible để tạo VPC và subnet (mất khả năng theo dõi state, dễ tạo tài nguyên mồ côi).
Sự thật là Terraform và Ansible được sinh ra để giải quyết hai bài toán khác nhau về bản chất, và người kỹ sư giỏi biết dùng chúng bổ trợ cho nhau chứ không phải thay thế nhau. Hiểu rõ ranh giới này không chỉ giúp bạn viết code sạch hơn, mà còn giúp bạn trả lời trôi chảy trong buổi phỏng vấn — đây là một trong những câu hỏi kinh điển mà nhà tuyển dụng DevOps ở Việt Nam rất hay hỏi. Bài này sẽ giúp bạn nắm chắc lằn ranh đó.
Khái niệm cốt lõi
Bản chất khác nhau: Provisioning vs Configuration Management
Điểm mấu chốt để phân biệt hai công cụ nằm ở hai khái niệm: provisioning (cung cấp/tạo hạ tầng) và configuration management (quản lý cấu hình bên trong).
Hãy tưởng tượng bạn xây một tòa nhà. Provisioning giống như việc đổ móng, dựng khung bê tông, kéo đường điện nước tổng — tức là tạo ra bản thân cơ sở vật chất. Configuration management giống như việc sơn tường, lắp đèn, kê bàn ghế, cài đặt phần mềm cho từng phòng — tức là cấu hình bên trong những gì đã được dựng lên.
Terraform là bậc thầy của provisioning. Nó chuyên tạo ra các tài nguyên hạ tầng: máy ảo (EC2, Compute Engine), mạng (VPC, subnet, security group), cơ sở dữ liệu quản lý (RDS), load balancer, DNS record, cụm Kubernetes... Terraform nói chuyện trực tiếp với API của nhà cung cấp cloud để "sinh ra" những thứ chưa tồn tại.
Ansible là bậc thầy của configuration management. Nó chuyên vào bên trong một máy chủ đã tồn tại và làm cho nó đúng như bạn muốn: cài nginx, cấu hình file config, tạo user, copy chứng chỉ SSL, khởi động service, deploy code ứng dụng... Ansible giả định rằng máy đã có sẵn (do Terraform hoặc ai đó tạo ra) và tập trung vào việc "trang bị" cho máy đó.
Bảng so sánh cốt lõi
| Khía cạnh | Terraform | Ansible |
|---|---|---|
| Mục đích chính | Provision hạ tầng (tạo VM, mạng, DB, cloud resource) | Configuration management (cài phần mềm, cấu hình OS, deploy app) |
| Ngôn ngữ | HCL (khai báo) | YAML (khai báo nhưng có yếu tố thủ tục) |
| Mô hình | Declarative (mô tả trạng thái mong muốn) | Chủ yếu declarative, có phần procedural (chạy tuần tự từng task) |
| Quản lý State | Có state file — nhớ mọi tài nguyên đã tạo | Không có state — chạy lại kiểm tra thực tế mỗi lần |
| Cách hoạt động | Gọi API của cloud provider | SSH vào máy đích và thực thi (agentless) |
| Xóa tài nguyên | terraform destroy xóa sạch, chính xác | Không tự biết xóa gì — phải viết task xóa thủ công |
| Điểm mạnh nhất | Vòng đời hạ tầng cloud | Cấu hình bên trong server, orchestration app |
State — điểm khác biệt định mệnh
Đây là điểm quan trọng nhất và cũng hay bị bỏ qua. Terraform có state file — một bản ghi nhớ toàn bộ những gì nó đã tạo. Nhờ state, Terraform biết chính xác 3 EC2 nào là của nó, nếu bạn xóa 1 dòng code thì nó biết cần destroy đúng máy đó. Đây là lý do Terraform quản lý vòng đời hạ tầng cực tốt: tạo, sửa, xóa đều chính xác.
Ansible thì stateless. Nó không nhớ lịch sử. Mỗi lần chạy playbook, Ansible SSH vào máy, kiểm tra trạng thái hiện tại rồi điều chỉnh cho đúng mong muốn. Ưu điểm là đơn giản, không lo state bị hỏng. Nhược điểm là Ansible không có khái niệm "xóa những gì tôi đã tạo" — nếu bạn bỏ một task cài package ra khỏi playbook, package đó vẫn nằm nguyên trên server, Ansible không tự dọn.
Chính vì vậy, nếu bạn dùng Ansible để tạo 10 EC2 rồi sau đó bỏ đi 3 cái trong file, Ansible sẽ không xóa 3 cái đó — bạn sẽ có "tài nguyên mồ côi" âm thầm tính tiền. Đây là lý do lớn nhất để KHÔNG dùng Ansible cho provisioning cloud.
Idempotency — điểm chung của cả hai
Cả hai công cụ đều theo đuổi idempotency — chạy bao nhiêu lần cũng ra cùng một kết quả. Chạy terraform apply lần thứ hai mà không sửa gì thì Terraform báo "no changes". Chạy lại một Ansible playbook thì các task đã đúng sẽ hiện "ok" (không đổi) thay vì "changed". Đây là nguyên tắc vàng của IaC: bạn phải luôn có thể chạy lại một cách an toàn.
Tình huống thực tế
Ví dụ 1: Startup fintech ở TP.HCM chọn "team Terraform" cho cả provisioning lẫn config — và trả giá
Một startup fintech khoảng 40 người ở Quận 1, TP.HCM, xây hệ thống trên AWS. Bạn team lead ban đầu rất thích Terraform nên quyết định "một công cụ cho tất cả": dùng Terraform provider remote-exec và file provisioner để vừa tạo EC2, vừa SSH vào cài Docker, cấu hình nginx và deploy ứng dụng.
Ban đầu mọi thứ chạy được. Nhưng sau 6 tháng, khi hệ thống lên 25 EC2, vấn đề bùng nổ. Mỗi lần cần sửa một dòng cấu hình nginx, họ phải chạy terraform apply — và Terraform, do provisioner gắn chặt vào tài nguyên, thường muốn destroy rồi recreate cả EC2 chỉ để chạy lại script cấu hình. Có lần một kỹ sư sửa một biến môi trường nhỏ, terraform plan báo sẽ hủy 8 EC2 production. Cả team toát mồ hôi hủy lệnh giữa chừng.
Bài học: provisioner trong Terraform (như remote-exec) chính thức được HashiCorp khuyến cáo là "last resort" — chỉ dùng khi hết cách. Cấu hình bên trong máy nên tách ra cho Ansible. Sau khi refactor, team dùng Terraform chỉ để tạo EC2 và xuất IP ra, rồi Ansible lo phần cài đặt. Thời gian deploy một thay đổi cấu hình giảm từ ~15 phút (kèm rủi ro recreate) xuống còn ~90 giây, không đụng đến vòng đời máy.
Ví dụ 2: Công ty thương mại điện tử ở Hà Nội dùng đúng mô hình lai — Terraform tạo, Ansible cấu hình
Một công ty e-commerce tầm trung ở Hà Nội (khoảng 150 kỹ sư) chạy hạ tầng hybrid: một phần trên VNG Cloud, một phần trên AWS. Họ áp dụng mô hình chuẩn "Terraform provisions, Ansible configures".
Quy trình của họ như sau: Terraform tạo VPC, subnet, security group, và một nhóm gồm 6 VM cho tầng ứng dụng. Sau khi terraform apply xong, Terraform xuất danh sách IP của các VM ra một output. Họ có một script nhỏ dùng plugin dynamic inventory của Ansible (đọc trực tiếp từ cloud API hoặc từ Terraform state) để Ansible tự biết 6 IP đó. Ansible sau đó chạy playbook cài đặt: hardening OS, cài Docker, kéo image, cấu hình log rotation, và đăng ký node vào hệ thống monitoring.
Điểm hay là ranh giới cực rõ ràng: Terraform sở hữu hạ tầng, Ansible sở hữu nội dung bên trong. Khi cần scale từ 6 lên 10 VM, họ sửa biến count trong Terraform, apply, rồi chạy lại Ansible playbook — vốn idempotent nên 6 máy cũ không bị đụng, chỉ 4 máy mới được cấu hình. Khi cần thu hẹp, terraform destroy phần thừa xóa chính xác nhờ state.
Bài học: Đây là mô hình "vàng" trong ngành. Terraform lo tạo và xóa (nơi state phát huy sức mạnh), Ansible lo cấu hình lặp lại (nơi agentless và idempotency phát huy). Hai công cụ không giẫm chân nhau.
Ví dụ 3: Team on-premise của một ngân hàng — nơi Ansible tỏa sáng gần như một mình
Một ngân hàng ở Việt Nam vận hành phần lớn hệ thống core banking trên máy chủ vật lý trong data center riêng (on-premise), không phải cloud. Ở đây gần như không có "provisioning theo kiểu cloud API" — các server vật lý đã được đội hạ tầng lắp đặt sẵn từ trước.
Trong bối cảnh này, Terraform gần như không có đất diễn (không có cloud API để gọi, dù có provider cho vSphere/VMware nhưng họ chưa dùng). Ngược lại, Ansible là ngôi sao: họ quản lý hàng trăm server bằng playbook — vá lỗ hổng bảo mật đồng loạt, cấu hình chuẩn tuân thủ (compliance), triển khai patch định kỳ, và roll-out cập nhật ứng dụng theo từng đợt (rolling update qua serial). Vì Ansible agentless (chỉ cần SSH, không cài agent lên từng máy), đội bảo mật ngân hàng rất thích — không có phần mềm lạ chạy thường trú trên server core.
Bài học: Khi hạ tầng đã tồn tại sẵn (on-premise, bare metal) và bài toán chính là quản lý cấu hình + orchestration ở quy mô lớn, Ansible mạnh hơn hẳn và có thể đứng một mình. Terraform tỏa sáng khi bạn cần dựng hạ tầng từ con số 0 trên cloud.
Hướng dẫn từng bước
Đây là quy trình thực tế để phối hợp hai công cụ theo mô hình lai chuẩn:
Bước 1 — Xác định ranh giới trách nhiệm. Trước khi viết bất kỳ dòng code nào, vẽ ra một đường: mọi thứ "cấp phát tài nguyên cloud" thuộc Terraform; mọi thứ "diễn ra bên trong OS" thuộc Ansible. Ghi ranh giới này vào README để cả team tuân theo.
Bước 2 — Dùng Terraform tạo hạ tầng. Viết code Terraform tạo mạng, security group và các VM. Quan trọng: đảm bảo security group mở cổng SSH (port 22) từ nơi Ansible sẽ chạy, và gắn đúng SSH key vào VM để Ansible đăng nhập được.
Bước 3 — Xuất thông tin kết nối qua output. Cho Terraform xuất ra IP (public hoặc private) của các VM vừa tạo. Ví dụ một output tên app_server_ips trả về danh sách IP. Đây là cầu nối giữa hai công cụ.
Bước 4 — Nối inventory cho Ansible. Có ba cách phổ biến: (a) dùng dynamic inventory plugin để Ansible đọc trực tiếp từ cloud (theo tag của VM), (b) dùng plugin đọc từ Terraform state, hoặc (c) đơn giản nhất cho người mới: dùng terraform output -json để lấy IP rồi sinh ra file inventory. Cách (a) là chuyên nghiệp nhất vì luôn đồng bộ với thực tế.
Bước 5 — Viết Ansible playbook idempotent. Playbook cài đặt phần mềm, cấu hình service, deploy code. Luôn dùng các module chuẩn (như apt, copy, template, service) thay vì command/shell bừa bãi, vì các module chuẩn đảm bảo idempotency — chạy lại không gây tác dụng phụ.
Bước 6 — Chạy theo đúng thứ tự và tự động hóa. Trong pipeline CI/CD: terraform apply chạy trước, thành công thì mới trigger ansible-playbook. Đừng bao giờ đảo ngược thứ tự — Ansible không thể cấu hình một máy chưa tồn tại.
Bước 7 — Tách vòng đời. Khi cần thay đổi cấu hình phần mềm, chỉ chạy lại Ansible, đừng động vào Terraform. Khi cần thêm/bớt máy, chạy Terraform rồi chạy lại Ansible. Việc tách bạch này giúp bạn tránh được thảm họa "recreate cả server chỉ để sửa config" như ví dụ 1.
Lỗi thường gặp & mẹo
Lỗi 1: Dùng Terraform provisioner để cấu hình máy. Đây là cái bẫy phổ biến nhất với người mới. remote-exec và local-exec trông tiện, nhưng HashiCorp chính thức khuyến cáo dùng chúng như "phương án cuối cùng". Chúng phá vỡ mô hình declarative của Terraform và khiến việc sửa config có thể trigger recreate cả tài nguyên. Mẹo: nếu bạn thấy mình viết script bash bên trong provisioner, hãy dừng lại và chuyển sang Ansible.
Lỗi 2: Dùng Ansible để tạo cloud resource lâu dài. Ansible CÓ module tạo EC2, VPC... nhưng vì không có state, nó không quản lý được vòng đời. Bạn sẽ dễ tạo tài nguyên mồ côi tính tiền âm thầm. Chỉ dùng khả năng này cho tác vụ tạm thời hoặc orchestration nhẹ, đừng dùng thay Terraform.
Lỗi 3: Lạm dụng module command/shell trong Ansible. Chúng phá idempotency vì Ansible không biết trạng thái trước/sau. Kết quả là mỗi lần chạy đều báo "changed" dù không thay đổi gì thực sự. Mẹo: luôn tìm module chuyên dụng trước; nếu buộc phải dùng shell, thêm điều kiện creates, removes hoặc changed_when để mô phỏng idempotency.
Lỗi 4: Để inventory tĩnh (hardcode IP). Khi Terraform tạo máy mới, IP thay đổi mà bạn quên cập nhật file inventory. Mẹo: dùng dynamic inventory để Ansible luôn nhìn thấy đúng máy đang tồn tại.
Mẹo tư duy nhanh khi phỏng vấn: Nếu câu hỏi là "tạo ra thứ chưa tồn tại trên cloud" → Terraform. Nếu câu hỏi là "làm gì đó bên trong máy đã tồn tại" → Ansible. Nếu là "cả hai" → mô hình lai, Terraform trước, Ansible sau. Một câu trả lời gọn: "Terraform provisions the infrastructure, Ansible configures what runs inside it."
Mẹo về Pulumi/CDK: Có bạn sẽ hỏi về các công cụ khác. Pulumi, AWS CDK cũng thuộc nhóm provisioning giống Terraform (cùng lằn ranh, khác cú pháp). Chef, Puppet, SaltStack thuộc nhóm configuration management giống Ansible. Nắm được hai "nhóm" này thì bạn phân loại được mọi công cụ mới.
Bài tập thực hành
Bài tập 1 — Phân loại (làm ngay trên giấy). Với mỗi tác vụ dưới đây, ghi rõ nên dùng Terraform hay Ansible và giải thích một câu:
- Tạo một cụm database RDS trên AWS.
- Cài đặt và cấu hình PostgreSQL trên một VM Ubuntu đã có sẵn.
- Tạo VPC và 3 subnet.
- Vá lỗ hổng bảo mật đồng loạt trên 50 server on-premise.
- Cấp phát một load balancer và gắn nó vào 4 web server.
- Deploy phiên bản mới của ứng dụng lên các web server đang chạy.
output, (c) viết một Ansible playbook idempotent cài nginx và deploy một trang HTML "Hello DevOps". Chạy playbook 2 lần và quan sát lần thứ hai báo "ok" thay vì "changed" — đó là idempotency đang hoạt động.Bài tập 3 — Trải nghiệm cái sai để nhớ. Cố tình dùng Terraform remote-exec provisioner để cài nginx thay vì Ansible. Sau đó sửa một biến trong resource VM và chạy terraform plan. Quan sát xem Terraform có định recreate VM không. Viết một đoạn ngắn (5 câu) giải thích vì sao cách này nguy hiểm trong môi trường production.
Tóm tắt
Terraform và Ansible không phải đối thủ — chúng là đồng đội giải quyết hai bài toán khác nhau. Điểm cốt lõi cần khắc sâu:
- Terraform = provisioning. Chuyên tạo, sửa, xóa hạ tầng cloud (VM, mạng, DB, load balancer). Sức mạnh nằm ở state — nó nhớ mọi thứ đã tạo nên quản lý vòng đời cực chính xác.
- Ansible = configuration management. Chuyên cấu hình bên trong máy đã tồn tại (cài phần mềm, deploy app, hardening). Sức mạnh nằm ở agentless + idempotency, hoạt động tuyệt vời cả trên cloud lẫn on-premise.
- State là điểm khác biệt định mệnh: Terraform có state nên biết xóa chính xác; Ansible stateless nên không tự dọn tài nguyên nó tạo. Vì vậy đừng dùng Ansible để provisioning cloud lâu dài.
- Mô hình vàng là lai ghép: Terraform tạo hạ tầng và xuất IP → Ansible dùng dynamic inventory để cấu hình. Chạy Terraform trước, Ansible sau. Tách bạch vòng đời để tránh thảm họa recreate.
- Tránh các bẫy: đừng lạm dụng Terraform
provisioner, đừng dùngcommand/shellbừa bãi trong Ansible, đừng hardcode inventory.