我正在使用的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的循环通过阵列。