没有模块化的缺点
- 配置文件过于庞大,不易维护
- 杂乱,无法看到整体结构
模块的作用
有效的组织各种资源,把相关资源放在同一个组中。按照逻辑划分形成不同的组件,这样就便于重用。比如:
- WebServer module: 负责创建Web服务器相关的资源
- Redis module:负责创建缓存相关的资源
每个模块都有几个关键的部分:
- inputs
- outputs
- dependencies
- resources
在Terraform,既有官方提供的modules,也有很多第三方的modules:https://registry.terraform.io/browse/modules
使用自定义模块
在Terraform中,通常会把不同的功能放置在不同的模块中,我们无需声明其依赖关系,Terraform会自动加载不同的文件,并将其组合在一起:
- outputs.tf: 用于放置输出信息
- variables.tf:用于放置变量声明
- providers.tf: 当使用多个providers的时候,可以将所有provider的定义放在这个文件夹中
需要注意的是,上面的几个文件名(main.tf,outputs.tf,variables.tf,providers.tf)只是一种convention,并不是定死的,你可以使用任何名字,但一般情况下还是请遵守这些约定。
当创建一个模块的时候,它应该是一组相关资源的分组。一般情况下,至少要包含3-4个资源才值得创建一个模块。
有了模块之后,Terraform项目的组织结构应该类似于:
main.tf
–main.tf
–variables.tf
–outputs.tf
–modules
—-redis
——main.tf
——variables.tf
——outputs.tf
—-webserver
——main.tf
——variables.tf
——outputs.tf
—-subnet
——main.tf
——variables.tf
——outputs.tf
如何传递值给模块中的输入
如果在模块的variables.tf中声明了一些变量,比如:
in modules/subnet/variables.tf:
variable available_zone {}
variable env_prefix {}
variable subnet_cidr_block {}
variable vpc_id {}
我们可以在modules/subnet/main.tf引用这些变量。
但这些变量的值需要在主模块,也就是根目录下的main.tf中进行传递:
module "my-subnet" {
source = "./modules/subnet"
# 注意下面引用的是在terraform.tfvars中定义的subnet_cidr_block
# 同时将等其作为变量subnet_cidr_block传递给modules/subnet
subnet_cidr_block = var.subnet_cidr_block
# 其余的变量同理
available_zone = var.available_zone
env_prefix = var.env_prefix
# vpc_id的值则可以引用在当前文件中定义的VPC的id属性
vpc_id = aws_vpc.lcoding-vpc.id
}
如何使用output在模块中把值传递出去
第一步:在modules/subnet/outputs.tf中声明:
output "subnet" {
value = aws_subnet.lcoding-subnet-1
}
之后就可以在主模块 /main.tf 中这样引用了:
resource "aws_instance" "web-server" {
# ...
subnet_id = module.my-subnet.subnet.id
}
测试模块
在更改了模块之后,必须要调用 terraform init 来进行初始化
terraform init
之后可以在主模块的main.tf中使用子模块的输出了:
resource "aws_instance" "web-server" {
# ...
depends_on = [
module.my-subnet
]
subnet_id = module.my-subnet.subnet.id
使用官方提供的模块
以AWS VPC模块为例。