Terraform Configuration Syntax
<BLOCK TYPE> "<BLOCK LABEL>" "<BLOCK LABEL>" {
# Block body
<IDENTIFIER> = <EXPRESSION> # Argument
}
Terraform là một công cụ quản lý hạ tầng mã hóa (Infrastructure as Code - IaC) phổ biến và mạnh mẽ. Nó sử dụng ngôn ngữ cấu hình riêng gọi là HashiCorp Configuration Language (HCL) để xác định cấu hình của hạ tầng và các nguồn tài nguyên liên quan.
- Khối (Blocks): Trong tệp cấu hình Terraform, bạn sẽ thấy các khối (blocks) đại diện cho các loại nguồn tài nguyên hoặc mô-đun khác nhau. Mỗi khối có mục đích cụ thể và chứa các đối số và thuộc tính lồng nhau. Ví dụ:
resource "aws_instance" "example" {
ami = "ami-0c94855ba95c71c99"
instance_type = "t2.micro"
}
Trong ví dụ trên, khối resource
đại diện cho một nguồn tài nguyên EC2 trên AWS. Khối này có tên là "example"
và có hai thuộc tính là ami
và instance_type
.
- Đối số (Arguments): Đối số (arguments) được sử dụng để định nghĩa các thuộc tính của nguồn tài nguyên. Chúng là các cặp key-value xác định cấu hình của nguồn tài nguyên. Ví dụ:
resource "aws_instance" "example" {
ami = "ami-0c94855ba95c71c99"
instance_type = "t2.micro"
tags = { Name = "Example Instance"
Environment = "Production" }}
Trong ví dụ trên, đối số ami
và instance_type
xác định AMI ID và loại instance của nguồn tài nguyên EC2. Đối số tags
là một cặp key-value khác biệt với các thuộc tính khác, cho phép bạn thêm các thuộc tính không cố định.
- Biến (Variables): Biến (variables) được sử dụng để parametrize cấu hình và làm cho nó linh hoạt hơn. Chúng cho phép bạn tái sử dụng và tùy chỉnh các thiết lập hạ tầng trong các môi trường khác nhau. Ví dụ:
variable "region" {
description = "AWS region to deploy resources"
type = string
default = "us-west-2"}
resource "aws_instance" "example" {
ami = "ami-0c94855ba95c71c99"
instance_type = "t2.micro"
region = var.region}
Trong ví dụ trên, chúng ta định nghĩa biến region
để xác định khu vực AWS mà tài nguyên sẽ triển khai. Biến này có mô tả, kiểu dữ liệu và giá trị là "us-west-2"
- Biểu thức (Expressions): Terraform hỗ trợ nhiều loại biểu thức cho phép bạn thực hiện tính toán, xử lý chuỗi và tạo ra logic điều kiện phức tạp trong cấu hình của bạn. Ví dụ:
variable "instance_count" {
description = "Number of instances to create"
type = number default = 1}
resource "aws_instance" "example" {
ami = "ami-0c94855ba95c71c99"
instance_type = "t2.micro"
count = var.instance_count}
Trong ví dụ trên, chúng ta sử dụng biến instance_count
để xác định số lượng instances sẽ được tạo ra. Thay vì chỉ định một giá trị cố định, chúng ta sử dụng biểu thức var.instance_count
để đánh giá giá trị từ biến.
- Nhà cung cấp (Providers): Nhà cung cấp (providers) là các plugin cho phép Terraform tương tác với các nhà cung cấp Cloud hoặc nền tảng hạ tầng khác nhau. Chúng được chỉ định ở cấp đầu của tệp cấu hình và xác định nền tảng mục tiêu cho triển khai. Ví dụ:
provider "aws" {
region = "us-west-2"}
resource "aws_instance" "example" {
ami = "ami-0c94855ba95c71c99"
instance_type = "t2.micro"}
Trong ví dụ trên, chúng ta sử dụng nhà cung cấp AWS và xác định khu vực AWS là "us-west-2". Nhà cung cấp này sẽ tương tác với AWS để triển khai và quản lý các nguồn tài nguyên.
- Nguồn tài nguyên (Resources): Nguồn tài nguyên (resources) là các khối xây dựng cốt lõi của cấu hình Terraform. Chúng đại diện cho các thành phần hạ tầng như máy ảo, mạng, bộ nhớ, v.v. và xác định các thuộc tính và quan hệ của chúng. Ví dụ:
resource "aws_instance" "example" {
ami = "ami-0c94855ba95c71c99"
instance_type = "t2.micro"
tags = {
Name = "Example Instance"
Environment = "Production" }}
Trong ví dụ trên, chúng ta định nghĩa một nguồn tài nguyên EC2 trên AWS với AMI ID và loại instance cụ thể. Chúng ta cũng định nghĩa các thuộc tính khác như tags
, cho phép bạn gán các thẻ (tags)
- Mô-đun (Modules): Mô-đun (modules) trong Terraform cho phép tái sử dụng và chia sẻ các khối cấu hình thông qua việc đóng gói các nguồn tài nguyên liên quan vào một đơn vị độc lập. Điều này giúp tạo ra các trừu tượng hóa và khuyến khích sự tái sử dụng code. Ví dụ:
module "web_server" {
source = "./modules/web_server"
instance_count = 2
ami = "ami-0c94855ba95c71c99"
instance_type = "t2.micro"}
Trong ví dụ trên, chúng ta sử dụng một mô-đun có tên web_server
từ đường dẫn ./modules/web_server
. Chúng ta cung cấp các đối số như instance_count
, ami
, và instance_type
để tùy chỉnh triển khai của mô-đun.
- Nguồn dữ liệu (Data Sources): Nguồn dữ liệu (data sources) cho phép bạn nhập dữ liệu từ các nguồn bên ngoài vào cấu hình Terraform. Điều này có thể là thông tin về nguồn tài nguyên hiện có như địa chỉ mạng, ID của Sercurity Group hoặc AMI ID. Ví dụ:
data "aws_ami" "example" {
most_recent = true
owners = ["self"]
tags = {
Name = "Example AMI"
Environment = "Production" }}
resource "aws_instance" "example" {
ami = data.aws_ami.example.id
instance_type = "t2.micro"}
Trong ví dụ trên, chúng ta sử dụng nguồn dữ liệu aws_ami
để lấy thông tin về một AMI từ AWS. Chúng ta sử dụng thuộc tính id
của nguồn dữ liệu trong khối resource
để xác định AMI cho instance.
- Giá trị đầu ra (Output Values): Giá trị đầu ra (output values) cho phép bạn trích xuất và hiển thị thông tin từ cấu hình Terraform sau khi triển khai. Điều này có thể là các chi tiết kết nối hoặc thông tin quan trọng khác mà bạn muốn hiển thị. Ví dụ:
resource "aws_instance" "example" {
ami = "ami-0c94855ba95c71c99"
instance_type = "t2.micro"}
output "instance_ip" { value = aws_instance.example.private_ip}
Trong ví dụ trên, chúng ta định nghĩa giá trị đầu ra có tên instance_ip
để hiển thị địa chỉ IP riêng tư của instance EC2 sau khi triển khai.
Tổng quan, cú pháp cấu hình Terraform được thiết kế để dễ hiểu và linh hoạt
- Modules Registry: Modules Registry là một kho lưu trữ trực tuyến chứa các mô-đun Terraform sẵn có và được chia sẻ bởi cộng đồng người dùng. Người dùng có thể tìm kiếm, tải về và sử dụng các mô-đun từ Registry để tăng tính tái sử dụng và nhanh chóng triển khai các nguồn tài nguyên.
Dependency Lock File
Tệp khóa phụ thuộc thuộc về cấu hình tổng thể, chứ không phải từng mô-đun riêng lẻ trong cấu hình.
Tệp khóa được đặt tên là .terraform.lock.hcl và có sẵn trong thư mục con .terraform của thư mục làm việc của bạn.
Nó tự động được tạo ra khi chúng ta thực thi lệnh terraform init để ghi lại Provider , để terraform có thể chọn mặc định các lựa chọn tương tự khi bạn chạy terraform init trong tương lai.
File khóa có tên là
.terraform.lock.hcl
và nằm trong thư mục con.terraform
của thư mục làm việc của bạnGhi lại thông tin về các phiên bản nhà cung cấp đã được sử dụng, đảm bảo rằng Terraform luôn sử dụng các phiên bản chính xác đó trong các lần chạy sau.
Điều này giúp duy trì tính nhất quán trong môi trường của bạn và tránh các vấn đề tiềm ẩn do thay đổi phiên bản nhà cung cấp.
Khi bạn chia sẻ cấu hình Terraform với người khác hoặc di chuyển nó sang môi trường mới, file khóa phụ thuộc sẽ đảm bảo rằng Terraform sử dụng các phiên bản nhà cung cấp chính xác như nhau. Điều này giúp đảm bảo rằng cấu hình của bạn được triển khai chính xác và nhất quán trên mọi môi trường
Các thay đổi đột ngột trong phiên bản nhà cung cấp có thể dẫn đến các vấn đề tương thích hoặc hành vi không mong muốn. Lock file ngăn chặn Terraform tự động cập nhật các phiên bản nhà cung cấp, đảm bảo rằng cấu hình của bạn vẫn hoạt động ổn định với các phiên bản đã được kiểm tra và xác nhận.
Khi Terraform biết chính xác các phiên bản nhà cung cấp cần thiết, nó có thể tối ưu hóa quá trình tải xuống và cài đặt, tiết kiệm thời gian và tài nguyên.
Terraform State File
Terraform State File đóng vai trò quan trọng trong việc quản lý cơ sở hạ tầng Cloud bằng Terraform. Nó lưu trữ thông tin chi tiết về các tài nguyên cơ sở hạ tầng đã được tạo và cấu hình của chúng. Dưới đây là những chức năng chính của tệp tin trạng thái:
1. Lưu trữ trạng thái cơ sở hạ tầng:
Tệp tin trạng thái ghi lại thông tin về tất cả các tài nguyên cơ sở hạ tầng được tạo bởi Terraform, bao gồm loại tài nguyên, thuộc tính cấu hình, ID tài nguyên và mối quan hệ giữa các tài nguyên.
Nó đóng vai trò như một bản ghi chép toàn diện về trạng thái hiện tại của cơ sở hạ tầng của bạn trên cloud.
2. Theo dõi thay đổi:
Khi bạn thực hiện các thay đổi đối với cấu hình Terraform và chạy lệnh
terraform apply
, Terraform sẽ so sánh trạng thái mong muốn (từ cấu hình) với trạng thái hiện tại (từ tệp tin trạng thái).Dựa trên sự so sánh này, Terraform sẽ xác định các tài nguyên cần được tạo, sửa đổi hoặc xóa để đưa cơ sở hạ tầng của bạn vào trạng thái mong muốn.
3. Hỗ trợ cộng tác:
Nhiều người dùng có thể làm việc trên cùng một cấu hình Terraform và tệp tin trạng thái, cho phép cộng tác hiệu quả trong việc quản lý cơ sở hạ tầng.
Terraform sẽ tự động đồng bộ hóa tệp tin trạng thái để đảm bảo rằng tất cả mọi người đều có cùng một cái nhìn về trạng thái hiện tại của cơ sở hạ tầng.
4. Khôi phục cơ sở hạ tầng:
Trong trường hợp xảy ra sự cố hoặc xóa nhầm tài nguyên, bạn có thể sử dụng tệp tin trạng thái để khôi phục cơ sở hạ tầng về trạng thái trước đó.
Điều này giúp đảm bảo tính khả dụng và khả năng phục hồi của hệ thống cơ sở hạ tầng của bạn.
What Is the Current State and Desire State in Terraform?
Trong Terraform, trạng thái hiện tại và trạng thái mong muốn là hai khái niệm cơ bản để mô tả cấu hình cơ sở hạ tầng của bạn.
Trạng thái hiện tại (Current State): Là trạng thái thực tế của cơ sở hạ tầng đám mây của bạn tại một thời điểm cụ thể. Nó bao gồm tất cả các tài nguyên cơ sở hạ tầng đã được tạo và cấu hình của chúng.
Trạng thái mong muốn (Desired State): Là trạng thái mà bạn muốn cơ sở hạ tầng của bạn đạt được. Nó được xác định bởi cấu hình Terraform của bạn, mô tả các tài nguyên cần được tạo, sửa đổi hoặc xóa.
Mục đích chính của việc sử dụng các khái niệm trạng thái hiện tại và trạng thái mong muốn trong Terraform là để tự động hóa việc quản lý cơ sở hạ tầng Cloud. Terraform so sánh trạng thái hiện tại với trạng thái mong muốn và xác định các thay đổi cần thiết để đưa cơ sở hạ tầng vào trạng thái mong muốn.
Cách thức hoạt động:
Đọc cấu hình Terraform: Terraform bắt đầu bằng cách đọc cấu hình Terraform của bạn, mô tả trạng thái mong muốn của cơ sở hạ tầng.
Xác định trạng thái hiện tại: Terraform truy vấn nhà cung cấp đám mây để thu thập thông tin về trạng thái hiện tại của cơ sở hạ tầng.
So sánh trạng thái: Terraform so sánh trạng thái hiện tại với trạng thái mong muốn để xác định các thay đổi cần thiết.
Áp dụng thay đổi: Terraform tạo, sửa đổi hoặc xóa các tài nguyên cơ sở hạ tầng để đưa cơ sở hạ tầng vào trạng thái mong muốn.
Lợi ích:
Sử dụng trạng thái hiện tại và trạng thái mong muốn trong Terraform mang lại nhiều lợi ích cho việc quản lý cơ sở hạ tầng Cloud:
Tự động hóa: Terraform tự động hóa việc tạo, sửa đổi và xóa các tài nguyên cơ sở hạ tầng, giảm thiểu sự can thiệp thủ công và lỗi của con người.
Tính nhất quán: Terraform đảm bảo rằng cơ sở hạ tầng của bạn luôn ở trạng thái mong muốn, giảm thiểu sự sai lệch và bất nhất.
Khả năng theo dõi: Terraform ghi lại lịch sử thay đổi cơ sở hạ tầng, giúp bạn dễ dàng theo dõi các thay đổi đã được thực hiện và lý do của chúng.
Khả năng lặp lại: Bạn có thể dễ dàng tái tạo cơ sở hạ tầng của mình từ đầu bằng cách sử dụng cấu hình Terraform và tệp tin trạng thái.
Trong Terraform, bên cạnh các kiểu biến cơ bản như số, chuỗi, và boolean, bạn có thể sử dụng các kiểu biến phức tạp hơn để lưu trữ dữ liệu dạng cấu trúc. Hai ví dụ phổ biến là Map và List.
1. Map :
Map là một tập hợp các cặp khóa-giá trị.
Mỗi khóa xác định duy nhất một giá trị trong Map.
Khóa có thể là chuỗi, số, hoặc thậm chí là Map hoặc List khác (tùy thuộc vào phiên bản Terraform).
Giá trị có thể là bất kỳ kiểu dữ liệu Terraform hợp lệ nào (chuỗi, số, boolean, v.v.).
variable "server_ips" { type = map default = { "web_server" = "192.168.1.100" "db_server" = "192.168.1.200" } } variable "server_tags" { type = map(string) default = { Name = "Web Server" Environment = "Production" } }
2. List (Danh Sách):
List là một tập hợp các phần tử được sắp xếp theo thứ tự.
Các phần tử trong List có thể là bất kỳ kiểu dữ liệu Terraform hợp lệ nào, nhưng lý tưởng nhất là chúng nên cùng kiểu để đảm bảo tính nhất quán.
Bạn có thể truy cập các phần tử trong List bằng chỉ mục của chúng, bắt đầu từ 0.
variable "domains" { type = list default = ["example.com", "example.org", "example.net"] } variable "web_server_instances" { type = list(object({ ami = string instance_type = string })) default = [ { ami = "ami-0123456789abcdef0" instance_type = "t2.micro" }, { ami = "ami-fedcba0987654321z" instance_type = "t2.medium" } ] }
Trong ví dụ này, web_server_instances
là một List với mỗi phần tử là một đối tượng chứa:
ami
: giá trị chuỗi đại diện cho Amazon Machine Imageinstance_type
: giá trị chuỗi đại diện cho loại instance
Sử dụng các kiểu biến phức tạp như Map và List giúp bạn tổ chức cấu trúc dữ liệu phức tạp trong cấu hình Terraform, khiến chúng dễ đọc, dễ bảo trì và có thể tái sử dụng hơn.
Tfvars file
Tệp Tfvars (Terraform Variables File) là một tệp cấu hình riêng biệt được sử dụng trong Terraform để lưu trữ các giá trị biến cho cấu hình Terraform. File này giúp bạn tách biệt các giá trị biến nhạy cảm hoặc thay đổi thường xuyên khỏi code Terraform chính, giúp mã gọn gàng và dễ quản lý hơn.
Lợi ích của tệp Tfvars:
Tăng tính bảo mật: Bạn có thể lưu trữ các giá trị biến nhạy cảm (như khóa truy cập API, mật khẩu) trong tệp Tfvars riêng biệt và bảo vệ nó bằng các biện pháp bảo mật mạnh mẽ hơn.
Tăng tính linh hoạt: Việc sử dụng tệp Tfvars cho phép bạn dễ dàng thay đổi các giá trị biến mà không cần sửa đổi mã Terraform chính. Điều này đặc biệt hữu ích khi bạn cần triển khai cấu hình Terraform cho nhiều môi trường khác nhau (ví dụ: phát triển, thử nghiệm, sản xuất) với các giá trị biến khác nhau.
Tăng tính khả năng đọc: Tách biệt các giá trị biến khỏi code Terraform giúp code Terraform dễ đọc và dễ hiểu hơn.
Tăng tính khả năng bảo trì: Việc sửa đổi và quản lý các giá trị biến trở nên dễ dàng hơn khi chúng được lưu trữ trong tệp riêng biệt.
Ví Dụ 1:
Tạo tệp tfvars (terraform.tfvars) để cung cấp giá trị cho các biến:
# file main.tf
provider "aws" {
access_key = var.aws_access_key
secret_key = var.aws_secret_key
region = var.region
}
resource "aws_instance" "example" {
ami = var.ami_id
instance_type = var.instance_type
}
# file terraform.tfvars
aws_access_key = "YOUR_AWS_ACCESS_KEY"
aws_secret_key = "YOUR_AWS_SECRET_KEY"
region = "us-west-2"
ami_id = "ami-0c94855ba95c71c99"
instance_type = "t2.micro"
Local Values
Local Values là một tính năng trong Terraform cho phép bạn định nghĩa các biến tạm thời chỉ có giá trị trong một phần cụ thể của code Terraform. Điều này hữu ích cho việc tạo các giá trị phụ trợ hoặc trung gian chỉ cần sử dụng trong phạm vi hẹp.
Cách sử dụng Local Values:
Để sử dụng Local Values, bạn cần sử dụng khối local
trong code Terraform của mình. Bên trong khối local
, bạn có thể khai báo các biến bằng cách sử dụng cú pháp tương tự như khai báo biến thông thường
locals {
instance_count = 3
instance_type = "t2.micro"
subnet_ids = ["subnet-12345678", "subnet-23456789", "subnet-34567890"]
}
resource "aws_instance" "example" {
count = local.instance_count
instance_type = local.instance_type
subnet_id = local.subnet_ids[count.index]
}
Trong ví dụ này, chúng ta đã định nghĩa ba local values: instance_count
, instance_type
, và subnet_ids
. Giá trị instance_count
đại diện cho số lượng instance EC2 cần triển khai. Giá trị instance_type
xác định kiểu instance và subnet_ids
là danh sách các subnet ID.
Trong resource aws_instance
, chúng ta sử dụng giá trị count
để chỉ định số lượng instance dựa trên giá trị của instance_count
. Giá trị instance_type
và subnet_id
được lấy từ local values tương ứng.
Việc sử dụng local values giúp mã cấu hình trở nên rõ ràng và dễ hiểu hơn, đồng thời giúp tái sử dụng và quản lý các giá trị tính toán trong mã cấu hình Terraform
Lợi ích của Local Values:
Tăng tính gọn gàng: Sử dụng giá trị cục bộ giúp bạn giữ cho code Terraform gọn gàng và dễ đọc hơn bằng cách tách biệt các biến tạm thời khỏi code chính.
Tăng tính linh hoạt: Giá trị cục bộ cho phép bạn tạo các giá trị phụ trợ hoặc trung gian chỉ cần sử dụng trong phạm vi hẹp của code.
Tăng khả năng tái sử dụng: Bạn có thể tái sử dụng các khối
local
trong các phần khác nhau của code Terraform để định nghĩa các giá trị cục bộ tương tự.
Ví dụ về Local Values:
Giả sử bạn muốn tạo một tài nguyên AWS EC2 cho mỗi môi trường (ví dụ: Dev, Staging, Production). Bạn có thể sử dụng giá trị cục bộ để định nghĩa biến environment
và sau đó sử dụng biến này để tạo tên tài nguyên EC2 cụ thể cho mỗi môi trường:
resource "aws_instance" "example" {
for_each = local.environments
ami = var.ami
instance_type = var.instance_type
tags = {
Name = local.instance_name
Environment = each.key
}
}
local {
environments = {
development = {
instance_name = "my-instance-dev"
},
testing = {
instance_name = "my-instance-test"
},
production = {
instance_name = "my-instance-prod"
}
}
}
Trong ví dụ này, Terraform sử dụng block local
để định nghĩa một biến environments
chứa các cấu hình cho mỗi môi trường. Sau đó, vòng lặp for_each
lặp qua mỗi môi trường trong environments
và tạo một tài nguyên EC2 với các thuộc tính được cấu hình cho từng môi trường.
Output Values
Output Values là một tính năng trong Terraform cho phép bạn lấy thông tin về các tài nguyên đã tạo và lưu trữ thông tin đó dưới dạng các biến có thể được sử dụng trong các phần khác nhau của cấu hình Terraform hoặc truy cập bên ngoài Terraform.
Output values giúp bạn truy cập dễ dàng đến các thông tin quan trọng như địa chỉ IP, URL, ID tài nguyên hoặc bất kỳ giá trị nào khác mà bạn muốn sử dụng sau khi triển khai. Bạn có thể sử dụng output values để truyền thông tin cho các công cụ khác, tự động hóa quy trình hoặc hiển thị kết quả cho người dùng cuối.
Dưới đây là một ví dụ về việc sử dụng output values trong Terraform:
resource "aws_instance" "example" {
ami = "ami-0c94855ba95c71c99"
instance_type = "t2.micro"
}
output "instance_public_ip" {
value = aws_instance.example.public_ip
}
Trong ví dụ này, chúng ta đã tạo một resource aws_instance
để triển khai một máy chủ EC2 trên AWS. Sau đó, chúng ta sử dụng output block để xuất ra giá trị của public_ip
của instance.
Khi chạy lệnh terraform apply
, Terraform sẽ tạo ra máy chủ EC2 và xuất ra giá trị instance_public_ip
. Bạn có thể sử dụng giá trị này trong các lệnh hoặc công cụ khác, ví dụ: ghi vào tệp tin, truyền cho công cụ tự động hóa, hiển thị cho người dùng cuối, v.v.
Outputs:
instance_public_ip = "203.0.113.10"
Giả sử bạn muốn tạo một tài nguyên AWS S3 và sử dụng giá trị đầu ra bucket_name
của nó trong tập lệnh bash để tải tệp lên kho lưu trữ S3. Bạn có thể thực hiện như sau:
resource "aws_s3_bucket" "example" {
bucket = "my-example-bucket"
tags = {
Name = "my-example-bucket"
}
}
output "bucket_name" {
value = aws_s3_bucket.example.bucket
}
Sau khi chạy code Terraform, bạn có thể sử dụng lệnh sau để tải tệp lên kho lưu trữ S3:
aws s3 cp my-file.txt s3://$(terraform output bucket_name)
Trong lệnh này, $(terraform output bucket_name)
sẽ được thay thế bằng giá trị thực tế của bucket_name
, tức là tên của kho lưu trữ S3 đã tạo.
Lưu ý:
Giá trị đầu ra chỉ có giá trị sau khi các tài nguyên liên quan đã được tạo.
Nên sử dụng giá trị đầu ra cho các thông tin quan trọng cần được truy cập bên ngoài Terraform.
Sử dụng các công cụ quản lý cấu hình như Terraform Cloud để bảo mật và quản lý giá trị đầu ra một cách hiệu quả.