AWS上带有Terraform的多个可用性区域



我正在使用的VPC具有3个逻辑层:Web,App和DB。对于每个层,每个可用性区都有一个子网。我正在使用的区域中总共有6个子网。

我正在尝试使用模块和count参数创建EC2实例,但我不知道如何告诉Terraform使用App Tier的两个子网。我拥有的另一个约束是使用静态IP地址(或一种确定性私人名称的方法)

我正在玩资源

resource "aws_instance" "app_server" {
  ...
  count = "${var.app_servers_count}"
  # Not all at the same time, though!
  availability_zone = ...
  subnet_id = ...
  private_ip = ...
}

到目前为止我尝试/思考的事情:

  • 使用data "aws_subnet" "all_app_subnets" {...},按名称过滤,获取匹配的所有子网并将其用作列表。但是aws_subnet无法返回列表;
  • 使用data "aws_availability_zones" {...}查找所有区域。但是我仍然有分配正确子网的问题;
  • 使用看起来像最佳选择的data "aws_subnet_ids" {...}。但是显然它没有匹配网络namel
  • 的过滤选项
  • 将子网ID作为字符串列表传递到模块。但是我不想硬编码ID,这不是自动化;
  • 硬码子网作为 data "aws_subnet" "app_subnet_1" {...}data "aws_subnet" "app_subnet_2" {...},但是我必须为我不喜欢的每个子网使用单独的变量集;
  • 在上面的点中获取每个子网的信息,然后创建一个map以访问列表。但是,在变量定义中使用插值是不可能的;
  • 不为每个环境使用模块和硬编码每个实例。嗯...真的?

我真的没有想法。似乎没有人必须在特定的子网中部署实例并保持良好的抽象程度。我只看到未指定子网的示例,或者人们只为所有内容使用默认值。这真的是如此不寻常吗?

事先感谢大家。

可以使用modulo均匀分布多个区域。

variable "zone" {
  description = "for single zone deployment"
  default = "europe-west4-b"
}
variable "zones" {
  description = "for multi zone deployment"
  default = ["europe-west4-b", "europe-west4-c"]
}
resource "google_compute_instance" "default" {
  count = "${var.role.count}"
  ...
  zone = "${var.zone != "" ? var.zone: var.zones[ count.index % length(var.zones) ]}"
  ...
}

这种分布机制允许在区域均匀分布节点。
例如。区域= [a,b] - instance-1将在a,instance-2中将在b中,实例-3将再次在a中。

通过将区域添加到区域,可以将实例3移至c。

如果您比子网更大的实例,资源中的计数索引将丢弃错误。使用Terraform

的元素插值

元素(列表,索引) - 从给定索引处返回列表中的单个元素。如果索引大于元素的数量,则此函数将使用标准MOD算法包装。此功能仅在平面列表上起作用。

subnet_id = "${element(data.aws_subnet_ids.app_tier_ids.ids, count.index)}"

最后,我想出了如何做到这一点,使用data "aws_subnet_ids" {...},更重要的是,使用count时Terraform创建的资源列表:

variable "target_vpc" {}
variable "app_server_count" {}
variable "app_server_ip_start" {}
# Discover VPC
data "aws_vpc" "target_vpc" {
  filter = {
    name = "tag:Name"
    values = [var.target_vpc]
  }
}
# Discover subnet IDs. This requires the subnetworks to be tagged with Tier = "AppTier"
data "aws_subnet_ids" "app_tier_ids" {
  vpc_id = data.aws_vpc.target_vpc.id
  tags {
    Tier = "AppTier"
  }
}
# Discover subnets and create a list, one for each found ID
data "aws_subnet" "app_tier" {
  count = length(data.aws_subnet_ids.app_tier_ids.ids)
  id = data.aws_subnet_ids.app_tier_ids.ids[count.index]
}
resource "aws_instance" "app_server" {
  ...
  # Create N instances
  count = var.app_server_count
  # Use the "count.index" subnet
  subnet_id = data.aws_subnet_ids.app_tier_ids.ids[count.index]
  # Create an IP address using the CIDR of the subnet
  private_ip = cidrhost(element(data.aws_subnet.app_tier.*.cidr_block, count.index), var.app_server_ip_start + count.index)
  ...
}

我通过使用aws_subnet_ids数据源并通过代表该层的标签进行过滤(在我的情况下公开/private)。

然后看起来像这样:

variable "vpc" {}
variable "ami" {}
variable "subnet_tier" {}
variable "instance_count" {}
data "aws_vpc" "selected" {
  tags {
    Name = "${var.vpc}"
  }
}
data "aws_subnet_ids" "selected" {
  vpc_id = "${data.aws_vpc.selected.id}"
  tags {
    Tier = "${var.subnet_tier}"
  }
}
resource "aws_instance" "instance" {
  count         = "${var.instance_count}"
  ami           = "${var.ami}"
  subnet_id     = "${data.aws_subnet_ids.selected.ids[count.index]}"
  instance_type = "${var.instance_type}"
}

这返回一致的排序订单,但不一定从您的帐户中的AZ A开始。我怀疑AWS API以AZ命令返回子网,但随着AZS被帐户的改装而被其内部ID命令(大概是为了阻止AZ AZ A被洪水淹没,因为人类最初可以使用所有东西可以使用所有东西)。

,如果出于某种奇怪的原因,您特别关心将实例放在AZ A之前,您将不得不打结自己的结,但这个最小的例子至少应该通过您拥有子网的AZ进行往返的实例。超过阵列长度时,依靠Terraform的循环通过阵列。

最新更新