🏗️ 第18课:IaC基础设施即代码

核心概念

IaC基础设施即代码:IaC将基础设施的定义从手工操作变成声明

IaC将基础设施的定义从手工操作变成声明式代码,实现版本控制、自动部署、可复现、可审计。Terraform是当前最流行的IaC工具。

架构图

┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐
│ 编写HCL  │→│ terraform │→│ terraform │→│ terraform │
│ (*.tf)   │  │   init    │  │   plan    │  │  apply    │
└──────────┘  └──────────┘  └──────────┘  └─────┬─────┘
                                                 │
                                          ┌──────▼──────┐
                                          │  云API调用   │
                                          └──────┬──────┘
                    ┌─────────────────────────────┼─────────┐
                    ▼                ▼             ▼         ▼
              ┌──────────┐  ┌──────────┐  ┌──────────┐ ┌──────┐
              │   VPC    │  │   EC2    │  │   RDS    │ │  S3  │
              └──────────┘  └──────────┘  └──────────┘ └──────┘
                    └────────────────┴─────────────┴─────────┘
                                     │
                              ┌──────▼──────┐
                              │ tfstate(S3) │
                              └─────────────┘

命令实操

1. Terraform基础操作 ✅

Terraform基础
# 安装Terraform
wget -O- https://releases.hashicorp.com/terraform/1.8.0/terraform_1.8.0_linux_amd64.zip > terraform.zip
unzip terraform.zip && sudo mv terraform /usr/local/bin/

mkdir -p terraform/aws-infra && cd terraform/aws-infra

cat > versions.tf << 'EOF'
terraform {
  required_version = ">= 1.5"
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }
  backend "s3" {
    bucket = "my-tf-state-2026"
    key    = "aws-infra/terraform.tfstate"
    region = "ap-southeast-1"
  }
}
EOF

cat > main.tf << 'EOF'
variable "environment" { default = "production" }
variable "instance_type" { default = "t3.medium" }

resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  tags = { Name = "${var.environment}-vpc" }
}

resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  map_public_ip_on_launch = true
  availability_zone       = "ap-southeast-1a"
  tags = { Name = "${var.environment}-public" }
}

resource "aws_instance" "app" {
  ami                    = data.aws_ami.ubuntu.id
  instance_type          = var.instance_type
  subnet_id              = aws_subnet.public.id
  vpc_security_group_ids = [aws_security_group.app.id]
  tags = { Name = "${var.environment}-app" }
}

data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"]
  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
  }
}

resource "aws_security_group" "app" {
  vpc_id = aws_vpc.main.id
  ingress {
    from_port   = 22
    to_port     = 22
    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"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

output "instance_ip" { value = aws_instance.app.public_ip }
EOF

terraform init
terraform plan -out=tfplan
terraform apply tfplan

2. Module复用 ✅

Module复用
mkdir -p modules/vpc

cat > modules/vpc/main.tf << 'EOF'
variable "cidr" { default = "10.0.0.0/16" }
variable "env"  { default = "dev" }
variable "azs"  { default = ["ap-southeast-1a","ap-southeast-1b"] }

resource "aws_vpc" "this" {
  cidr_block = var.cidr
  tags = { Name = "${var.env}-vpc" }
}

resource "aws_subnet" "public" {
  count                   = length(var.azs)
  vpc_id                  = aws_vpc.this.id
  cidr_block              = cidrsubnet(var.cidr, 8, count.index)
  availability_zone       = var.azs[count.index]
  map_public_ip_on_launch = true
}

resource "aws_subnet" "private" {
  count             = length(var.azs)
  vpc_id            = aws_vpc.this.id
  cidr_block        = cidrsubnet(var.cidr, 8, count.index + length(var.azs))
  availability_zone = var.azs[count.index]
}

output "vpc_id"     { value = aws_vpc.this.id }
output "public_ids" { value = aws_subnet.public[*].id }
EOF

# 使用Module
cat > environments/prod/main.tf << 'EOF'
module "vpc" {
  source = "../../modules/vpc"
  cidr   = "10.1.0.0/16"
  env    = "prod"
  azs    = ["ap-southeast-1a","ap-southeast-1b","ap-southeast-1c"]
}
EOF

3. State管理与CI集成 ✅

State管理
# 远程State(S3+DynamoDB锁)
aws dynamodb create-table --table-name tf-lock \
    --attribute-definitions AttributeName=LockID,AttributeType=S \
    --key-schema AttributeName=LockID,KeyType=HASH \
    --billing-mode PAY_PER_REQUEST

# State操作
terraform state list
terraform state show aws_instance.app
terraform state mv aws_instance.app aws_instance.app_new

# Import已有资源
terraform import aws_instance.app i-1234567890abcdef0

# GitHub Actions集成
cat > .github/workflows/terraform.yml << 'EOF'
name: Terraform CI/CD
on: [push, pull_request]
jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: hashicorp/setup-terraform@v3
    - run: terraform init
    - run: terraform plan -out=tfplan
    - run: terraform apply -auto-approve tfplan
      if: github.ref == 'refs/heads/main'
EOF

架构图

IaC基础设施即代码架构

┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐
│ 编写HCL  │→│ terraform │→│ terraform │→│ terraform │
│ (*.tf)   │  │   init    │  │   plan    │  │  apply    │
└──────────┘  └──────────┘  └──────────┘  └─────┬─────┘
                                                 │
                                          ┌──────▼──────┐
                                          │  云API调用   │
                                          └──────┬──────┘
                    ┌─────────────────────────────┼─────────┐
                    ▼                ▼             ▼         ▼
              ┌──────────┐  ┌──────────┐  ┌──────────┐ ┌──────┐
              │   VPC    │  │   EC2    │  │   RDS    │ │  S3  │
              └──────────┘  └──────────┘  └──────────┘ └──────┘
                    └────────────────┴─────────────┴─────────┘
                                     │
                              ┌──────▼──────┐
                              │ tfstate(S3) │
                              └─────────────┘

故障排查

❌ State冲突/锁

排查
aws dynamodb get-item --table-name tf-lock --key '{"LockID":{"S":"my-tf-state/prod/terraform.tfstate-md5"}}'
# 强制解锁(确认无其他人执行)
terraform force-unlock 
# State修复
terraform state pull > backup.tfstate
terraform state push backup.tfstate
💡 Terraform最佳实践:远程State必须加密、每次apply前先plan、使用workspace隔离环境、Module版本锁定。

🏆 成就解锁:IaC专家!

掌握Terraform HCL、Module复用、State管理、CI/CD集成——基础设施即代码是DevOps核心