- OpenTofu 语言
- 模块
- 创建模块
- 模块内的提供程序
模块内的提供程序
在包含多个模块的配置中,对于如何将资源与提供程序配置关联起来,有一些特殊注意事项。
配置中的每个资源都必须与一个提供程序配置关联。与 OpenTofu 中大多数其他概念不同,提供程序配置对于整个 OpenTofu 配置是全局的,并且可以在模块边界之间共享。提供程序配置只能在根模块中定义。
提供程序可以通过两种方式传递给子模块:通过继承隐式传递,或者通过module
块中的providers
参数显式传递。这两个选项将在以下部分中详细讨论。
旨在被一个或多个其他模块调用的模块不得包含任何provider
块。包含自身提供程序配置的模块与for_each
、count
和depends_on
参数不兼容。
提供程序配置用于对关联资源执行所有操作,包括销毁远程对象和刷新状态。OpenTofu 作为其状态的一部分,保留对最近用于对每个资源应用更改的提供程序配置的引用。当resource
块从配置中删除时,此状态记录将用于定位适当的配置,因为资源的provider
参数(如果有)将不再存在于配置中。
因此,您必须确保在从配置中删除特定提供程序配置的块之前,销毁属于该提供程序配置的所有资源。如果 OpenTofu 发现状态中跟踪的资源实例的提供程序配置块不再可用,那么它将在规划期间返回错误,提示您重新引入提供程序配置。
模块中的提供程序版本约束
虽然提供程序配置在模块之间共享,但每个模块都必须声明自己的 提供程序需求,以便 OpenTofu 能够确保存在与配置中所有模块兼容的单个提供程序版本,并指定用作全局(模块无关)提供程序标识符的 源地址。
要声明模块需要特定提供程序的特定版本,请在terraform
块内使用required_providers
块
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
}
}
}
例如,提供程序需求表示:“此模块需要提供程序hashicorp/aws
的 v2.7.0 版本,并将将其称为aws
。”但是,它没有指定确定提供程序将访问哪些远程端点的任何配置设置,例如 AWS 区域;配置设置来自提供程序配置,并且特定的整体 OpenTofu 配置可能具有 针对同一提供程序的多个不同配置。
模块内的提供程序别名
要在模块内为提供程序声明多个配置名称,请添加configuration_aliases
参数
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
configuration_aliases = [ aws.alternate ]
}
}
}
上述需求与之前的需求相同,只是添加了别名提供程序配置名称aws.alternate
,资源可以使用provider
参数引用它。
如果您正在编写共享模块,请仅使用>=
约束来约束所需的最低提供程序版本。这应该指定包含模块依赖的特征的最低版本,从而允许模块的用户在需要其他特征时选择更新的提供程序版本。
隐式提供程序继承
为了在简单配置中方便起见,子模块会自动从其父级继承 默认提供程序配置。这意味着显式provider
块只出现在根模块中,下游模块可以简单地声明该提供程序的资源,并自动将其与根提供程序配置相关联。
例如,根模块可能只包含一个provider
块和一个用于实例化子模块的module
块
provider "aws" {
region = "us-west-1"
}
module "child" {
source = "./child"
}
然后,子模块可以使用来自此提供程序的任何资源,而无需任何其他提供程序配置。
resource "aws_s3_bucket" "example" {
bucket = "provider-inherit-example"
}
当单个配置对于每个提供程序足以满足整个配置时,我们建议使用这种方法。
只有提供程序配置会由子模块继承,而提供程序源或版本需求则不会。每个模块都必须 声明自己的提供程序需求。这对于非 HashiCorp 提供程序尤其重要。
在更复杂的情况下,可能存在 多个提供程序配置,或者子模块可能需要使用与其父级不同的提供程序设置。对于这种情况,您必须显式传递提供程序。
显式传递提供程序
当子模块需要特定提供商的不同配置,或子模块需要与父模块不同的提供商配置时,您可以在 `module` 块中使用 `providers` 参数来明确定义哪些提供商配置可用于子模块。例如
# The default "aws" configuration is used for AWS resources in the root
# module where no explicit provider instance is selected.
provider "aws" {
region = "us-west-1"
}
# An alternate configuration is also defined for a different
# region, using the alias "usw2".
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
# An example child module is instantiated with the alternate configuration,
# so any AWS resources it defines will use the us-west-2 region.
module "example" {
source = "./example"
providers = {
aws = aws.usw2
}
}
`module` 块中的 `providers` 参数类似于资源中的 `provider` 参数,但它是映射而不是单个字符串,因为模块可能包含来自许多不同提供商的资源。
`providers` 映射的键是子模块期望的提供商配置名称,值是*当前*模块中对应配置的名称。
一旦在 `module` 块中使用 `providers` 参数,它就会覆盖所有默认的继承行为,因此必须为*所有*必需的提供商枚举映射。这样做是为了避免在混合隐式和显式提供商传递时可能出现的混淆和意外情况。
附加的提供商配置(`alias` 参数已设置的配置)*绝不*会自动由子模块继承,因此必须始终使用 `providers` 映射显式传递它们。例如,配置两个 AWS 区域之间网络连接的模块可能需要源区域和目标区域。在这种情况下,根模块可能看起来像这样
provider "aws" {
alias = "usw1"
region = "us-west-1"
}
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
module "tunnel" {
source = "./tunnel"
providers = {
aws.src = aws.usw1
aws.dst = aws.usw2
}
}
然后,子目录 `./tunnel` 必须声明提供商的配置别名,以便调用模块可以在其 `providers` 参数中传递具有这些名称的配置
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
configuration_aliases = [ aws.src, aws.dst ]
}
}
}
然后,每个资源都应将其自己的 `provider` 属性设置为 `aws.src` 或 `aws.dst` 来选择要使用的两个提供商配置中的哪一个。