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"
  

该模块中的每个dataresource 块都需要设置provider,因为在该模块中默认情况下没有可供选择的默认提供程序配置。

当您调用模块时,您需要告诉 Terraform 调用者中的哪些提供程序配置映射到被调用模块中的 srcdst 配置:

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

Terraform 上的 Azure 应用服务自动缩放错误

在 terraform 文件而不是 env 变量中为 Terraform 提供凭据

01.terraform概述

如何使用 Terraform 将 GKE 凭证传递给 Kubernetes 提供者?

Terraform - Azure 作为提供者和受限访问帐户