用 Terraform 在华为云上一键创建 VPC + ECS + EIP:从零到一的 IaC 实战
用 Terraform 在华为云上一键创建 VPC + ECS + EIP:从零到一的 IaC 实战
还在控制台点点点建资源?每次环境重建都要手动操作一遍?本文带你用 Terraform 把华为云上最常见的 VPC + ECS + EIP 组合变成一份代码,
terraform apply一条命令搞定,删环境也只需terraform destroy。
为什么用 Terraform
如果你有过这样的经历——
- 测试环境用完想删,结果漏删了一个 EIP,月底账单多出几十块
- 同一套环境要搭三遍(开发、测试、预发),每次都在控制台重复操作
- 同事问你"这台 ECS 的安全组规则加了哪些端口",你翻了半天控制台才找到
——那 Terraform 就是为你准备的。
Terraform 是 HashiCorp 出的基础设施即代码(IaC)工具。你用一种声明式语言描述"我想要什么样的云资源",Terraform 负责调用云平台的 API 把它们创建出来,并且记住这些资源的状态(叫 state)。下次改了代码再 apply,它只变更差异部分;想销毁,一条 destroy 全部干净回收。
本文以华为云为例,从零搭建一个最小可用的网络 + 服务器 + 公网 IP。
前置准备
1. 安装 Terraform
华为云提供了官方镜像源,国内下载不走国外网络:
# 下载并安装(以 Linux 为例)
curl -o terraform.zip https://mirrors.huaweicloud.com/terraform/1.8.5/terraform_1.8.5_linux_arm64.zip
unzip terraform.zip
mv terraform /usr/local/bin/
terraform version
Windows / Mac 用户把 linux_arm64 换成 windows_amd64 / darwin_arm64 即可。
2. 获取 AK / SK
登录华为云控制台 → 右上角头像 → “我的凭证” → “访问密钥” → 新建密钥。你会得到一个 AK(Access Key ID)和一个 SK(Secret Access Key),SK 只在创建时显示一次,务必保存好。
⚠️ 安全提醒:AK/SK 是你账号的长期凭证,泄露等于账号沦陷。不要写死在代码里提交到 Git,推荐用环境变量传入。
3. 确认区域和可用区
本文以 cn-north-4(华北-北京四)为例,可用区用 cn-north-4a。你可以根据自己资源所在区域调整。
开始写代码
建一个项目目录:
mkdir huaweicloud-ecs-demo && cd huaweicloud-ecs-demo
文件一:provider.tf —— 告诉 Terraform 用哪个云
terraform {
required_providers {
huaweicloud = {
source = "huaweicloud/huaweicloud"
version = ">= 1.60.0"
}
}
}
provider "huaweicloud" {
region = "cn-north-4"
# AK/SK 通过环境变量传入,不写死在代码里
# export HW_ACCESS_KEY="你的AK"
# export HW_SECRET_KEY="你的SK"
}
这段在做什么:
required_providers声明我们要用华为云的 Terraform Provider(插件),它会去 HashiCorp 的 registry 下载。华为云也提供了 registry 镜像,可以在terraform块里加provider_mirror配置加速。provider "huaweicloud"配置认证信息。region直接写死,AK/SK 通过环境变量HW_ACCESS_KEY/HW_SECRET_KEY传入——这是推荐做法,避免凭证泄露到代码仓库。
文件二:variables.tf —— 把可变参数抽出来
variable "ecs_name" {
description = "ECS 实例名称"
type = string
default = "demo-ecs"
}
variable "ecs_password" {
description = "ECS root 用户密码"
type = string
sensitive = true
# 密码要求:8-26 位,至少包含大写、小写、数字、特殊字符各一种
}
variable "flavor_id" {
description = "ECS 规格ID"
type = string
default = "s6.large.2" # 2核4G
}
variable "image_id" {
description = "镜像ID,这里用 Huawei Cloud EulerOS 2.12 公共镜像"
type = string
default = "your-image-id-here" # 替换成你区域的实际镜像ID
}
为什么要抽变量: 同一套代码,改个变量值就能给不同环境用——开发环境用小规格 s6.large.2,生产环境换成 s6.xlarge.4,不用动主体代码。sensitive = true 让密码在 terraform plan 输出中显示为 (sensitive value),不会明文打印。
💡 怎么查镜像 ID:控制台 → ECS → 镜像 → 找到你要的公共镜像,复制 ID。或者用
hcloudCLI:hcloud IMS ShowImages --images.image_type=public。
文件三:network.tf —— 网络基础设施
# VPC
resource "huaweicloud_vpc" "demo" {
name = "demo-vpc"
cidr = "192.168.0.0/16"
}
# 子网
resource "huaweicloud_vpc_subnet" "demo" {
name = "demo-subnet"
vpc_id = huaweicloud_vpc.demo.id
cidr = "192.168.0.0/24"
gateway_ip = "192.168.0.1"
# 指定可用区
availability_zone = "cn-north-4a"
}
# 安全组
resource "huaweicloud_networking_secgroup" "demo" {
name = "demo-secgroup"
description = "安全组:仅放行 SSH(22)端口"
}
# 安全组规则:放行 SSH
resource "huaweicloud_networking_secgroup_rule" "ssh" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 22
port_range_max = 22
remote_ip_prefix = "0.0.0.0/0"
security_group_id = huaweicloud_networking_secgroup.demo.id
}
# 安全组规则:放行 HTTP(如果你要跑 Web 服务,按需开放)
resource "huaweicloud_networking_secgroup_rule" "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.demo.id
}
逐块解释:
| 资源 | 云上对应 | 关键参数说明 |
|---|---|---|
huaweicloud_vpc |
虚拟私有云 | cidr 是整个 VPC 的网段,用 /16 给子网留足空间 |
huaweicloud_vpc_subnet |
子网 | 必须在 VPC 的 CIDR 内,gateway_ip 通常是网段第一个地址 |
huaweicloud_networking_secgroup |
安全组 | 相当于云级别的防火墙,默认全部拒绝,需要逐条放行 |
..._secgroup_rule |
安全组规则 | ingress = 入方向,remote_ip_prefix 控制来源 IP |
⚠️ 安全提醒:这里 SSH 放行了
0.0.0.0/0(全网可访问),仅适合测试环境。生产环境建议改为你的办公出口 IP,比如203.0.113.10/32。或者更好的做法:用华为云的 NAT 网关 + 跳板机,不直接对公网开放 22 端口。
文件四:compute.tf —— ECS 和 EIP
# 弹性公网 IP
resource "huaweicloud_vpc_eip" "demo" {
publicip {
type = "5_bgp" # BGP 类型弹性公网IP
}
bandwidth {
name = "demo-bandwidth"
size = 5 # 5 Mbit/s
share_type = "PER"
charge_mode = "traffic" # 按流量计费
}
}
# ECS 实例
resource "huaweicloud_compute_instance" "demo" {
name = var.ecs_name
flavor_id = var.flavor_id
image_id = var.image_id
availability_zone = "cn-north-4a"
admin_pass = var.ecs_password
# 绑定网络
network {
uuid = huaweicloud_vpc_subnet.demo.id
}
# 绑定安全组
security_group_ids = [
huaweicloud_networking_secgroup.demo.id
]
# 绑定 EIP
eip_id = huaweicloud_vpc_eip.demo.id
# 系统盘
system_disk_type = "SAS" # 高 IO 类型
system_disk_size = 40 # 40 GB
tags = {
Environment = "demo"
ManagedBy = "terraform"
}
}
几个值得注意的点:
eip_id:ECS 创建时直接绑定 EIP,不用事后手动关联。注意 EIP 资源要先于 ECS 创建——Terraform 会根据引用关系自动推断依赖顺序,你不需要手动写depends_on。system_disk_type:华为云磁盘类型有SAS(高 IO)、SSD(超高 IO)、GPSSD(通用型 SSD)、ESSD(极速型 SSD)。测试环境SAS够用,生产数据库建议SSD或ESSD。tags:给资源打标签是好习惯,后续用标签筛选资源、分摊成本都靠它。ManagedBy = terraform标记这是 IaC 管理的,提醒同事别手动改。
文件五:outputs.tf —— 输出关键信息
output "ecs_public_ip" {
description = "ECS 公网 IP"
value = huaweicloud_vpc_eip.demo.address
}
output "ecs_private_ip" {
description = "ECS 私网 IP"
value = huaweicloud_compute_instance.demo.network[0].fixed_ip_v4
}
output "vpc_id" {
description = "VPC ID"
value = huaweicloud_vpc.demo.id
}
apply 完成后这些值会直接打印在终端,不用再去控制台翻。
跑起来
第一步:设置环境变量
export HW_ACCESS_KEY="你的AK"
export HW_SECRET_KEY="你的SK"
export TF_VAR_ecs_password="你的密码" # 满足复杂度要求
第二步:初始化
terraform init
这一步会下载华为云 Provider 插件。如果国内网络慢,配置 provider 镜像:
# 在 ~/.terraformrc 或 terraform 配置中
provider_installation {
dev_overrides {}
direct {
exclude = ["huaweicloud/huaweicloud"]
}
filesystem_mirror {
path = "/usr/local/share/terraform/providers"
include = ["huaweicloud/huaweicloud"]
}
}
第三步:预览执行计划
terraform plan
Terraform 会告诉你它将要创建哪些资源,但不会真的创建。仔细看一遍输出,确认无误:
Plan: 7 to add, 0 to change, 0 to destroy.
# huaweicloud_vpc.demo will be created
# huaweicloud_vpc_subnet.demo will be created
# huaweicloud_networking_secgroup.demo will be created
# huaweicloud_networking_secgroup_rule.ssh will be created
# huaweicloud_networking_secgroup_rule.http will be created
# huaweicloud_vpc_eip.demo will be created
# huaweicloud_compute_instance.demo will be created
7 个资源,符合预期:1 VPC + 1 子网 + 1 安全组 + 2 安全组规则 + 1 EIP + 1 ECS。
第四步:正式创建
terraform apply
输入 yes 确认。大约 1-2 分钟后,你会看到 outputs 打印出公网 IP:
Apply complete! Resources: 7 added, 0 changed, 0 destroyed.
Outputs:
ecs_public_ip = "121.xxx.xxx.xxx"
ecs_private_ip = "192.168.0.123"
vpc_id = "vpc-xxxxx"
用 SSH 连上去验证:
ssh root@121.xxx.xxx.xxx
第五步(用完后):销毁
terraform destroy
输入 yes,7 个资源全部干净删除,不会漏删 EIP 产生持续计费。这就是 IaC 最大的好处之一:环境即代码,创建和销毁完全对称。
进阶:把状态存到 OBS
默认 state 文件存在本地 terraform.tfstate,团队协作时不方便。华为云 OBS 可以作为 Terraform 的远程 backend:
terraform {
backend "s3" {
endpoint = "obs.cn-north-4.myhuaweicloud.com"
bucket = "my-terraform-state"
key = "ecs-demo/terraform.tfstate"
region = "cn-north-4"
# OBS 兼容 S3 协议,Terraform 的 s3 backend 可以直接用
}
# ... required_providers 不变
}
这样团队成员共享同一份 state,谁改了资源,其他人 terraform plan 能立刻看到差异。
常见踩坑记录
1. image_id 找不到
镜像 ID 是区域相关的,cn-north-4 的镜像在 cn-east-3 用不了。确认你用的镜像在你配置的 region 下可用。
2. 密码不符合要求
华为云 ECS 密码规则:8-26 位,至少包含大写字母、小写字母、数字、特殊字符(!@$%^-_=+[{}]:,./?)各一种。不符合会报 Invalid password。
3. 可用区没有该规格
不是所有可用区都有所有规格。用 hcloud ECS ListFlavors --availability_zone=cn-north-4a 确认你要的 flavor 在目标可用区有库存。
4. 改了安全组规则没生效
Terraform 管理的安全组规则,如果你在控制台手动加了一条规则,再 terraform apply 时 Terraform 不会动那条手动加的(它只管自己 state 里记录的)。但如果你手动改了 Terraform 管理的规则,terraform plan 会显示 drift,apply 会覆盖回代码定义的状态。建议:一旦用 Terraform 管理资源,就不要再手动在控制台改同一资源。
小结
| 传统方式 | Terraform 方式 |
|---|---|
| 控制台逐个创建,容易漏配 | 一份代码描述全部,plan 预览差异 |
| 删除靠记忆,漏删就持续计费 | destroy 一键干净回收 |
| 环境复制靠重复操作 | 改变量值,同一套代码复用 |
| 变更没有审计记录 | 代码版本管理 = 基础设施变更审计 |
本文的完整代码已经能跑通一个最小可用的华为云 ECS 环境。下一步你可以尝试:
- 加一个 RDS 数据库,用
huaweicloud_rds_instance资源 - 加一个 ELB 负载均衡,把流量分发到多台 ECS
- 用 Terraform Module 把这套封装成可复用模块
IaC 的核心理念就一句话:基础设施是代码,代码可以版本化、可以复用、可以审计。 从今天开始,把你的云资源交给 Terraform 管理吧。
- 点赞
- 收藏
- 关注作者
评论(0)