从手动运维到基础设施即代码:华为云 Terraform 实战避坑指南
如果你还在控制台里点点点,手动创建 VPC、子网、安全组、ECS……那你一定经历过这些痛苦:
- 测试环境要重建,又得从头点一遍
- 同事问"线上安全组开了哪些端口",你打开控制台翻了半天
- 手滑删错了资源,连夜写事故报告
基础设施即代码(Infrastructure as Code,简称 IaC)就是解决这些问题的。用 Terraform 把基础设施描述成代码,一条命令创建,一条命令销毁,版本可控,复用性强。
本文不讲 Terraform 入门语法(官方文档已经很详细了),只讲我在华为云上用 Terraform 实战踩过的坑,以及怎么避开它们。
一、provider 配置:别把 AK/SK 写进代码里
最常见的第一个坑,就是直接把 AK/SK 明文写进 .tf 文件:
provider "huaweicloud" {
access_key = "AKXXXXXXXXXXXXXX"
secret_key = "SKXXXXXXXXXXXXXXXXXXXXXXXXXX"
region = "cn-north-4"
}
这段代码能跑,但一旦提交到 Git,你的密钥就泄露了。
正确做法:用环境变量或 profile 方式:
provider "huaweicloud" {
region = "cn-north-4"
# AK/SK 通过环境变量 HW_ACCESS_KEY / HW_SECRET_KEY 传入
# 或者使用 credentials 文件中的 profile
}
在执行 terraform plan 之前,先 export 环境变量:
export HW_ACCESS_KEY="你的AK"
export HW_SECRET_KEY="你的SK"
这样代码可以安全提交,密钥只存在本地环境。
二、VPC 和子网:别忘了 IPv6 和可用区
很多人创建 VPC 时只配了 IPv4 CIDR,后来业务需要 IPv6,又得重建。
建议一开始就考虑清楚:
resource "huaweicloud_vpc" "main" {
name = "vpc-prod"
cidr = "192.168.0.0/16"
enable_ipv6 = true # 提前开启,避免后期重建
}
resource "huaweicloud_vpc_subnet" "web" {
name = "subnet-web"
vpc_id = huaweicloud_vpc.main.id
cidr = "192.168.1.0/24"
gateway_ip = "192.168.1.1"
# 指定可用区,多子网分布在不同 AZ 实现高可用
availability_zone = "cn-north-4a"
}
坑点:华为云不同区域可用区名称不一样,比如 cn-north-4 是 4a/4b,cn-east-3 是 3a/3b。写代码前先确认目标区域的可用区列表,别想当然。
三、安全组:最小权限原则不是一句口号
我见过太多安全组直接开 0.0.0.0/0 全端口,这在测试环境也许无所谓,但一旦带到生产就是灾难。
分层设计安全组:
# Web 层安全组:只开 80 和 443
resource "huaweicloud_networking_secgroup" "web" {
name = "sg-web"
description = "Web layer security group"
}
resource "huaweicloud_networking_secgroup_rule" "web_http" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 80
port_range_max = 80
remote_ip_prefix = "0.0.0.0/0"
security_group_id = huaweicloud_networking_secgroup.web.id
}
resource "huaweicloud_networking_secgroup_rule" "web_https" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 443
port_range_max = 443
remote_ip_prefix = "0.0.0.0/0"
security_group_id = huaweicloud_networking_secgroup.web.id
}
# 数据库层安全组:只允许 Web 层访问 3306
resource "huaweicloud_networking_secgroup" "db" {
name = "sg-db"
description = "Database layer security group"
}
resource "huaweicloud_networking_secgroup_rule" "db_mysql" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 3306
port_range_max = 3306
remote_group_id = huaweicloud_networking_secgroup.web.id # 只允许 Web 层访问
security_group_id = huaweicloud_networking_secgroup.db.id
}
关键点:数据库安全组的入站规则用 remote_group_id 引用 Web 层安全组,而不是写死 IP。这样 Web 层扩容时新 ECS 自动就能访问数据库,不用改安全组规则。
四、ECS 创建:镜像 ID 会变,别写死
新手常犯的错误是直接写死镜像 ID:
# ❌ 错误做法
resource "huaweicloud_compute_instance" "web" {
image_id = "a1b2c3d4-xxxx-xxxx-xxxx-xxxxxxxxxxxx" # 这个 ID 会过期!
...
}
华为云公共镜像会定期更新,旧镜像 ID 可能被下架。
正确做法:用 data source 动态查询:
data "huaweicloud_images_image" "ubuntu" {
name = "Ubuntu 22.04 server 64bit"
most_recent = true
}
resource "huaweicloud_compute_instance" "web" {
name = "web-server-01"
image_id = data.huaweicloud_images_image.ubuntu.id
flavor_id = "s6.large.2"
...
}
most_recent = true 会自动取最新版本,不用手动维护镜像 ID。
五、状态文件管理:本地 state 是定时炸弹
Terraform 默认把状态存在本地 terraform.tfstate 文件里。单人开发没问题,团队协作时这是灾难:
- 两个人同时 apply,state 冲突
- 本地文件误删,基础设施"失联",只能手动 import
- state 文件里明文存着密码等敏感信息
建议用 OBS 做远程后端:
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "cn-north-4"
endpoint = "obs.cn-north-4.myhuaweicloud.com"
# OBS 兼容 S3 协议,Terraform 可以直接用
}
}
配合 DynamoDB 做状态锁(华为云对应 DCS 或自建方案),防止并发写入。
六、destroy 是不可逆的:养成 plan 习惯
terraform destroy 会删除所有资源,没有回收站。我见过有人把生产环境的 state 和测试环境搞混,一条 destroy 把线上全删了。
养成三个习惯:
- 先 plan 再 apply:
terraform plan会告诉你哪些资源要创建、修改、删除,看清楚再执行 - 加 prevent_destroy 生命周期保护:
resource "huaweicloud_compute_instance" "prod_db" {
name = "prod-mysql-master"
...
lifecycle {
prevent_destroy = true # terraform destroy 时会拒绝删除此资源
}
}
- 不同环境用不同的 state 目录:
environments/dev/、environments/prod/物理隔离,别用一个 state 文件管所有环境。
七、变量管理:别把所有东西都写死
好的 IaC 代码应该是参数化的。用 variables.tf 管理输入,main.tf 管理资源,outputs.tf 管理输出:
# variables.tf
variable "env" {
type = string
default = "dev"
}
variable "instance_count" {
type = number
default = 2
}
# main.tf
resource "huaweicloud_compute_instance" "web" {
count = var.instance_count
name = "web-${var.env}-${count.index + 1}"
...
}
这样切换环境只需要传不同的变量值,不用改代码:
terraform apply -var="env=prod" -var="instance_count=4"
写在最后
从手动运维到 IaC,最大的转变不是工具,而是思维方式:
- 一切皆代码:基础设施和业务代码一样,有版本、有 review、有 CI/CD
- 幂等性:同一个配置 apply 一百次,结果一样,不会创建出重复资源
- 可复现:新人 clone 代码,一条命令就能拉起一套一模一样的环境
Terraform 的学习曲线不算陡,但华为云 provider 的文档有些地方确实不够详细,需要结合实际操作来摸索。希望这些避坑经验能帮你少走弯路。
如果你也在用 Terraform 管理华为云资源,欢迎在评论区交流你的经验和问题。我们一起把踩过的坑填平。
- 点赞
- 收藏
- 关注作者
评论(0)