[英]Multiple availability zones with terraform on AWS
The VPC I'm working on has 3 logical tiers: Web, App and DB.我正在处理的 VPC 有 3 个逻辑层:Web、App 和 DB。 For each tier there is one subnet in each availability zone.
对于每一层,每个可用区内都有一个子网。 Total of 6 subnets in the region I'm using.
我正在使用的区域中共有 6 个子网。
I'm trying to create EC2 instances using a module and the count
parameter but I don't know how to tell terraform to use the two subnets of the App tier.我正在尝试使用模块和
count
参数创建 EC2 实例,但我不知道如何告诉 terraform 使用 App 层的两个子网。 An additional constraint I have is to use static IP addresses (or a way to have a deterministic private name)我有一个额外的限制是使用静态 IP 地址(或具有确定性私有名称的方法)
I'm playing around with the resource我在玩资源
resource "aws_instance" "app_server" {
...
count = "${var.app_servers_count}"
# Not all at the same time, though!
availability_zone = ...
subnet_id = ...
private_ip = ...
}
Things I've tried/thought so far:到目前为止我尝试过/想到的事情:
data "aws_subnet" "all_app_subnets" {...}
, filter by name, get all the subnets that match and use them as a list.data "aws_subnet" "all_app_subnets" {...}
,按名称过滤,获取所有匹配的子网并将它们用作列表。 But aws_subnet
cannot return a list;aws_subnet
不能返回列表;data "aws_availability_zones" {...}
to find all the zones.data "aws_availability_zones" {...}
查找所有区域。 But I still have the problem of assigning the correct subnet;data "aws_subnet_ids" {...}
which looks like the best option.data "aws_subnet_ids" {...}
看起来是最好的选择。 But apparently it doesn't have a filter option to match the networks nameldata "aws_subnet" "app_subnet_1" {...}
, data "aws_subnet" "app_subnet_2" {...}
but then I have to use separate sets of variables for each subnet which I don't like;data "aws_subnet" "app_subnet_1" {...}
, data "aws_subnet" "app_subnet_2" {...}
但是我必须为每个我不喜欢的子网使用单独的变量集;map
to access it as a list.map
以将其作为列表访问。 But it's not possibile to use interpolation in variables definition; I really ran out of ideas.我真的没有主意了。 It seems that nobody has to deploy instances in specific subnetworks and keep a good degree of abstration.
似乎没有人必须在特定的子网中部署实例并保持良好的抽象程度。 I see only examples where subnetworks are not specified or where people just use default values for everything.
我只看到未指定子网或人们只对所有内容使用默认值的示例。 Is this really something so unusual?
这真的很不寻常吗?
Thanks in advance to everyone.在此先感谢大家。
It is possible to evenly distribute instances across multiple zones using 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) ]}"
...
}
This distribution mechanism allow to distribute nodes evenly across zones.这种分布机制允许跨区域均匀分布节点。
Eg zones = [A,B] - instance-1 will be in A, instance-2 will in B, instance-3 will be in A again.例如 zone = [A,B] - instance-1 将在 A 中,instance-2 将在 B 中,instance-3 将再次在 A 中。
By adding zone C to zones will shift instance-3 to C.通过将区域 C 添加到区域会将实例 3 转移到 C。
The count index in the resource will throw an error if you have more instances than subnets.如果实例多于子网,资源中的计数索引将引发错误。 Use the element interpolation from Terraform
使用 Terraform 的元素插值
element(list, index) - Returns a single element from a list at the given index.
element(list, index) - 从给定索引处的列表中返回单个元素。 If the index is greater than the number of elements, this function will wrap using a standard mod algorithm.
如果索引大于元素的数量,则此函数将使用标准 mod 算法进行换行。 This function only works on flat lists.
此功能仅适用于平面列表。
subnet_id = "${element(data.aws_subnet_ids.app_tier_ids.ids, count.index)}"
At the end I figured out how to do it, using data "aws_subnet_ids" {...}
and more importantly understanding that terraform creates lists out of resources when using count
:最后我想出了如何做到这一点,使用
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)
...
}
I get Terraform to loop through the subnets in an availability zone by using the aws_subnet_ids
data source and filtering by a tag representing the tier (in my case public/private).我让 Terraform 通过使用
aws_subnet_ids
数据源并通过表示层的标记(在我的情况下为公共/私有)过滤来遍历可用区中的子网。
This then looks something like this:然后看起来像这样:
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}"
}
This returns a consistent sort order but not necessarily starting with AZ A in your account.这将返回一致的排序顺序,但不一定以您账户中的 AZ A 开头。 I suspect that the AWS API returns the subnets in AZ order but ordered by their own internal id as the AZs are shuffled by account (presumably to stop AZ A being flooded as humans are predictably bad at putting everything in the first place they can use).
我怀疑 AWS API 按 AZ 顺序返回子网,但按它们自己的内部 id 排序,因为 AZ 按帐户打乱(大概是为了阻止 AZ A 被淹没,因为可以预见,人类不擅长将所有东西放在他们可以使用的首位) .
You would have to tie yourself in some horrible knots if for some odd reason you particularly care about instances being placed in AZ A first but this minimal example should at least get instances being round-robined through the AZs you have subnets in by relying on Terraform's looping back through arrays when exceeding the array length.如果出于某种奇怪的原因您特别关心首先将实例放置在 AZ A 中,您将不得不把自己绑在一些可怕的结上,但是这个最小的示例应该至少通过依赖 Terraform 的子网在您拥有子网的 AZ 中轮询实例超过数组长度时循环返回数组。
对于在 aws_instance 方法中建议 count.index 的每个人来说,这不是最好的,因为如果您的实例多于子网,则会失败。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.