AWS上具有terraform的多个可用区域

时间:2017-09-04 16:50:36

标签: amazon-web-services amazon-ec2 terraform availability-zone

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

我正在尝试使用模块和count参数创建EC2实例,但我不知道如何告诉terraform使用App层的两个子网。我有一个额外的约束是使用静态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" {...}。但显然它没有匹配网络名称的过滤选项
  • 将子网ID作为字符串列表传递给模块。但我不想硬编码ID,这不是自动化;
  • 将子网硬编码为data "aws_subnet" "app_subnet_1" {...}data "aws_subnet" "app_subnet_2" {...},但我必须为每个不喜欢的子网使用不同的变量集;
  • 获取每个子网的信息,如上所述,但随后创建map以列表形式访问它。但是在变量定义中使用插值是不可能的;
  • 不使用模块并为每个环境硬编码每个实例。嗯......真的吗?

我真的没想完了。似乎没有人必须在特定的子网中部署实例并保持良好的程度。我只看到未指定子网的示例或人们只使用默认值的示例。这真的很不寻常吗?

提前感谢所有人。

5 个答案:

答案 0 :(得分:3)

我让Terraform使用aws_subnet_ids data source循环遍历可用区中的子网,并使用代表层的标记进行过滤(在我的情况下是公共/私有)。

这看起来像这样:

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顺序返回子网,但是按照自己的内部ID排序,因为AZ被帐户洗牌(可能是为了阻止AZ A被淹没,因为人们可以预测他们可以使用的所有东西都是不好的)

如果由于一些奇怪的原因你特别关心将实例放在AZ A中,你必须把自己绑在一些可怕的结上但是这个最小的例子应该至少让实例通过你有子网的AZ进行循环当超过数组长度时,依赖Terraform循环回数组。

答案 1 :(得分:3)

最后,我使用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)}"

  ...
}

答案 2 :(得分:3)

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

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

此分发机制允许在各个区域之间均匀分发节点。
例如。 zone = [A,B]-实例1将在A中,实例2将在B中,实例3将再次在A中。
通过将区域C添加到区域,会将实例3转换为C。

答案 3 :(得分:1)

如果实例数多于子网数,则资源中的计数索引将引发错误。使用Terraform中的元素插值

  

element(list,index)-从列表中的给定索引处返回单个元素。如果索引大于元素数,则此函数将使用标准的mod算法进行包装。此功能仅适用于平面列表。

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

答案 4 :(得分:0)

对于在 aws_instance 方法中建议使用 count.index 的每个人来说,这不是最好的,因为如果您的实例数多于子网,就会失败。