Infrastructure as Code, Terraform Là Gì, và Làm Quen CLI

K
Kai··10 min read

Hạ tầng đám mây ban đầu bao giờ cũng dễ. Bạn mở console AWS, bấm vài nút, một con EC2 chạy lên, một bucket S3 được tạo, một security group mở cổng 443. Mọi thứ ổn cho tới khi cần làm lại lần thứ hai: dựng đúng cấu hình đó ở môi trường staging, hoặc khôi phục sau khi ai đó xóa nhầm, hoặc giải thích cho đồng nghiệp vì sao security group lại mở đúng những cổng kia. Lúc đó bạn nhận ra mình không có bản ghi nào về những gì đã bấm, ngoài trí nhớ.

Series này dạy Terraform theo lối thực chiến: mỗi khái niệm đều gắn với một lần terraform apply thật trên AWS, ta soi state thật và dọn sạch sau đó. Bài đầu tiên không gõ lệnh tạo hạ tầng nào cả. Ta cần hiểu trước cái công cụ này thực ra là gì, nó giải bài toán nào, và bên trong nó vận hành ra sao, để những bài sau gõ lệnh mà biết mình đang làm gì.

Vấn đề: hạ tầng dựng bằng tay không lặp lại được

Cấu hình hạ tầng bằng cách bấm console (hay gõ aws ec2 run-instances rời rạc) gặp ba vấn đề lớn dần theo thời gian.

Thứ nhất là không tái lập được. Cái bạn dựng tháng trước tồn tại, nhưng cách bạn dựng nó thì không được ghi lại ở đâu. Muốn có một bản y hệt cho môi trường test, bạn phải nhớ lại từng bước, và trí nhớ thì sai.

Thứ hai là trôi dạt cấu hình (drift). Ai đó sửa tay một tham số lúc xử lý sự cố lúc 2 giờ sáng, rồi quên. Vài tuần sau không ai biết hệ thống thực tế khác gì so với ý định ban đầu, vì không có "ý định ban đầu" nào được viết ra để mà so.

Thứ ba là không review được. Một thay đổi hạ tầng nguy hiểm (mở cổng 22 ra toàn Internet, xóa một subnet) trông y hệt một cú click chuột vô hại. Không có diff, không có pull request, không có dấu vết để ai đó duyệt trước khi nó xảy ra.

Infrastructure as Code (IaC) giải cả ba bằng một ý tưởng đơn giản: mô tả hạ tầng bạn muốn bằng các file cấu hình, lưu chúng trong git, và để một công cụ biến file đó thành hạ tầng thật. File trở thành nguồn sự thật. Tái lập là chạy lại. Drift trở thành thứ phát hiện được, vì có cái để so. Review trở thành đọc diff như review code bình thường.

Terraform là gì

Theo tài liệu HashiCorp, Terraform là "một công cụ infrastructure as code cho phép bạn định nghĩa tài nguyên cloud và on-prem trong các file cấu hình con người đọc được, có thể version, tái sử dụng và chia sẻ". Bạn viết ra trạng thái mong muốn của hạ tầng, Terraform lo phần biến hiện trạng thành trạng thái đó.

Điểm cốt lõi cần nắm ngay từ đầu: Terraform khai báo (declarative). Bạn không viết "tạo một EC2, rồi gắn security group, rồi tạo elastic IP". Bạn viết "tôi muốn có một EC2 thế này, một security group thế kia, một elastic IP gắn vào đó". Terraform tự tính ra cần làm gì, theo thứ tự nào, để hiện trạng khớp với mô tả. Lần đầu chạy, nó tạo mới tất cả. Lần sau, nếu bạn đổi một dòng, nó chỉ sửa đúng cái thay đổi chứ không dựng lại từ đầu.

Ba khái niệm sẽ theo bạn suốt series:

Provider là plugin giúp Terraform nói chuyện với một nền tảng cụ thể. hashicorp/aws biết cách gọi API của AWS; có provider cho Google Cloud, Azure, Cloudflare, GitHub, Kubernetes, và hàng nghìn dịch vụ khác trên Terraform Registry. Terraform core bản thân nó không biết gì về AWS — toàn bộ hiểu biết "EC2 có những tham số nào, gọi API nào để tạo" nằm trong provider.

Resource là một mẩu hạ tầng bạn khai báo: một aws_instance, một aws_s3_bucket, một aws_security_group. Đây là đơn vị Terraform quản lý.

State là file Terraform dùng để nhớ "thực tế đang có gì". Tài liệu mô tả nó là "nguồn sự thật cho môi trường của bạn" — Terraform đối chiếu file cấu hình với state để biết cần thay đổi gì. Đây là phần dễ gây nhầm và sẽ có hẳn vài bài riêng (Part II).

Vòng đời: write, plan, apply

HashiCorp gói quy trình Terraform thành ba bước.

Write — bạn định nghĩa resource trong file .tf, có thể trải trên nhiều provider.

Plan — Terraform tạo một execution plan, mô tả nó sẽ tạo, sửa hay xóa cái gì, dựa trên hiện trạng và cấu hình của bạn. Đây là bước xem trước: chưa có gì thay đổi thật, bạn đọc kế hoạch và quyết định.

Apply — sau khi bạn duyệt, Terraform thực hiện các thao tác đó "theo đúng thứ tự, tôn trọng mọi quan hệ phụ thuộc giữa resource". Câu này quan trọng: bạn không nói thứ tự, Terraform tự suy ra (bài 5 sẽ mổ kỹ đồ thị phụ thuộc này).

Cộng thêm destroy để dỡ bỏ những gì đã tạo, đó là vòng đời cơ bản. Cả series xoay quanh việc làm chủ bốn động từ này cho những tình huống mỗi lúc một phức tạp.

Bên trong: core nói chuyện với provider ra sao

Đây là phần ít người mới để ý nhưng nó giải thích gần như mọi hành vi của Terraform về sau. Terraform không phải một khối liền. Nó gồm hai phần tách rời chạy như hai tiến trình riêng:

                terraform plan / apply
                         │
          ┌──────────────▼───────────────┐
          │       Terraform Core          │  đọc *.tf  +  terraform.tfstate
          │  - dựng đồ thị phụ thuộc      │  so cấu hình ⟷ state ⟷ thực tế
          │  - tính diff (kế hoạch)       │  quyết định tạo/sửa/xóa cái gì
          └──────────────┬───────────────┘
                         │  gRPC (go-plugin, chạy local)
          ┌──────────────▼───────────────┐
          │     Provider plugin           │  vd hashicorp/aws 6.46.0
          │  - biết schema từng resource  │  tải về .terraform/ khi init
          │  - dịch sang lời gọi API      │
          └──────────────┬───────────────┘
                         │  HTTPS (AWS SDK, có ký SigV4)
          ┌──────────────▼───────────────┐
          │          AWS API              │  EC2, S3, IAM, ...
          └───────────────────────────────┘

   terraform.tfstate  ◄─ Core ghi lại id thật + thuộc tính của mọi resource

Terraform core là cái binary bạn cài. Nó đọc file .tf, dựng đồ thị các resource và quan hệ giữa chúng, đối chiếu với state, rồi tính ra kế hoạch. Core không chứa một dòng nào hiểu biết về AWS.

Provider là binary riêng, tải về lúc terraform init và nằm trong thư mục .terraform/. Nó khai báo schema (resource aws_instance có những trường nào, kiểu gì, trường nào bắt buộc) và biết cách dịch "tạo resource này" thành lời gọi API thật. Core khởi chạy provider như một tiến trình con và giao tiếp qua gRPC trên localhost — đây là cơ chế go-plugin của HashiCorp. Khi core cần "tạo một EC2", nó gửi yêu cầu qua gRPC cho provider AWS; provider dịch thành lời gọi RunInstances của AWS SDK, ký SigV4 bằng credential bạn cấu hình, nhận về instance id, rồi trả id đó ngược lên core.

Core ghi id thật cùng toàn bộ thuộc tính vào terraform.tfstate. Lần chạy sau, core đọc state để biết "resource này đã tồn tại, id là i-0abc...", gọi provider hỏi lại AWS xem nó còn đó và còn đúng cấu hình không, rồi mới tính diff. Tách core khỏi provider chính là lý do một công cụ duy nhất quản lý được cả AWS lẫn Cloudflare lẫn GitHub trong cùng một lần apply: core điều phối đồ thị, mỗi provider lo phần API của mình.

Một câu về giấy phép

Từ phiên bản 1.6 (tháng 8/2023), Terraform chuyển từ giấy phép MPL 2.0 sang Business Source License 1.1 (BUSL). Với người dùng thông thường — cá nhân, công ty dùng Terraform để quản lý hạ tầng của chính mình — không có gì thay đổi: bạn vẫn dùng miễn phí. BUSL chỉ hạn chế việc đem chính Terraform ra làm sản phẩm cạnh tranh thương mại với HashiCorp. Việc này đã dẫn tới sự ra đời của OpenTofu, một bản fork giữ giấy phép mã nguồn mở; series này dùng Terraform chính thống, nhưng phần lớn kiến thức ở đây áp dụng được cho cả hai vì cú pháp HCL gần như tương đồng. Ta sẽ không quay lại chủ đề giấy phép nữa.

Cài đặt

Trên macOS, dùng Homebrew tap của HashiCorp:

brew tap hashicorp/tap
brew install hashicorp/tap/terraform

Trên Ubuntu/Debian, thêm apt repo chính thức:

wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform

Nếu bạn cần chạy nhiều phiên bản Terraform trên cùng một máy (dự án cũ pin bản cũ), tfenv là công cụ quản lý phiên bản đáng dùng. Còn cài một bản dùng chung thì hai cách trên là đủ.

Kiểm tra:

$ terraform version
Terraform v1.15.4
on darwin_arm64

Cả series này dùng Terraform 1.15.4 và AWS provider 6.46.0. Phiên bản quan trọng hơn bạn nghĩ: nhiều tính năng ta sẽ dùng (state lock bằng use_lockfile, ephemeral resources, các block import/moved/removed) chỉ có ở những bản gần đây, và mỗi bài sẽ ghi rõ tính năng nào cần bản nào.

Một vòng các lệnh CLI

terraform -help để xem toàn bộ. Phần đầu là các lệnh của workflow chính, đúng theo thứ tự bạn sẽ dùng hằng ngày:

$ terraform -help
Usage: terraform [global options] <subcommand> [args]
...
Main commands:
  init          Prepare your working directory for other commands
  validate      Check whether the configuration is valid
  plan          Show changes required by the current configuration
  apply         Create or update infrastructure
  destroy       Destroy previously-created infrastructure

Năm lệnh này là xương sống. init chuẩn bị thư mục làm việc — tải provider và module về. validate kiểm cú pháp và tính nhất quán mà không gọi API. plan xem trước thay đổi. apply thực thi. destroy dỡ bỏ.

Bên dưới là nhóm lệnh ít gặp hơn nhưng sẽ cần khi đi sâu:

All other commands:
  console       Try Terraform expressions at an interactive command prompt
  fmt           Reformat your configuration in the standard style
  graph         Generate a Graphviz graph of the steps in an operation
  import        Associate existing infrastructure with a Terraform resource
  output        Show output values from your root module
  providers     Show the providers required for this configuration
  show          Show the current state or a saved plan
  state         Advanced state management
  test          Execute integration tests for Terraform modules
  ...

fmt chuẩn hóa định dạng (sẽ chạy thường xuyên, nên đưa vào CI ở Part VII). console cho phép thử biểu thức HCL tương tác — rất tiện khi học hàm và biến ở Part III. state gom các thao tác state nâng cao, import đưa hạ tầng có sẵn vào quản lý, test chạy kiểm thử — mỗi cái có một bài riêng sau này. Giờ chỉ cần biết chúng tồn tại và đại khái làm gì.

Một mẹo nhỏ đáng làm ngay: bật autocomplete cho shell, gõ terraform rồi Tab sẽ gợi ý lệnh.

terraform -install-autocomplete

Lệnh này thêm cấu hình vào ~/.bashrc hoặc ~/.zshrc; mở shell mới để nó có hiệu lực.

Tổng kết

Terraform là công cụ biến mô tả hạ tầng dạng khai báo trong file .tf thành hạ tầng thật, qua vòng đời write → plan → apply. Bên dưới, core lo đồ thị và diff, provider lo dịch sang lời gọi API, còn state là cuốn sổ ghi lại thực tế đang có gì — ba mảnh này giải thích gần như mọi hành vi ta gặp về sau. Máy bạn giờ đã có Terraform 1.15 và bạn đã biết các lệnh chính dùng để làm gì.

Bài tới ta dừng nói lý thuyết và dựng resource thật đầu tiên trên AWS: khai báo provider, pin phiên bản, tạo một bucket S3, rồi đi trọn vòng init → plan → apply → destroy để thấy từng bước thực sự xảy ra chuyện gì.