用 Terraform 管理华为云资源:从控制台点击到基础设施即代码
为什么要把控制台点击搬进代码
一个人维护三五台云主机时,控制台点点鼠标是最快的。但当环境从一套变成三套(开发、测试、生产),当半年后要回答"这套安全组规则是谁在什么时候改的",控制台点击的隐性成本就开始显形。
具体有三个:不可复现——你记得当时建了子网、绑了弹性公网 IP、开了 8080 端口,但顺序和参数细节已经模糊;无法 review——任何变更都是一个人点完就生效,没有第二双眼睛;漂移不可见——有人临时在控制台放行了一个端口排查问题,事后忘了收回,代码和实际状态从此分叉。
基础设施即代码(IaC)解决的就是这三件事。华为云官方提供 Terraform Provider,把资源声明写进 .tf 文件,plan 看差异、apply 落地、state 记录真实状态。
环境准备:Provider 与认证
先装 Terraform(1.5 以上都可用),然后建一个目录,写 provider.tf:
terraform {
required_providers {
huaweicloud = {
source = "huaweicloud/huaweicloud"
version = "~> 1.60"
}
}
}
provider "huaweicloud" {
region = "cn-south-1"
}
认证信息不要写进文件。推荐走环境变量:
export HW_ACCESS_KEY="你的 AK"
export HW_SECRET_KEY="你的 SK"
AK/SK 建议单独创建一个 IAM 用户,只授予需要的项目权限,而不是直接用主账号密钥。如果后续跑在 CI 里,可以改用 IAM 的临时凭证或委托,避免长期密钥落到流水线日志里。
一个最小可用栈
从 VPC 开始,因为几乎所有计算资源都要落在某个子网里。下面这段声明了 VPC、子网、安全组和一台 ECS:
resource "huaweicloud_vpc" "main" {
name = "demo-vpc"
cidr = "192.168.0.0/16"
}
resource "huaweicloud_vpc_subnet" "app" {
name = "demo-subnet-app"
vpc_id = huaweicloud_vpc.main.id
cidr = "192.168.1.0/24"
gateway_ip = "192.168.1.1"
}
resource "huaweicloud_networking_secgroup" "app" {
name = "demo-sg-app"
description = "app tier"
}
resource "huaweicloud_networking_secgroup_rule" "ssh" {
security_group_id = huaweicloud_networking_secgroup.app.id
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 22
port_range_max = 22
remote_ip_prefix = "10.0.0.0/8"
}
注意这里有两个刻意的选择:安全组只放行内网来源的 22 端口,公网访问走堡垒机或跳板;子网 CIDR 和 VPC CIDR 留足了余量,后面加子网不用重建。
ECS 的定义里,image_id、flavor_id 这类 ID 不要手抄,用 data 源去查,可读性和可移植性都会好很多:
data "huaweicloud_images_image" "ubuntu" {
name = "Ubuntu 22.04 server 64bit"
most_recent = true
}
resource "huaweicloud_compute_instance" "app" {
name = "demo-app-01"
image_id = data.huaweicloud_images_image.ubuntu.id
flavor_id = "s6.large.2"
availability_zone = "cn-south-1a"
security_group_ids = [huaweicloud_networking_secgroup.app.id]
network {
uuid = huaweicloud_vpc_subnet.app.id
}
}
state 放在哪里
Terraform 的 terraform.tfstate 记录了"代码里的资源"和"云上真实资源"的映射,是整个体系的地基。默认放本地,一个人用没问题,两个人以上就会出事:谁先 apply,谁的 state 就是最新的,另一个人的 plan 会显示一堆莫名其妙的差异。
标准做法是放到 OBS 里并开启状态锁:
terraform {
backend "obs" {
bucket = "my-tfstate"
key = "prod/network/terraform.tfstate"
region = "cn-south-1"
}
}
bucket 一定要开版本控制。state 文件损坏或被误删时,历史版本是唯一的退路。另外按模块拆 key(网络一个、计算一个),别把所有资源塞进同一个 state——一次 plan 要刷新几十个资源,慢且风险集中。
四个容易踩的坑
一、密钥硬编码。 最常见的错误是把 AK/SK 写进 provider.tf 然后提交到仓库。一旦推上去,密钥就等同于公开,必须立刻轮换。
二、destroy 顺序。 删 VPC 时如果子网里还有 ECS,接口会直接报错。Terraform 靠依赖关系推导顺序,但通过 data 源或手工填 ID 建立的隐式依赖它看不到,必要时用 depends_on 显式声明。
三、改了代码不等于改了云上。 有人图快在控制台改配置,下次 plan 会显示要把配置改回去。要么接受"代码是唯一事实来源",要么先把控制台的改动补回代码,不要两边同时改。
四、生产环境直接 apply。 plan 的输出必须有人看。删一台 ECS 在 plan 里只是几行减号,在业务上是事故。生产环境建议加人工确认环节,或用 -target 分批推进。
落地节奏
不建议一次性把存量环境全搬进代码。比较稳的路径是:先拿一套新环境从零用 Terraform 建起来,跑通完整生命周期;再把存量资源用 import 逐个纳管,每纳管一个就 plan 一次,确认输出是"无变更"再继续。看到"无变更"这三个字,才说明代码和现实真正对齐了。
IaC 的价值不在第一次写完,而在第十次变更时——你打开 PR,看到的是三个文件的 diff,而不是一段"我改了下安全组"的口头描述。
- 点赞
- 收藏
- 关注作者
评论(0)