深色模式
Terraform 模块:封装可复用资源
摘要:一个项目写十遍同样的资源定义,就该抽模块了。本文演示如何把一组资源封装成本地模块、声明输入输出、在多环境复用,以及如何安全引用公开模块。
适用环境
- 已安装 Terraform 并有可跑项目
- 存在至少两处重复的资源定义,或计划在多环境复用
操作步骤
1. 模块结构
text
modules/webserver/
├── main.tf # 资源定义
├── variables.tf # 输入
├── outputs.tf # 输出
└── README.md1
2
3
4
5
2
3
4
5
一个目录只要含 .tf 文件就是模块,根目录本身也是 root module。
2. 编写模块
bash
mkdir -p ~/tf-demo/modules/webserver && cd ~/tf-demo/modules/webserver
cat > variables.tf <<'EOF'
variable "name" { type = string }
variable "instance_type" { type = string, default = "t3.micro" }
variable "tags" { type = map(string), default = {} }
EOF
cat > main.tf <<'EOF'
data "aws_ami" "al2023" {
most_recent = true
owners = ["amazon"]
filter { name = "name", values = ["al2023-ami-*-x86_64"] }
}
resource "aws_instance" "this" {
ami = data.aws_ami.al2023.id
instance_type = var.instance_type
tags = merge(var.tags, { Name = var.name })
}
EOF
cat > outputs.tf <<'EOF'
output "id" { value = aws_instance.this.id }
output "public_ip" { value = aws_instance.this.public_ip }
EOF1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
3. 调用与批量创建
hcl
module "web_prod" {
source = "./modules/webserver"
name = "prod-web"
instance_type = "t3.small"
tags = { Env = "prod" }
}
module "web" {
source = "./modules/webserver"
for_each = toset(["dev", "staging", "prod"])
name = "${each.key}-web"
instance_type = each.key == "prod" ? "t3.small" : "t3.micro"
}
output "prod_ip" { value = module.web_prod.public_ip }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
用 for_each 时引用变成 map:module.web["prod"].public_ip。
4. 引用公开模块并固定版本
hcl
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.8.1"
name = "my-vpc"
cidr = "10.0.0.0/16"
}1
2
3
4
5
6
2
3
4
5
6
改模块后需重新 terraform init。
模块内不要写 provider 块
provider 只在 root module 配置,子模块继承。模块里写 provider 会导致复用困难。
验证
bash
cd ~/tf-demo && terraform init && terraform fmt -recursive && terraform validate
terraform state list # 资源名以 module.web_prod. 开头1
2
2
- [ ] 修改模块一次,两个调用方同时生效
- [ ] 引用公开模块时 version 已固定,
.terraform.lock.hcl已提交
常见坑
改了 source 路径要重新 init
模块 source 变更后未 init 会报 Module not installed。
for_each 改键名会重建资源
把 key 从 dev 改成 develop 会先销毁再新建。改名前确认可重建,或用 moved 块迁移。
模块输出没声明就用不了
子模块属性必须先 output 才能被 root 访问。