Terraform 的基础设施即代码:从手动到自动化云管理

使用 Terraform 管理云基础设施。涵盖HCL语法、模块、状态管理、CI/CD集成和多环境部署策略。

E
ECOSIRE Research and Development Team
|2026年3月16日5 分钟阅读963 字数|

使用 Terraform 进行基础设施即代码:从手动到自动化云管理

Organizations using Infrastructure as Code (IaC) provision environments 90% faster and experience 60% fewer configuration-related outages than those managing infrastructure manually. Terraform has emerged as the dominant IaC tool, with over 3,000 providers supporting every major cloud platform and SaaS service.

This guide covers practical Terraform usage for web applications, ERP systems, and eCommerce platforms --- from your first resource definition to production-grade multi-environment deployments.

要点

  • Terraform 通过版本控制使基础设施更改可审查、可测试和可逆
  • 远程状态管理可防止多个工程师修改基础设施时发生冲突
  • 模块封装了可重用的模式,将配置从数百行减少到几个参数
  • Terraform Cloud 或 CI/CD 集成强制执行“先计划后应用”规则以实现安全变更

为什么 Terraform 适合中小型企业

手动基础设施问题

如果没有 IaC,您的基础设施知识将存在于:

  • 无人记录的 AWS 控制台点击路径
  • 几个月前运行的 SSH 命令无人记得
  • 直接在服务器上编辑的配置文件
  • 一位工程师关于“网络如何工作”的心智模型

借助 Terraform,您的基础设施位于 Git 中。每个更改都是一个拉取请求。每个部署都是可重复的。每个工程师都能了解全局。

核心概念

概念描述
供应商与云平台(AWS、GCP、Azure、Cloudflare)接口的插件
资源单个基础设施组件(EC2 实例、RDS 数据库、S3 存储桶)
数据来源对现有基础设施的只读引用
变量可重用配置的输入参数
输出从 Terraform 配置导出的值
状态Terraform 管理内容及其当前属性的记录
模块具有已定义接口的可重用资源组

第一个 Terraform 配置

用于 Web 应用程序的 AWS VPC 和 EC2

# providers.tf
terraform {
  required_version = ">= 1.7"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }

  backend "s3" {
    bucket = "ecosire-terraform-state"
    key    = "production/terraform.tfstate"
    region = "us-east-1"
    encrypt = true
    dynamodb_table = "terraform-locks"
  }
}

provider "aws" {
  region = var.aws_region
}

# variables.tf
variable "aws_region" {
  type    = string
  default = "us-east-1"
}

variable "environment" {
  type    = string
  default = "production"
}

variable "instance_type" {
  type    = string
  default = "t3.large"
}

# main.tf
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name        = "${var.environment}-vpc"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

resource "aws_subnet" "public" {
  count             = 2
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.${count.index + 1}.0/24"
  availability_zone = data.aws_availability_zones.available.names[count.index]

  map_public_ip_on_launch = true

  tags = {
    Name = "${var.environment}-public-${count.index + 1}"
  }
}

resource "aws_instance" "app" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = var.instance_type
  subnet_id     = aws_subnet.public[0].id

  vpc_security_group_ids = [aws_security_group.app.id]
  key_name               = aws_key_pair.deploy.key_name

  root_block_device {
    volume_size = 50
    volume_type = "gp3"
    encrypted   = true
  }

  tags = {
    Name        = "${var.environment}-app"
    Environment = var.environment
  }
}

resource "aws_db_instance" "postgres" {
  identifier     = "${var.environment}-db"
  engine         = "postgres"
  engine_version = "17"
  instance_class = "db.t3.medium"

  allocated_storage     = 50
  max_allocated_storage = 200
  storage_encrypted     = true

  db_name  = "ecosire"
  username = "app"
  password = var.db_password

  vpc_security_group_ids = [aws_security_group.db.id]
  db_subnet_group_name   = aws_db_subnet_group.main.name

  backup_retention_period = 7
  backup_window           = "03:00-04:00"
  maintenance_window      = "sun:04:00-sun:05:00"

  skip_final_snapshot = false
  final_snapshot_identifier = "${var.environment}-db-final"

  tags = {
    Environment = var.environment
  }
}

可重用基础设施模块

创建 Web 应用程序模块

# modules/web-app/main.tf
variable "name" {
  type = string
}

variable "environment" {
  type = string
}

variable "instance_type" {
  type    = string
  default = "t3.medium"
}

variable "vpc_id" {
  type = string
}

variable "subnet_ids" {
  type = list(string)
}

resource "aws_lb" "app" {
  name               = "${var.name}-${var.environment}-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb.id]
  subnets            = var.subnet_ids
}

resource "aws_lb_target_group" "app" {
  name     = "${var.name}-${var.environment}-tg"
  port     = 3000
  protocol = "HTTP"
  vpc_id   = var.vpc_id

  health_check {
    path                = "/health"
    healthy_threshold   = 2
    unhealthy_threshold = 3
    interval            = 30
  }
}

resource "aws_autoscaling_group" "app" {
  name                = "${var.name}-${var.environment}-asg"
  min_size            = 2
  max_size            = 10
  desired_capacity    = 2
  vpc_zone_identifier = var.subnet_ids
  target_group_arns   = [aws_lb_target_group.app.arn]

  launch_template {
    id      = aws_launch_template.app.id
    version = "$Latest"
  }

  tag {
    key                 = "Name"
    value               = "${var.name}-${var.environment}"
    propagate_at_launch = true
  }
}

output "alb_dns_name" {
  value = aws_lb.app.dns_name
}

使用模块

# environments/production/main.tf
module "web" {
  source = "../../modules/web-app"

  name          = "ecosire-web"
  environment   = "production"
  instance_type = "t3.large"
  vpc_id        = module.network.vpc_id
  subnet_ids    = module.network.public_subnet_ids
}

module "api" {
  source = "../../modules/web-app"

  name          = "ecosire-api"
  environment   = "production"
  instance_type = "t3.large"
  vpc_id        = module.network.vpc_id
  subnet_ids    = module.network.public_subnet_ids
}

状态管理

使用 S3 进行远程状态

# Bootstrap: create the state bucket and DynamoDB table manually or with a separate config
resource "aws_s3_bucket" "terraform_state" {
  bucket = "ecosire-terraform-state"

  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_s3_bucket_versioning" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

通过 DynamoDB 进行状态锁定可防止两名工程师同时运行 terraform apply,这可能会损坏状态。

State File Security

Terraform 状态文件包含敏感信息,包括数据库密码、API 密钥和资源 ID。保护它:

  • 静态加密:S3 存储桶版本控制 + 服务器端加密
  • 传输中加密:HTTPS 仅用于状态访问
  • 限制访问:IAM 策略限制谁可以读取/写入状态
  • 永远不要提交到 Git:状态文件绝不能处于版本控制中
  • 启用版本控制:S3 版本控制允许从损坏的状态中恢复

CI/CD 集成

GitHub Actions Terraform 管道

name: Terraform
on:
  pull_request:
    paths: ['infrastructure/**']
  push:
    branches: [main]
    paths: ['infrastructure/**']

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3

      - name: Terraform Init
        run: terraform init
        working-directory: infrastructure/environments/production

      - name: Terraform Plan
        run: terraform plan -out=tfplan
        working-directory: infrastructure/environments/production

      - name: Comment PR with plan
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const plan = require('fs').readFileSync('infrastructure/environments/production/tfplan.txt', 'utf8');
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `## Terraform Plan\n\`\`\`\n${plan}\n\`\`\``
            });

  apply:
    needs: plan
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3

      - name: Terraform Apply
        run: terraform apply -auto-approve
        working-directory: infrastructure/environments/production

多环境策略

环境目的实例大小成本目标
发展功能测试t3.micro / t3.smallt3.micro / t3.small
分期生产前验证镜子生产(较小)约 30% 的产量
生产实时路况尺寸适合负载优化

每个环境使用 Terraform 工作区或单独的目录:

infrastructure/
  modules/
    web-app/
    database/
    network/
  environments/
    development/
      main.tf
      terraform.tfvars
    staging/
      main.tf
      terraform.tfvars
    production/
      main.tf
      terraform.tfvars

常见问题

Terraform 或 Pulumi --- 我们应该选择哪个?

Terraform 如果您的团队包括喜欢声明性配置的运营工程师。如果您的团队由大量开发人员组成并且更喜欢使用 TypeScript 或 Python 编写基础架构,那么 Pulumi 是首选。 Terraform拥有更大的生态系统和更多的社区模块。 Pulumi 的初始学习曲线更陡峭,但对于复杂逻辑更灵活。

我们如何将现有基础设施导入 Terraform?

使用 terraform import 将现有资源置于 Terraform 管理之下。例如:terraform import aws_instance.app i-1234567890abcdef0。导入后,写入匹配的配置。 Terraform 1.5+ 支持配置文件中的导入块以进行批量导入。

我们如何在 Terraform 中处理秘密?

切勿将机密提交给 Terraform 文件。使用 terraform.tfvars(从 Git 中排除)、环境变量 (TF_VAR_db_password) 或机密管理器(AWS Secrets Manager、HashiCorp Vault)。使用 sensitive = true 标记敏感变量,以防止它们出现在计划输出中。

管理 Terraform 的成本是多少?

Terraform 本身是免费且开源的。 Terraform Cloud 提供最多 5 个用户的免费套餐,并具有远程状态和计划/应用功能。主要成本是学习曲线(经验丰富的工程师需要 20-40 小时)和持续维护(每月 2-4 小时)。这被手动基础设施管理节省的时间所抵消。


接下来会发生什么

Terraform 为自动化基础设施提供了基础。将其与 CI/CD 管道 相结合以实现自动化部署,与 监控 相结合以实现操作可见性,并与 灾难恢复 相结合以实现弹性。

联系 ECOSIRE 获取基础设施自动化咨询,或浏览我们的小型企业 DevOps 指南 获取完整的路线图。


由 ECOSIRE 发布——帮助企业实现云基础设施自动化。

E

作者

ECOSIRE Research and Development Team

在 ECOSIRE 构建企业级数字产品。分享关于 Odoo 集成、电商自动化和 AI 驱动商业解决方案的洞见。

通过 WhatsApp 聊天