TLDR: Các biến giúp cấu hình có thể tái sử dụng - xác định chúng bằng loại và mặc định, đặt chúng thông qua CLI, tệp hoặc biến môi trường. Đầu ra hiển thị các giá trị sau khi áp dụng - như địa chỉ IP hoặc ID tài nguyên. Sử dụng các quy tắc xác thực để phát hiện lỗi sớm và gắn cờ nhạy cảm để che giấu bí mật.
Các biến và kết quả đầu ra là cách bạn tạo cấu hình Terraform linh hoạt và mang tính thông tin. Các biến cho phép bạn tùy chỉnh hành vi mà không cần thay đổi mã. Đầu ra trích xuất thông tin về các tài nguyên được tạo.
Biến đầu vào
Các biến tham số hóa cấu hình của bạn để bạn có thể sử dụng nó trong các tình huống khác nhau mà không cần sửa đổi.
Khai báo biến cơ bản
Khai báo biến bằng khối variable:
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.micro"
}
variable "instance_count" {
description = "Number of instances to create"
type = number
default = 1
}
variable "enable_monitoring" {
description = "Enable detailed monitoring"
type = bool
default = false
}
Sử dụng các biến trong cấu hình của bạn:
resource "aws_instance" "web" {
count = var.instance_count
ami = "ami-0c55b159cbfafe1f0"
instance_type = var.instance_type
monitoring = var.enable_monitoring
tags = {
Name = "web-${count.index}"
}
}
Các loại biến
Terraform hỗ trợ một số loại:
Các loại nguyên thủy:
variable "string_example" {
type = string
default = "hello"
}
variable "number_example" {
type = number
default = 42
}
variable "bool_example" {
type = bool
default = true
}
Các loại bộ sưu tập:
variable "availability_zones" {
type = list(string)
default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
variable "instance_tags" {
type = map(string)
default = {
Environment = "development"
Project = "web-app"
}
}
variable "allowed_ports" {
type = set(number)
default = [80, 443, 8080]
}
Các loại kết cấu:
variable "server_config" {
type = object({
instance_type = string
disk_size = number
enable_backup = bool
})
default = {
instance_type = "t3.micro"
disk_size = 20
enable_backup = false
}
}
variable "subnet_configs" {
type = list(object({
cidr_block = string
availability_zone = string
public = bool
}))
default = [
{
cidr_block = "10.0.1.0/24"
availability_zone = "us-east-1a"
public = true
},
{
cidr_block = "10.0.2.0/24"
availability_zone = "us-east-1b"
public = false
}
]
}
Sử dụng các loại phức tạp:
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = var.server_config.instance_type
root_block_device {
volume_size = var.server_config.disk_size
}
tags = var.instance_tags
}
resource "aws_subnet" "subnets" {
for_each = { for idx, subnet in var.subnet_configs : idx => subnet }
vpc_id = aws_vpc.main.id
cidr_block = each.value.cidr_block
availability_zone = each.value.availability_zone
map_public_ip_on_launch = each.value.public
}
Đặt giá trị biến
Có một số cách để cung cấp giá trị:
Dòng lệnh:
terraform apply -var="instance_type=t3.large" -var="instance_count=3"
Các tệp biến:
Tạo terraform.tfvars:
instance_type = "t3.large"
instance_count = 3
enable_monitoring = true
instance_tags = {
Environment = "production"
Project = "web-app"
Team = "platform"
}
Terraform tự động tải các tệp terraform.tfvars và *.auto.tfvars.
Đối với cấu hình dành riêng cho môi trường:
# dev.tfvars
instance_type = "t3.micro"
instance_count = 1
# prod.tfvars
instance_type = "t3.large"
instance_count = 5
Áp dụng với:
terraform apply -var-file="dev.tfvars"
terraform apply -var-file="prod.tfvars"
EBiến môi trường:
export TF_VAR_instance_type="t3.large"
export TF_VAR_instance_count=3
terraform apply
Terraform đọc bất kỳ biến môi trường nào bắt đầu bằng TF_VAR_.
Đầu vào tương tác:
Nếu một biến không có giá trị mặc định và bạn không cung cấp giá trị, Terraform sẽ nhắc:
$ terraform apply
var.instance_type
EC2 instance type
Enter a value: t3.micro
Mức độ ưu tiên thay đổi
Khi nhiều nguồn cung cấp giá trị, Terraform sử dụng mức độ ưu tiên này (cao nhất đến thấp nhất):
- Cờ dòng lệnh (
-var) - Tệp
*.auto.tfvars(thứ tự bảng chữ cái) - Tệp
terraform.tfvars - Biến môi trường (
TF_VAR_*) - Giá trị mặc định trong khai báo biến
Xác thực biến
Thêm quy tắc xác thực để phát hiện lỗi trước khi thay đổi cơ sở hạ tầng:
variable "instance_type" {
type = string
description = "EC2 instance type"
validation {
condition = can(regex("^t3\\.", var.instance_type))
error_message = "Instance type must be from the t3 family."
}
}
variable "environment" {
type = string
description = "Environment name"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "disk_size" {
type = number
description = "Root disk size in GB"
validation {
condition = var.disk_size >= 20 && var.disk_size <= 1000
error_message = "Disk size must be between 20 and 1000 GB."
}
}
Nếu xác thực không thành công, Terraform sẽ hiển thị lỗi trước khi thực hiện thay đổi:
Error: Invalid value for variable
on variables.tf line 12:
12: variable "environment" {
Environment must be dev, staging, or prod.
Biến nhạy cảm
Đánh dấu các biến chứa bí mật:
variable "database_password" {
type = string
description = "Database admin password"
sensitive = true
}
variable "api_key" {
type = string
sensitive = true
}
Terraform sẽ không hiển thị các giá trị này trong nhật ký hoặc đầu ra:
# aws_db_instance.main will be created
+ resource "aws_db_instance" "main" {
+ password = (sensitive value)
...
}
Vẫn chưa bao giờ commit bí mật kiểm soát phiên bản. Sử dụng các biến môi trường hoặc hệ thống quản lý bí mật.
Giá trị đầu ra
Đầu ra hiển thị thông tin về cơ sở hạ tầng của bạn sau khi Terraform tạo ra nó.
Đầu ra cơ bản
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
}
output "instance_id" {
description = "ID of the EC2 instance"
value = aws_instance.web.id
}
output "instance_public_ip" {
description = "Public IP address"
value = aws_instance.web.public_ip
}
output "instance_private_ip" {
description = "Private IP address"
value = aws_instance.web.private_ip
}
Sau terraform apply, kết quả đầu ra xuất hiện:
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
instance_id = "i-0123456789abcdef"
instance_private_ip = "10.0.1.25"
instance_public_ip = "54.123.45.67"
Xem kết quả đầu ra bất cứ lúc nào:
terraform output
Nhận một đầu ra cụ thể:
terraform output instance_public_ip
Nhận định dạng JSON:
terraform output -json
Đầu ra phức tạp
Bộ sưu tập và cấu trúc đầu ra:
resource "aws_instance" "web" {
count = 3
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
}
output "all_instance_ids" {
description = "IDs of all instances"
value = aws_instance.web[*].id
}
output "all_instance_ips" {
description = "Public IPs of all instances"
value = aws_instance.web[*].public_ip
}
output "instance_details" {
description = "Detailed information about instances"
value = {
ids = aws_instance.web[*].id
public_ips = aws_instance.web[*].public_ip
private_ips = aws_instance.web[*].private_ip
}
}
Đầu ra:
Outputs:
all_instance_ids = [
"i-0123456789abcdef",
"i-0123456789abcdeg",
"i-0123456789abcdeh",
]
instance_details = {
"ids" = [
"i-0123456789abcdef",
"i-0123456789abcdeg",
"i-0123456789abcdeh",
]
"private_ips" = [
"10.0.1.25",
"10.0.1.26",
"10.0.1.27",
]
"public_ips" = [
"54.123.45.67",
"54.123.45.68",
"54.123.45.69",
]
}
Đầu ra nhạy cảm
Ẩn thông tin nhạy cảm trong đầu ra:
resource "aws_db_instance" "main" {
identifier = "mydb"
engine = "postgres"
password = var.database_password
# ... other config ...
}
output "database_endpoint" {
description = "Database connection endpoint"
value = aws_db_instance.main.endpoint
}
output "database_password" {
description = "Database password"
value = aws_db_instance.main.password
sensitive = true
}
Đầu ra nhạy cảm không xuất hiện ở đầu ra bình thường:
Outputs:
database_endpoint = "mydb.abc123.us-east-1.rds.amazonaws.com:5432"
database_password = <sensitive>
Truy xuất giá trị một cách rõ ràng:
terraform output database_password
Hoặc với -json để phân tích nó:
terraform output -json database_password | jq -r
Đầu ra từ mô-đun
Đầu ra là cách các mô-đun trả về giá trị. Nếu bạn sử dụng mô-đun VPC:
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
name = "main-vpc"
}
# Use the module's outputs
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
subnet_id = module.vpc.public_subnet_id # Output from module
}
# Re-export module outputs
output "vpc_id" {
description = "ID of the VPC"
value = module.vpc.vpc_id
}
Ví dụ thực tế: Cơ sở hạ tầng linh hoạt
Đây là một ví dụ hoàn chỉnh sử dụng các biến và kết quả đầu ra:
# variables.tf
variable "environment" {
description = "Environment name"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Must be dev, staging, or prod."
}
}
variable "project" {
description = "Project name"
type = string
default = "webapp"
}
variable "instance_configs" {
description = "Configuration for each instance type"
type = map(object({
instance_type = string
count = number
disk_size = number
}))
default = {
dev = {
instance_type = "t3.micro"
count = 1
disk_size = 20
}
staging = {
instance_type = "t3.small"
count = 2
disk_size = 30
}
prod = {
instance_type = "t3.large"
count = 5
disk_size = 50
}
}
}
variable "allowed_ssh_cidrs" {
description = "CIDR blocks allowed to SSH"
type = list(string)
default = []
}
# main.tf
locals {
config = var.instance_configs[var.environment]
common_tags = {
Environment = var.environment
Project = var.project
ManagedBy = "terraform"
}
}
resource "aws_security_group" "web" {
name = "${var.project}-${var.environment}-sg"
description = "Security group for ${var.environment}"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
dynamic "ingress" {
for_each = length(var.allowed_ssh_cidrs) > 0 ? [1] : []
content {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = var.allowed_ssh_cidrs
}
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = merge(local.common_tags, {
Name = "${var.project}-${var.environment}-sg"
})
}
resource "aws_instance" "web" {
count = local.config.count
ami = data.aws_ami.ubuntu.id
instance_type = local.config.instance_type
vpc_security_group_ids = [aws_security_group.web.id]
subnet_id = aws_subnet.public.id
root_block_device {
volume_size = local.config.disk_size
}
tags = merge(local.common_tags, {
Name = "${var.project}-${var.environment}-web-${count.index + 1}"
})
}
# outputs.tf
output "environment" {
description = "Deployment environment"
value = var.environment
}
output "instance_count" {
description = "Number of instances created"
value = local.config.count
}
output "instance_ids" {
description = "IDs of all web instances"
value = aws_instance.web[*].id
}
output "instance_ips" {
description = "Public IP addresses"
value = aws_instance.web[*].public_ip
}
output "ssh_commands" {
description = "SSH commands for each instance"
value = [
for idx, instance in aws_instance.web :
"ssh ubuntu@${instance.public_ip} # ${var.project}-${var.environment}-web-${idx + 1}"
]
}
output "load_balancer_endpoint" {
description = "Load balancer endpoint"
value = aws_lb.web.dns_name
depends_on = [aws_lb.web]
}
Sử dụng nó cho các môi trường khác nhau:
# Development
terraform apply -var="environment=dev"
# Staging
terraform apply -var="environment=staging" -var="allowed_ssh_cidrs=[\"203.0.113.0/24\"]"
# Production
terraform apply -var-file="prod.tfvars"
Trong đó prod.tfvars chứa:
environment = "prod"
project = "webapp"
allowed_ssh_cidrs = [
"203.0.113.0/24", # Office network
"198.51.100.0/24" # VPN network
]
Thiết lập này cung cấp cho bạn:
- Số lượng và kích thước phiên bản dành riêng cho môi trường
- Xác thực ngăn ngừa lỗi chính tả trong tên môi trường
- Kiểm soát truy cập SSH linh hoạt
- Đầu ra chi tiết để kết nối với tài nguyên
- Cấu hình có thể tái sử dụng trên nhiều môi trường
Hiểu các biến và kết quả đầu ra cho phép bạn xây dựng các cấu hình Terraform linh hoạt, có thể tái sử dụng. Tiếp theo, chúng ta sẽ khám phá các mô-đun - cách tổ chức và chia sẻ mã Terraform giữa các dự án.