AWS 上带有 Terraform 的多个可用区

Multiple availability zones with terraform on AWS

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

我正在尝试使用模块和 count 参数创建 EC2 实例,但我不知道如何告诉 Terraform 使用应用层的两个子网。我还有一个额外的限制是使用静态 IP 地址(或一种具有确定性私有名称的方法)

我正在玩转资源

resource "aws_instance" "app_server" {
  ...
  count = "${var.app_servers_count}"

  # Not all at the same time, though!
  availability_zone = ...
  subnet_id = ...
  private_ip = ...
}

到目前为止我 tried/thought 的事情:

我真的运行没主意了。似乎没有人必须在特定子网中部署实例并保持良好的抽象度。我只看到未指定子网或人们只对所有内容使用默认值的示例。这真的很不寻常吗?

在此先感谢大家。

我让 Terraform 通过使用 aws_subnet_ids data source 并按代表层的标记过滤(在我的例子中是 public/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}"
}

这 returns 一致的排序顺序,但不一定在您的帐户中以 AZ A 开头。我怀疑 AWS API returns 子网按 AZ 顺序排列,但按其内部 ID 排序,因为 AZ 按帐户洗牌(大概是为了阻止 AZ A 被淹没,因为人类可预见地不擅长放置所有内容首先他们可以使用)。

如果出于某种奇怪的原因您特别关心首先放置在可用区 A 中的实例,那么您将不得不陷入一些可怕的结在超过数组长度时依靠 Terraform 循环返回数组。

最后我想出了如何去做,使用 data "aws_subnet_ids" {...} 更重要的是理解 terraform 在使用 count:

时从资源中创建列表
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)}"

  ...
}

如果实例数多于子网数,资源中的计数索引将引发错误。使用来自 Terraform

的元素插值

element(list, index) - Returns a single element from a list at the given index. If the index is greater than the number of elements, this function will wrap using a standard mod algorithm. This function only works on flat lists.

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

可以使用模数在多个区域中均匀分布实例。

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) ]}"
  ...
}

这种分配机制允许跨区域平均分配节点。
例如。 zones = [A,B] - 实例 1 将在 A 中,实例 2 将在 B 中,实例 3 将再次在 A 中。
通过将区域 C 添加到区域会将 instance-3 转移到 C.