Terraform的模块及依赖引用
1. 模块(Modules)
1.1. module简介
Terraform 模块是一组位于单个目录中的 Terraform 配置文件,即使是一个包含了一个或多个 .tf 文件的单一目录的简单配置也被视为一个模块。模块是 Terraform 中代码复用的主要方法,它们通过指定可以检索代码的源来重复使用。
模块可以多层嵌套,类似代码中的函数。
Module 就是一组
.tf
文件的集合,用来创建一组相关的基础设施资源。
比如:
- 一个
vpc
模块:创建 VPC、子网、路由表 - 一个
rds
模块:创建数据库实例、安全组 - 一个
eks
模块:创建 Kubernetes 集群
1.2. Module 的基本结构
modules/
└── vpc/
├── main.tf # 资源定义
├── variables.tf # 输入参数
└── outputs.tf # 输出结果
modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
tags = {
Name = var.name
}
}
resource "aws_subnet" "private" {
count = length(var.private_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnets[count.index]
availability_zone = element(var.azs, count.index)
tags = {
Name = "private-${element(var.azs, count.index)}"
}
}
variables.tf
variable "cidr_block" {
type = string
}
variable "name" {
type = string
}
variable "private_subnets" {
type = list(string)
}
variable "azs" {
type = list(string)
}
outputs.tf
output "vpc_id" {
value = aws_vpc.main.id
}
output "private_subnet_ids" {
value = aws_subnet.private[*].id
}
1.3. 在根模块中使用 Module
方法 1:本地模块
module "prod_vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
name = "prod-vpc"
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
azs = ["us-west-2a", "us-west-2b", "us-west-2c"]
}
方法 2:远程模块
module "vpc" {
source = "git::https://github.com/your-org/terraform-modules.git//vpc?ref=v1.0.0"
cidr_block = "10.10.0.0/16"
name = "dev-vpc"
# ... 其他参数
}
支持来源类型:
./path/to/module
— 本地github.com/org/repo//dir
git::https://...
terraform-registry-mirror/internal/modules/vpc
1.4. Module 的输入与输出
1. 输入(Input Variables)
通过 variables.tf
定义参数,在调用时传入。
module "xxx" {
source = "..."
param1 = "value1"
param2 = true
}
2. 输出(Outputs)
其他模块或根配置可以通过 module.<name>.<output>
引用输出值。
# 假设 module.vpc 输出了 vpc_id 和 subnet_ids
resource "aws_instance" "app" {
subnet_id = module.prod_vpc.private_subnet_ids[0]
# ...
}
1.5. 实际使用场景示例
VPC 模块创建网络,RDS 模块使用它的输出来部署数据库。
# main.tf
module "network" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
name = "my-app-network"
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
azs = ["us-west-2a", "us-west-2b"]
}
module "database" {
source = "./modules/rds"
vpc_id = module.network.vpc_id
subnet_ids = module.network.private_subnet_ids
instance_class = "db.t3.micro"
}
2. 资源依赖
Terraform 有两种依赖关系:隐式依赖
(Implicit Dependence)和`显式依赖``(Explicit Dependence)。隐式依赖是 Terraform 已知的,而显式依赖是未知的。
2.1. 隐式依赖(Implicit Dependence)
隐式依赖简单来讲就是对于变量引用的依赖。当一个资源的创建依赖于另一个资源创建后的信息时,需要用到隐式依赖来让 Terraform 知晓依赖关系。
针对隐式依赖关系,Terraform 通过属性值引用赋值的方式来知晓。
2.2. 显式依赖(Explicit Dependence)
显式依赖就是Terraform无法通过变量之间的引用关系推断出来,需要用户明确指出的依赖。可以使用 depends_on 来显式声明依赖关系。无论资源类型是什么,depends_on 可以在模块内使用,该值可以是指向资源的表达式。
2.3. 平级module的变量引用
Terraform 中:Module 之间不能直接访问对方的内部资源或输出,除非通过根模块中显式传递。
但你可以通过 根模块作为“中介”,将一个 module 的输出传给另一个 module 作为输入。
示例:两个平级模块通信
假设我们有两个模块:
vpc
:创建 VPC 和子网eks
:创建 EKS 集群,需要使用 VPC 创建的子网 ID
.
├── main.tf
├── variables.tf
├── outputs.tf
└── modules/
├── vpc/
│ ├── main.tf
│ └── outputs.tf
└── eks/
├── main.tf
└── variables.tf
步骤 1:为 vpc
模块定义输出(modules/vpc/outputs.tf
)
output "private_subnet_ids" {
value = aws_subnet.private[*].id
}
output "vpc_id" {
value = aws_vpc.main.id
}
步骤 2:为 eks
模块定义输入变量(modules/eks/variables.tf
)
variable "vpc_id" {
type = string
}
variable "subnet_ids" {
type = list(string)
}
步骤 3:在根模块中调用并连接两个模块(main.tf
)
# 创建 VPC 模块
module "network" {
source = "./modules/vpc"
# 输入变量...
}
# 创建 EKS 模块,使用 network 模块的输出作为输入
module "cluster" {
source = "./modules/eks"
vpc_id = module.network.vpc_id
subnet_ids = module.network.private_subnet_ids
}
这样就实现了:eks
模块使用了平级 vpc
模块的输出值。
2.4. 父级模块的变量引用
核心原则:Terraform 模块的引用方向是 单向向下的。
🔹 Terraform 只能引用当前模块直接调用的“子模块”的
output
字段。
🔹 不能向上引用父级、也不能横向引用兄弟模块。
🔹 所有跨模块通信都必须通过“调用者”显式传递(通常是根模块)。
依赖必须由“上层模块”显式传递,通过 根模块中转
module "A" {
source = "./modules/a"
}
module "B" {
source = "./modules/b"
# 正确!根模块把 A 的输出传给 B 的输入
vpc_id = module.A.vpc_id
}
2.5. 推荐架构设计原则
-
扁平化优于深层嵌套
- 尽量让多个模块由根模块统一调用
- 减少层级,便于管理依赖
-
接口清晰化
- 每个模块通过
outputs.tf
明确暴露哪些值 - 通过
variables.tf
明确需要哪些输入
- 每个模块通过
-
避免循环依赖
- A → B → C → A 是非法的
- 如果出现,说明模块职责不清,需重构
-
用 locals 或 variables 统一配置
locals {
common_tags = { Environment = "prod" }
}
module "vpc" {
source = "./modules/vpc"
tags = local.common_tags
}
module "rds" {
source = "./modules/rds"
tags = local.common_tags
}
参考:
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.