使用Terraform管理阿里云基础设施

发布于:2025-09-09 ⋅ 阅读:(16) ⋅ 点赞:(0)

摘要

本文演示如何使用 Terraform 在阿里云(Alibaba Cloud)上通过代码创建网络与 ECS,并让 ECS
能够被公网访问:在实例启动时通过 user_data 自动安装 Docker 并运行一个 nginx 容器,最后可通过公网 IP 访问
nginx 默认页面。Terraform 的 state 使用阿里云 OSS 作为远程后端,适合团队协作与 CI/CD
场景。文中包含概念介绍、适用场景、完整代码、部署步骤与最佳实践,代码可直接复制部署(请替换示例中的 OSS bucket、image_id
等敏感或私有信息)。

一、概念简介

  • Terraform:HashiCorp 的基础设施即代码(IaC)工具,使用声明式配置管理云资源。
  • Provider:与云厂商交互的插件(本文使用 aliyun/alicloud)。
  • State(状态):Terraform 用来追踪资源与其元数据的文件,可放本地或远端(remote state)。
  • Backend:定义 state 存放位置(本文使用 OSS backend)。

二、适用场景

  • 团队协作时统一管理 Terraform state;
  • 通过 CI/CD 自动化创建与销毁基础设施;
  • 需要通过实例 user_data 初始化环境(如自动安装 Docker 并部署容器);
  • 希望快速搭建一个对外提供服务的演示或轻量 Web 服务(nginx)。

三、前置准备

  • 阿里云账号与具有相应权限的 AccessKey(或使用 RAM 角色 / 实例角色)。
  • 已创建的 OSS Bucket(用于存放 Terraform state),并记录 bucket 名称与 endpoint(例如 oss-cn-hangzhou.aliyuncs.com)。
  • 本地已安装 Terraform(建议 1.0+)。
  • 目标 region 中可用的镜像 ID(image_id)。可在控制台或镜像市场查询,或使用 Terraform data 源动态查找。

如何创建 OSS Bucket(简要):

  • 控制台:对象存储 OSS -> 创建 Bucket -> 选择地域与权限(建议私有),建议开启版本控制(Versioning)。

四、OSS 作为远程 state 的注意点

  • 在 Terraform 配置中使用 terraform { backend “oss” { … } } 指定 OSS 后端。
  • 认证:通过环境变量 ALICLOUD_ACCESS_KEY / ALICLOUD_SECRET_KEY 或 RAM 实例角色,不要在代码中写明文凭证。
  • State locking:OSS 后端通常不提供 Terraform 的分布式状态锁(相比 AWS + DynamoDB 的方式),并发 apply 可能存在竞态风险。团队建议使用 Terraform Cloud/Enterprise 或在 CI 层做互斥控制。
  • 建议对 OSS Bucket 限权并开启版本控制,防止误删或篡改 state。

五、完整示例

建议文件结构

  • terraform/
    • main.tf
    • variables.tf
    • outputs.tf
    • terraform.tfvars (可选,不要提交到版本库含敏感信息)

注意:请把示例中的 bucket 名称、endpoint、image_id 等替换为你的实际值。

main.tf

terraform {
  required_providers {
    alicloud = {
      source  = "aliyun/alicloud"
      version = "~> 1.200"
    }
  }

  backend "oss" {
    bucket   = "my-terraform-state-bucket"      # 替换为你的 OSS bucket 名称
    key      = "envs/dev/terraform.tfstate"     # state 存放路径
    endpoint = "oss-cn-hangzhou.aliyuncs.com"   # 替换为你的 OSS endpoint
    encrypt  = true
  }
}

provider "alicloud" {
  region = var.region
  # 凭证通过环境变量或 RAM 角色提供,不要在此处明文写入
}

# VPC 与 VSwitch
resource "alicloud_vpc" "demo_vpc" {
  name       = var.vpc_name
  cidr_block = var.vpc_cidr
}

resource "alicloud_vswitch" "demo_vswitch" {
  vpc_id            = alicloud_vpc.demo_vpc.id
  cidr_block        = var.vswitch_cidr
  availability_zone = var.az
  name              = "${var.vpc_name}-vswitch"
}

# 安全组(允许 SSH 和 HTTP)
resource "alicloud_security_group" "demo_sg" {
  name        = "${var.vpc_name}-sg"
  vpc_id      = alicloud_vpc.demo_vpc.id
  description = "Allow SSH and HTTP inbound"
}

resource "alicloud_security_group_rule" "ssh_inbound" {
  type              = "ingress"
  ip_protocol       = "tcp"
  nic_type          = "internet"
  port_range        = "22/22"
  policy            = "accept"
  priority          = 1
  security_group_id = alicloud_security_group.demo_sg.id
  cidr_ip           = "0.0.0.0/0"
}

resource "alicloud_security_group_rule" "http_inbound" {
  type              = "ingress"
  ip_protocol       = "tcp"
  nic_type          = "internet"
  port_range        = "80/80"
  policy            = "accept"
  priority          = 1
  security_group_id = alicloud_security_group.demo_sg.id
  cidr_ip           = "0.0.0.0/0"
}

# ECS:通过 user_data 安装 Docker 并运行 nginx
resource "alicloud_instance" "demo_ecs" {
  instance_name             = "${var.vpc_name}-ecs"
  instance_type             = var.instance_type
  image_id                  = var.image_id
  vswitch_id                = alicloud_vswitch.demo_vswitch.id
  security_groups           = [alicloud_security_group.demo_sg.id]
  internet_max_bandwidth_out = 5
  system_disk_category       = "cloud_efficiency"
  system_disk_size           = 40

  user_data = <<-EOF
              #!/bin/bash
              set -e
              exec > /var/log/cloud-init-docker.log 2>&1

              # 安装 Docker(兼容常见发行版)
              if command -v yum >/dev/null 2>&1; then
                yum install -y yum-utils device-mapper-persistent-data lvm2 || true
                curl -fsSL https://get.docker.com | sh
              elif command -v apt-get >/dev/null 2>&1; then
                apt-get update -y || true
                apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release || true
                curl -fsSL https://get.docker.com | sh
              else
                curl -fsSL https://get.docker.com | sh || true
              fi

              systemctl enable docker || true
              systemctl start docker || true

              # 等待 Docker 就绪(最多等待 60s)
              for i in {1..30}; do
                if docker version >/dev/null 2>&1; then break; fi
                sleep 2
              done

              # 运行 nginx 容器,宿主机 80 -> 容器 80
              docker run -d --name demo-nginx -p 80:80 nginx:stable-alpine || true
              EOF
}

# 为 ECS 分配 EIP(稳定公网 IP)并关联
resource "alicloud_eip" "web_eip" {
  name                 = "${var.vpc_name}-eip"
  internet_charge_type = "PayByTraffic"
  bandwidth            = 1
}

resource "alicloud_eip_association" "eip_assoc" {
  allocation_id = alicloud_eip.web_eip.id
  instance_id   = alicloud_instance.demo_ecs.id
}

variables.tf

variable "region" {
  type    = string
  default = "cn-hangzhou"
}

variable "vpc_name" {
  type    = string
  default = "demo-terraform-vpc"
}

variable "vpc_cidr" {
  type    = string
  default = "10.0.0.0/16"
}

variable "vswitch_cidr" {
  type    = string
  default = "10.0.1.0/24"
}

variable "az" {
  type    = string
  default = "cn-hangzhou-a"
}

variable "instance_type" {
  type    = string
  default = "ecs.t5-lc2m1.small"
}

variable "image_id" {
  type        = string
  description = "请替换为你所在 region 可用的镜像 ID(官方 Ubuntu/CentOS 等)。"
  default     = ""
}

outputs.tf

output "vpc_id" {
  value = alicloud_vpc.demo_vpc.id
}

output "vswitch_id" {
  value = alicloud_vswitch.demo_vswitch.id
}

output "instance_id" {
  value = alicloud_instance.demo_ecs.id
}

output "web_eip_public_ip" {
  value       = alicloud_eip.web_eip.ip_address
  description = "EIP 公网 IP,用于访问 nginx(若 provider 字段不同,请据实际属性名调整)。"
}

可选:terraform.tfvars(不要上传到公开仓库)

# terraform.tfvars 示例(实际请替换为你的 image_id 等)
image_id = "m-xxxxxxxxxxxxx"
region   = "cn-hangzhou"

提示:如果你不确定 image_id,可以用 Terraform data 源来查找官方镜像(例如按镜像名称或标签过滤)。不同 provider 版本 data 源用法可能不同,需参考 aliyun/alicloud provider 文档。

六、初始化与部署步骤

  1. 在终端设置阿里云凭证(推荐使用环境变量或 RAM 角色):

    • Linux/macOS:
      • export ALICLOUD_ACCESS_KEY=“你的AccessKey”
      • export ALICLOUD_SECRET_KEY=“你的Secret”
    • Windows PowerShell:
      • $env:ALICLOUD_ACCESS_KEY=“你的AccessKey”
      • $env:ALICLOUD_SECRET_KEY=“你的Secret”
  2. 在包含 main.tf 的目录运行:

    • terraform init
      • 第一次 init 会读取 backend “oss” 配置并尝试初始化 OSS 后端,确保 OSS bucket 已存在且凭证有权限访问该 bucket。
    • terraform plan
    • terraform apply
  3. 部署完成后查看输出:

    • terraform output web_eip_public_ip
    • 在浏览器中访问 http://<web_eip_public_ip>/ ,应看到 nginx 默认页面。

七、访问验证与排查建议

  • 访问不到 nginx 页面时请检查:
    • Security Group 是否开放 80 端口(ingress 规则)。
    • EIP 是否成功分配并关联到 ECS(terraform output / 控制台查看)。
    • SSH 登录 ECS(若能连),查看 /var/log/cloud-init-docker.log、Docker 服务状态与容器状态:
      • systemctl status docker
      • docker ps -a
    • 若 user_data 执行失败,可在实例上查看 cloud-init 或 system 日志,调整 user_data 脚本后重建实例(或手动修复)。

八、最佳实践

  • 不要在 Terraform 文件中写明文凭证,优先使用 RAM 角色或环境变量。
  • 为 OSS bucket 设置最小权限策略,并开启版本控制(Bucket Versioning)。
  • OSS 后端无原生锁,团队并发时使用 Terraform Cloud/Enterprise 或在 CI 层实现互斥。
  • 把敏感信息(密码、密钥)视为敏感变量,避免在 state 中明文保存;必要时使用加密或专用 Secrets 管理服务。
  • 对生产环境进行模块化设计(模块、命名规则、环境分离),并在部署前进行变更审查(terraform plan -> 审核 -> apply)。
  • 生产环境建议使用更严格的镜像与容器安全策略(私有镜像仓库、镜像扫描、最小权限)。

九、总结

本文展示了如何使用 Terraform 在阿里云上:

  • 使用 OSS 作为远端 state 后端以便团队共享与版本化;
  • 创建 VPC、VSwitch、Security Group、ECS,并通过 EIP 为实例分配稳定公网 IP;
  • 通过 user_data 自动安装 Docker 并在容器中运行 nginx,使得服务可以通过公网访问。

关键注意点包括 OSS 后端的权限与版本控制、state 锁机制的限制、以及对敏感信息的保护。在生产中应结合模块化、审计、CI/CD、以及更严格的安全策略进行完善。


网站公告

今日签到

点亮在社区的每一天
去签到