Развертывание ресурса в нескольких регионах с затратами 0,12 / 13

#amazon-web-services #terraform #terraform-provider-aws

#amazon-веб-сервисы #terraform #terraform-поставщик-aws

Вопрос:

У нас довольно сложная среда, в которой у нас много учетных записей AWS в разных регионах, и все они подключены к транзитной сети через VPN-туннели.

На данный момент мы развертываем клиентские шлюзы через модуль «VPC» для каждого VPC в регионе, но проблема, с которой мы сталкиваемся, заключается в том, что развертывание первого VPC проходит нормально, но последующие развертывания VPC вызывают проблемы с тем фактом, что CGW уже существует, и поэтому нам нужно импортировать его, прежде чем мы сможем продолжить, чтоэто не идеальное место для работы, и я также думаю, что есть риск, что если мы отключим VPC, он может попытаться уничтожить CGW, который используется другими VPN.

То, что я хочу сделать, это развернуть CGW отдельно от VPC, а затем VPC выполняет поиск данных для CGW.

Я думал, что, возможно, мы можем использовать наше «базовое» задание для предоставления CGW, которые определены в файле переменных, но пока ничего из того, что я пробовал, не сработало.

Определение переменной будет:

 variable "region_data" {
  type = list(object({
    region = string
    deploy_cgw = bool
    gateways = any
  }))

  default = [
    {
      region = "eu-west-1"
      deploy_cgw = true
      gateways = [
        {
          name = "gateway1"
          ip   = "1.2.3.4"
        },
        {
          name = "gateway2"
          ip   = "2.3.4.5"
        }
      ]
    },
    {
      region = "us-east-1"
      deploy_cgw = true
      gateways = [
        {
          name = "gateway1"
          ip   = "2.3.4.5"
        },
        {
          name = "gateway2"
          ip   = "3.4.5.6"
        }
      ]
    }
  ]
}
  

Я попробовал несколько вещей, таких как:

 locals {
  regions = [for region in var.region_data : region if region.deploy_cgw]
  cgws    = flatten([
    for region in local.regions : [
      for gateway in region.gateways : {
        region = region.region
        name = gateway.name
        ip = gateway.ip
      }
    ]
  ])
}

provider "aws" {
  region = "eu-west-1"
  alias = "eu-west-1"
}

provider "aws" {
  region = "us-east-1"
  alias = "us-east-1"
}

module "cgw" {
  source = "../../../modules/customer-gateway"

  for_each = { for cgw in local.cgws: "${cgw.region}.${cgw.name}" => cgw }
  name_tag = each.value.name
  ip_address = each.value.ip

  providers = {
    aws = "aws.${each.value.region}"
  }
}
  

Но с этим я получаю:

 Error: Invalid provider configuration reference

 on main.tf line 439, in module "cgw":
 439:     aws = "aws.${each.value.region}"

A provider configuration reference must not be given in quotes.
  

Если я перемещу поставщика AWS в модуль и передам регион в качестве параметра, я получу следующее:

 Error: Module does not support for_each

  on main.tf line 423, in module "cgw":
 423:   for_each   = { for cgw in local.testing : "${cgw.region}.${cgw.name}" => cgw }

Module "cgw" cannot be used with for_each because it contains a nested
provider configuration for "aws", at
  

Я провел довольно много исследований, и последнее, что я понимаю, — это то, в отношении чего Terraform занимает жесткую позицию.

Возможно ли то, о чем я спрашиваю?

Ответ №1:

for_each не может использоваться в модулях, в которых определены поставщики. Я тоже был разочарован, узнав об этом. Они делают это потому, что наличие вложенных поставщиков вызывает кошмары, если этот поставщик исчезнет, у вас будут потерянные ресурсы в состоянии, которым вы не можете управлять, и ваши планы потерпят неудачу. Однако это вполне возможно в https://www.pulumi.com /. Мне надоели ограничения в terraform, и я перееду в пулуми. Но это не то, что вы просили, поэтому я продолжу.

Определенно не продолжайте импортировать его. В итоге вы получите несколько частей вашей terraform, управляющих одним и тем же ресурсом.

Просто создайте cgw один раз для каждого региона. Затем передайте идентификатор в свой модуль vpc. Вы не можете перебирать поставщиков, поэтому используйте один модуль для каждого поставщика. Другими словами, для каждого из всех виртуальных серверов в одной учетной записи и в одном регионе для каждого вызова модуля.

 resource "aws_customer_gateway" "east" {
  bgp_asn    = 65000
  ip_address = "172.83.124.10"
  type       = "ipsec.1"
}
resource "aws_customer_gateway" "west" {
  bgp_asn    = 65000
  ip_address = "172.83.128.10"
  type       = "ipsec.1"
}


module "east" {
  source = "../../../modules/customer-gateway"

  for_each = map(
    {
      name = "east1"
      ip = "1.2.3.4"
    },
    {
      name = "east2"
      ip = "1.2.3.5"
    },
  )
  name_tag = each.value.name
  ip_address = each.value.ip
  cgw_id = aws_customer_gateway.east.id

  providers = {
    aws = "aws.east"
  }
}

module "west" {
  source = "../../../modules/customer-gateway"

  for_each = map(
    {
      name = "west1"
      ip = "1.2.3.4"
    },
    {
      name = "west2"
      ip = "1.2.3.5"
    },
  )
  name_tag = each.value.name
  ip_address = each.value.ip
  cgw_id = aws_customer_gateway.west.id

  providers = {
    aws = "aws.west"
  }
}