从零开始:用 Terraform 在华为云上部署高可用 Web 应用架构
# 从零开始:用 Terraform 在华为云上部署高可用 Web 应用架构
> 本文面向有一定云基础、但刚接触基础设施即代码(IaC)的开发者。我们将用 Terraform 在华为云上一步到位地部署一套包含 VPC、子网、安全组、弹性负载均衡(ELB)和多台 ECS 的高可用 Web 应用架构——并解释每一行代码背后的含义。
## 为什么选择 Terraform?
如果你过去都是在控制台里手动点鼠标创建云资源,可能遇到过这些场景:
- 环境搭好了,想再复制一套测试环境,又得从头点一遍
- 团队来了新人,问他"这套架构怎么搭的",谁也说不清
- 手滑删错了一个资源,排查半天才知道影响范围
**基础设施即代码(Infrastructure as Code, IaC)** 就是解决这些问题的思路:把基础设施用代码描述出来,像管理应用代码一样管理基础设施——版本控制、代码审查、一键复现。
Terraform 是目前最主流的 IaC 工具之一,华为云提供了官方 Provider(`huaweicloud`),支持 200+ 种资源类型,覆盖计算、网络、存储、数据库等核心服务。
## 我们要部署什么?
一套经典的高可用 Web 应用架构:
```
┌─────────────┐
│ ELB (公网) │
│ 负载均衡器 │
└──────┬──────┘
│
┌────────────┼────────────┐
│ │ │
┌─────┴─────┐ ┌───┴─────┐ ┌───┴─────┐
│ ECS-1 │ │ ECS-2 │ │ ECS-3 │
│ Web应用 │ │ Web应用 │ │ Web应用 │
└─────┬─────┘ └───┬─────┘ └───┬─────┘
│ │ │
└────────────┼────────────┘
│
┌──────┴──────┐
│ VPC 内网子网 │
│ 172.16.0.0/24│
└─────────────┘
```
**架构要点:**
| 组件 | 作用 | 高可用体现 |
|------|------|-----------|
| VPC + 子网 | 隔离的网络空间 | 资源在内网通信,不直接暴露 |
| 安全组 | 精确控制出入站规则 | 只开放必要端口 |
| ELB | 公网入口,分发流量 | 后端 ECS 故障自动摘除 |
| ECS × 3 | 运行 Web 应用 | 多实例分摊流量,单实例宕机不影响整体 |
## 前置准备
### 1. 安装 Terraform
```bash
# Linux / macOS
curl -fsSL https://releases.hashicorp.com/terraform/1.7.5/terraform_1.7.5_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m).zip -o terraform.zip
unzip terraform.zip && sudo mv terraform /usr/local/bin/
# 验证安装
terraform version
```
> **提示:** 华为云提供了 Terraform 的国内镜像源,如果从 HashiCorp 官方下载慢,可以在 `~/.terraformrc` 中配置镜像加速:
> ```hcl
> provider_installation {
> registry_mirrors {
> "registry.terraform.io" = "https://mirrors.huaweicloud.com/terraform-provider"
> }
> }
> ```
### 2. 准备华为云认证信息
你需要以下信息(在华为云控制台的"我的凭证"页面获取):
- **AK / SK**:访问密钥
- **Region**:区域,如 `cn-north-4`(华北-北京四)
- **Project ID**:项目 ID
建议通过环境变量传入,避免硬编码到代码中:
```bash
export HW_ACCESS_KEY="你的AK"
export HW_SECRET_KEY="你的SK"
export HW_REGION="cn-north-4"
export HW_PROJECT_ID="你的项目ID"
```
## 开始编写 Terraform 代码
### 项目结构
```
huaweicloud-ha-web/
├── main.tf # 主配置:provider + 资源定义
├── variables.tf # 输入变量
└── outputs.tf # 输出信息
```
### 第一步:variables.tf — 定义可复用的参数
把可能变化的值提取成变量,是 Terraform 的基本习惯。这样同一套代码可以部署到不同区域、不同规格,只需改变量值。
```hcl
# variables.tf
variable "region" {
description = "华为云区域"
type = string
default = "cn-north-4"
}
variable "ecs_flavor" {
description = "ECS 规格(CPU/内存)"
type = string
default = "s6.large.2" # 2核4G
}
variable "ecs_count" {
description = "ECS 实例数量"
type = number
default = 3
}
variable "image_id" {
description = "ECS 镜像 ID(EulerOS 2.9)"
type = string
# 请替换为你账号下可用的镜像 ID,可通过控制台或 hcloud CLI 查询
default = "your-image-id-here"
}
variable "admin_password" {
description = "ECS 管理员密码"
type = string
sensitive = true # 标记为敏感值,日志中会脱敏
default = "YourStrongPassword123!"
}
```
> **关于 `sensitive = true`:** 这个标记会让 Terraform 在 plan/apply 的输出中用 `(sensitive value)` 代替明文,避免密码出现在日志里。但注意,state 文件中仍然是明文存储的,所以 state 文件本身也要妥善保管。
### 第二步:main.tf — 核心资源配置
这是文章的主体,我们逐块讲解。
#### 2.1 Provider 配置
```hcl
# main.tf
terraform {
required_providers {
huaweicloud = {
source = "huaweicloud/huaweicloud"
version = ">= 1.50.0"
}
}
}
provider "huaweicloud" {
region = var.region
# AK/SK 通过环境变量传入,不写在这里
}
```
**为什么 AK/SK 不写在代码里?** 代码会进版本控制系统(Git),密钥不应该跟着代码走。通过环境变量传入是最基本的安全实践。
#### 2.2 VPC 和子网
```hcl
# VPC — 虚拟私有云,相当于你在云上的一块隔离网络
resource "huaweicloud_vpc" "main" {
name = "ha-web-vpc"
cidr = "172.16.0.0/16"
}
# 子网 — VPC 内的更细分段,ECS 都部署在子网内
resource "huaweicloud_vpc_subnet" "web" {
name = "ha-web-subnet"
vpc_id = huaweicloud_vpc.main.id
cidr = "172.16.0.0/24"
gateway_ip = "172.16.0.1"
}
```
**VPC 和子网是什么关系?** 打个比方:VPC 是你租的一整栋楼,子网是楼里的一层。CIDR `172.16.0.0/16` 定义了整栋楼能用的地址范围,`172.16.0.0/24` 是其中一层的地址段。
#### 2.3 安全组
```hcl
# 安全组 — 控制 ECS 的出入站流量,相当于贴在门上的访问规则
resource "huaweicloud_networking_secgroup" "web" {
name = "ha-web-sg"
description = "安全组:允许 ELB 转发的 HTTP 流量,允许 SSH 管理"
}
# 入站规则:允许 80 端口(HTTP)
resource "huaweicloud_networking_secgroup_rule" "allow_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
}
# 入站规则:允许 22 端口(SSH)
# 注意:生产环境建议限制来源 IP,不要对全网开放
resource "huaweicloud_networking_secgroup_rule" "allow_ssh" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 22
port_range_max = 22
remote_ip_prefix = "0.0.0.0/0" # 生产环境请改为你的管理 IP,如 203.0.113.10/32
security_group_id = huaweicloud_networking_secgroup.web.id
}
```
> **⚠️ 安全提醒:** 上面的 SSH 规则对 `0.0.0.0/0` 开放,这在教程中方便演示,但在生产环境中是**高风险**的3——相当于把你服务器的管理端口对全世界开放。正确做法是只允许你的堡垒机或管理 IP 访问,把 `remote_ip_prefix` 改成具体的 IP 地址,如 `203.0.113.10/32`。
#### 2.4 弹性负载均衡(ELB)
```hcl
# ELB 负载均衡器 — 公网入口,将流量分发到后端多台 ECS
resource "huaweicloud_elb_loadbalancer" "web" {
name = "ha-web-elb"
vpc_id = huaweicloud_vpc.main.id
network_type = "external" # 对外提供公网访问
admin_state_up = true
}
# ELB 监听器 — 监听 80 端口的 HTTP 流量
resource "huaweicloud_elb_listener" "http" {
name = "ha-web-listener"
protocol = "HTTP"
protocol_port = 80
loadbalancer_id = huaweicloud_elb_loadbalancer.web.id
}
# 后端服务器组 — ECS 集群
resource "huaweicloud_elb_pool" "web" {
name = "ha-web-pool"
protocol = "HTTP"
lb_algorithm = "ROUND_ROBIN" # 轮询,流量均匀分配
listener_id = huaweicloud_elb_listener.http.id
}
# 健康检查 — ELB 定期检查后端 ECS 是否正常,异常的自动摘除
resource "huaweicloud_elb_monitor" "health" {
pool_id = huaweicloud_elb_pool.web.id
protocol = "HTTP"
port = 80
path = "/"
interval = 10 # 每 10 秒检查一次
timeout = 5 # 超时 5 秒
max_retries = 3 # 连续 3 次失败才标记为异常
}
```
**健康检查为什么重要?** 假设 ECS-2 因为应用崩溃无法响应,如果没有健康检查,ELB 还会往它转发流量,用户就会偶尔碰到报错。有了健康检查,ELB 在 30 秒内(`interval × max_retries`)就会把异常实例摘除,用户完全无感知。
#### 2.5 ECS 集群
```hcl
# ECS 实例 — 用 count 创建多台,实现高可用
resource "huaweicloud_compute_instance" "web" {
count = var.ecs_count # 默认 3 台
name = "ha-web-ecs-${count.index + 1}"
flavor_id = var.ecs_flavor
image_id = var.image_id
admin_pass = var.admin_password
security_group_ids = [huaweicloud_networking_secgroup.web.id]
# 网络配置:接入子网,自动分配内网 IP
network {
uuid = huaweicloud_vpc_subnet.web.id
}
tags = {
app = "ha-web"
role = "web-server"
managed = "terraform"
}
}
# 将 ECS 加入 ELB 后端服务器组
resource "huaweicloud_elb_member" "web" {
count = var.ecs_count
pool_id = huaweicloud_elb_pool.web.id
address = huaweicloud_compute_instance.web[count.index].access_ip_v4
protocol_port = 80
weight = 1
}
```
**`count` 是什么?** 这是 Terraform 的元参数(meta-argument)。`count = 3` 意味着这个 resource 会创建 3 个实例,通过 `count.index`(0, 1, 2)区分它们。改一个数字就能调整集群规模——这就是 IaC 的威力。
#### 2.6 EIP(弹性公网 IP)
```hcl
# 给 ELB 绑定一个弹性公网 IP,让外部能访问
resource "huaweicloud_vpc_eip" "elb" {
publicip {
type = "5_bgp" # BGP 多线,网络质量更好
}
bandwidth {
name = "ha-web-bw"
size = 5 # 5 Mbit/s
share_type = "PER"
charge_mode = "traffic"
}
}
```
### 第三步:outputs.tf — 输出关键信息
部署完成后,我们想知道 ELB 的公网 IP 是多少,方便验证。
```hcl
# outputs.tf
output "elb_public_ip" {
description = "ELB 公网访问 IP"
value = huaweicloud_vpc_eip.elb.address
}
output "ecs_private_ips" {
description = "ECS 内网 IP 列表"
value = huaweicloud_compute_instance.web[*].access_ip_v4
}
output "vpc_id" {
description = "VPC ID"
value = huaweicloud_vpc.main.id
}
```
## 执行部署
### 1. 初始化
```bash
terraform init
```
这一步会下载华为云 Provider 插件。如果配置了华为云镜像源,下载速度会快很多。
### 2. 预览变更
```bash
terraform plan
```
**这是 Terraform 最重要的安全机制之一。** `plan` 会告诉你它准备创建、修改、删除哪些资源,但不会真正执行。你可以在执行前检查是否符合预期:
```
Plan: 14 to add, 0 to change, 0 to destroy.
# huaweicloud_vpc.main will be created
# huaweicloud_vpc_subnet.web will be created
# huaweicloud_networking_secgroup.web will be created
# huaweicloud_elb_loadbalancer.web will be created
# huaweicloud_compute_instance.web[0] will be created
# huaweicloud_compute_instance.web[1] will be created
# huaweicloud_compute_instance.web[2] will be created
...
```
### 3. 正式部署
```bash
terraform apply
```
输入 `yes` 确认后,Terraform 会按照依赖关系自动编排创建顺序。整个过程通常 3-5 分钟。
部署完成后,你会看到输出信息:
```
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
Outputs:
elb_public_ip = "114.116.xxx.xxx"
ecs_private_ips = [
"172.16.0.10",
"172.16.0.11",
"172.16.0.12",
]
```
### 4. 验证
用浏览器或 curl 访问 ELB 的公网 IP:
```bash
curl http://114.116.xxx.xxx
```
如果你在 ECS 上部署了 Web 应用,应该能收到响应。多次请求,可以通过查看 ECS 日志确认流量被轮询分发到了不同实例。
## 日常运维:改一个数字就能扩容
假设你的应用流量增长,需要从 3 台扩到 5 台。用传统方式,你得去控制台手动创建 2 台 ECS、配置网络、加入负载均衡。用 Terraform:
```bash
# 修改变量
export TF_VAR_ecs_count=5
# 预览变更 — 只会新增 2 台,已有的不受影响
terraform plan
# Plan: 2 to add, 0 to change, 0 to destroy.
# 执行
terraform apply
```
**这就是 IaC 的核心价值:基础设施的变更和应用的变更一样,可预览、可追溯、可回滚。**
## 清理资源
验证完成后,记得清理资源,避免产生不必要的费用:
```bash
terraform destroy
```
输入 `yes` 确认,Terraform 会按照依赖关系的逆序依次删除所有资源。
> **注意:** `destroy` 会删除所有 Terraform 管理的资源,且不可逆。执行前请确认环境无误。
## 回顾与思考
### 我们做了什么
用约 120 行 Terraform 代码,部署了一套包含 14 个资源的高可用 Web 应用架构:VPC、子网、安全组、安全组规则、ELB(负载均衡器 + 监听器 + 后端组 + 健康检查)、3 台 ECS、EIP 和带宽。
### 为什么这比手动操作好
| 对比维度 | 控制台手动操作 | Terraform IaC |
|---------|-------------|---------------|
| 可复现性 | 靠记忆和文档,容易遗漏 | 代码即文档,`terraform apply` 一键复现 |
| 可审查性 | 变更无记录,出了问题难追溯 | 每次变更都有 diff,可走 Code Review |
| 团队协作 | "只有张三知道怎么搭的" | 代码在 Git 里,人人可读可改 |
| 扩缩容 | 手动逐台操作,容易出错 | 改一个数字,plan 确认,apply 生效 |
| 环境一致性 | 开发/测试/生产容易不一致 | 同一套代码,不同变量值,天然一致 |
### 进阶方向
本文是一个入门教程,实际生产环境还需要考虑:
1. **多可用区(AZ)部署**:将 ECS 分布在不同 AZ,整个 AZ 故障时仍可服务
2. **自动伸缩(AS)**:根据 CPU/内存指标自动增减 ECS 实例数
3. **数据库层**:加入 RDS 作为后端存储,配置只读实例分担读流量
4. **CI/CD 集成**:把 Terraform 代码纳入 GitLab CI / CodeArts 流水线,实现基础设施的持续交付
5. **State 远程存储**:将 state 文件存到 OBS,支持团队多人协作和状态锁定
### 写在最后
从"在控制台点鼠标"到"用代码描述基础设施",这个转变不需要你一次性掌握所有东西。从本文这样一个小项目开始,先把一套环境用 Terraform 管起来,体验 `plan → apply → destroy` 的完整流程,再逐步加入更多资源、更多环境。
当你发现改一行代码、敲一个命令就能完成过去半小时的手动操作时,你就回不去了。
---
**相关链接:**
- [Terraform 官方文档](https://developer.hashicorp.com/terraform/docs)
- [华为云 Terraform Provider](https://registry.terraform.io/providers/huaweicloud/huaweicloud/latest/docs)
- [华为云 Terraform 实践最佳实践](https://support.huaweicloud.com/terraform/index.html)
> 本文示例代码已开源,欢迎 Star 和 PR。如果在实践过程中遇到问题,欢迎在评论区交流。
- 点赞
- 收藏
- 关注作者
评论(0)