Terraform 0.15.1 多提供者问题 - 参数“region”是必需的,但未设置
Posted
技术标签:
【中文标题】Terraform 0.15.1 多提供者问题 - 参数“region”是必需的,但未设置【英文标题】:Terraform 0.15.1 Multiple Provider Issue - The argument "region" is required, but was not set 【发布时间】:2021-07-22 10:43:25 【问题描述】:所以下面是我的项目文件结构:
├── main.tf
├── tunnel
│ ├── main.tf
│ └── variables.tf
└── variables.tf
我正在尝试在 Terraform 0.15.1 中使用多个提供程序,如此处所述 -> https://www.terraform.io/docs/language/modules/develop/providers.html
按照示例后,我无法使其工作。我现在已经简化了我的代码,只使用一个提供者别名(尽可能简单)。我得到的错误是:
╷
│ Error: Missing required argument
│
│ The argument "region" is required, but was not set.
╵
我在根目录下的 main.tf 文件:
module "tunnel"
source = "./tunnel"
providers =
aws.r = aws.requester
我的 variables.tf 在根目录中:
provider "aws"
alias = "requester"
region = "ap-southeast-2"
profile = "benchmark"
我的隧道/variables.tf 文件:
terraform
required_providers
aws =
source = "hashicorp/aws"
version = ">= 2.7.0"
configuration_aliases = [ aws.r ]
data "aws_region" "current"
data "aws_caller_identity" "current"
我的隧道/main.tf 文件:
# Requester's side of the connection.
resource "aws_vpc_peering_connection" "peer"
vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
peer_vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
peer_owner_id = data.aws_caller_identity.current.account_id
peer_region = data.aws_region.current.name
auto_accept = false
tags =
Side = "Requester"
我不明白为什么会出现此错误?这段代码的最终目标是自动化 vpc 对等的双方,如下所示 -> https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_peering_connection_accepter 。但我目前坚持让两个 aws 提供程序使用不同的凭据(上面示例中的一个提供程序以简化事情)。
当我从根 main.tf 中删除 alias = "requester"
时:
provider "aws"
// alias = "requester"
region = "ap-southeast-2"
profile = "benchmark"
以及根路径中 main.tf 中的提供程序配置:
module "tunnel"
source = "./tunnel"
// providers =
// aws.r = aws.requester
//
以及来自 tunnel/variables.tf 的别名配置:
terraform
required_providers
aws =
source = "hashicorp/aws"
version = ">= 2.7.0"
// configuration_aliases = [ aws.r ]
计划运行良好:
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# module.tunnel.aws_vpc_peering_connection.peer will be created
+ resource "aws_vpc_peering_connection" "peer"
+ accept_status = (known after apply)
+ auto_accept = false
+ id = (known after apply)
+ peer_owner_id = "xxxxxxx"
+ peer_region = "ap-southeast-2"
+ peer_vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
+ tags =
+ "Side" = "Requester"
+ vpc_id = "vpc-xxxxxxxxxxx"
+ accepter
+ allow_classic_link_to_remote_vpc = (known after apply)
+ allow_remote_vpc_dns_resolution = (known after apply)
+ allow_vpc_to_remote_classic_link = (known after apply)
+ requester
+ allow_classic_link_to_remote_vpc = (known after apply)
+ allow_remote_vpc_dns_resolution = (known after apply)
+ allow_vpc_to_remote_classic_link = (known after apply)
Plan: 1 to add, 0 to change, 0 to destroy.
【问题讨论】:
【参考方案1】:此错误消息是 Terraform 必须使更简单的情况变得更简单的一些自动行为的结果,但不幸的是,这会导致在像您这样的更复杂的情况下情况相当不清楚。
在您的子模块中,您已声明它期望在调用者中传递一个替代(别名)提供程序配置,在此模块中将被称为aws.r
。但是,您之后声明的数据资源不包含 provider
参数来指定它们属于哪个提供程序配置,因此 Terraform 选择 默认(无别名)提供程序配置。
不幸的是,您的配置实际上没有默认提供程序配置,因为根模块也使用了替代提供程序配置aws.requester
。因此,Terraform 会自动构造一个空配置,因为这对于像 http
这样不需要任何特殊配置的简单提供者来说是一种有用的行为。但这对aws
提供程序最终不起作用,因为它需要设置region
。
至少有两种不同的方法可以更改子模块以使其工作。其中哪一个最合适将取决于此模块如何适合您的更广泛的配置。
第一个选项是让子模块根本不声明aws.r
,而只使用其默认的提供程序配置:
terraform
required_providers
aws =
source = "hashicorp/aws"
version = ">= 2.7.0"
data "aws_region" "current"
data "aws_caller_identity" "current"
因为您的根模块没有hashicorp/aws
的默认配置,您仍然需要在模块调用中明确指出模块的默认提供程序是根模块看到的aws.requester
提供程序:
module "tunnel"
source = "./tunnel"
providers =
aws = aws.requester
对于不需要多个 AWS 提供程序配置的共享模块,这种方法是一个不错的选择,因为模块本身可能完全不知道其调用者中的多个配置,而只是期望获得一个hashicorp/aws
使用的默认配置。
但是,如果您的子模块也需要为 hashicorp/aws
配置多个配置,则它不会起作用。在这种情况下,您将需要我接下来要描述的另一个选项。
当一个共享模块将使用多个提供者配置时,我们需要为它希望从其调用者传递的每个配置声明一个configuration_aliases
条目。你在你的例子中只展示了一个名为r
,我不知道“r”代表什么,所以为了这里的例子,我将称它们为“src”(代表“source”)和“dst” " for ("destination") 只是为了举例说明一些有意义的术语。
我们将从configuration_aliases
配置开始:
terraform
required_providers
aws =
source = "hashicorp/aws"
version = ">= 2.7.0"
configuration_aliases = [ aws.src, aws.dst ]
configuration_aliases
中给出的每一项都声明了一个配置地址,在对该模块的任何调用中,该配置地址必须在 providers
参数中具有相应的条目,我们稍后会看到。
由于该模块不希望使用默认(无别名)配置,我们现在需要为每个资源块告诉 Terraform 它属于哪个提供程序配置。从您的数据资源开始,我们假设它们属于“源”端:
data "aws_region" "current"
provider = aws.src
data "aws_caller_identity" "current"
provider = aws.src
我怀疑在您的真实系统中,您显示的 aws_vpc_peering_connection
资源在逻辑上也可能属于“源”端,但由于您没有显示任何其他资源,我将任意将其分配给 @987654342 @ 显示它的样子:
resource "aws_vpc_peering_connection" "peer"
provider = aws.dst
vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
peer_vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
peer_owner_id = data.aws_caller_identity.current.account_id
peer_region = data.aws_region.current.name
auto_accept = false
tags =
Side = "Requester"
该模块中的每个data
和resource
块都需要设置provider
,因为在该模块中默认情况下没有可供选择的默认提供程序配置。
当您调用模块时,您需要告诉 Terraform 调用者中的哪些提供程序配置映射到被调用模块中的 src
和 dst
配置:
module "tunnel"
source = "./tunnel"
providers =
aws.src = aws.requester
aws.dst = aws.peer
正如我之前提到的,对于模块内声明的每个configuration_aliases
,我们需要在providers
中添加一个条目。将这些替代提供程序配置视为与输入变量有些相似可能会有所帮助,但它们具有更专业的声明和定义语法,因为提供程序对于 Terraform 的执行模型非常基础,需要在正常表达式评估之前解决.
在这里,我只是随意选择“peer”作为您在根模块中声明的假定第二个配置的名称。将调用者中的默认配置分配给被调用模块中的替代配置也是有效的,例如aws.src = aws
,但这似乎不适用于您的情况,因为您在根模块中也没有默认配置.
【讨论】:
出色的答案@Martin,非常感谢! :)以上是关于Terraform 0.15.1 多提供者问题 - 参数“region”是必需的,但未设置的主要内容,如果未能解决你的问题,请参考以下文章
在 terraform 文件而不是 env 变量中为 Terraform 提供凭据