Terraform 中动态且可配置的可用性区域
Terraform 中动态且可配置的可用性区域
在构建 Terraform 模块时,一个常见的需求是允许客户端选择资源创建的区域和使用的可用区。
我见过几种实现方法,但没有一种完全让我满意。经过一番试验,我找到了一种我认为非常有效的方法。该方案避免了预先知道我们将支持多少个可用区。
为了演示,我搭建了一个部署 Web 服务器集群的模块。我的目标是能够配置区域、VPC CIDR 块、子网和子网 CIDR 块如下
module "cluster" {
source = "github.com/dwmkerr/terraform-aws-vpc"
# Note how we can specify any number of availability zones here...
region = "ap-northeast-2"
vpc_cidr = "10.0.0.0/16"
subnets = {
ap-northeast-2a = "10.0.1.0/24"
ap-northeast-2b = "10.0.2.0/24"
ap-northeast-2c = "10.0.3.0/24"
}
# This just defines the number of web servers to deploy, and uses
# adds my public key so I can SSH into the servers...
web_server_count = "3"
public_key_path = "~/.ssh/id_rsa.pub"
}
示例模块位于 github.com/dwmkerr/terraform-aws-vpc。让我们来看一下其中的关键元素。
变量
我们非常明确地定义了所需的变量,并附带描述和变量类型,以避免混淆
variable "region" {
description = "The region to deploy the VPC in, e.g: us-east-1."
type = "string"
}
variable "vpc_cidr" {
description = "The CIDR block for the VPC, e.g: 10.0.0.0/16"
type = "string"
}
variable "subnets" {
description = "A map of availability zones to CIDR blocks, which will be set up as subnets."
type = "map"
}
VPC
现在我们已经定义了变量,就可以设置 VPC 了
// Define the VPC.
resource "aws_vpc" "cluster" {
cidr_block = "${var.vpc_cidr}"
enable_dns_hostnames = true
}
// An Internet Gateway for the VPC.
resource "aws_internet_gateway" "cluster_gateway" {
vpc_id = "${aws_vpc.cluster.id}"
}
// Create one public subnet per key in the subnet map.
resource "aws_subnet" "public-subnet" {
count = "${length(var.subnets)}"
vpc_id = "${aws_vpc.cluster.id}"
cidr_block = "${element(values(var.subnets), count.index)}"
map_public_ip_on_launch = true
depends_on = ["aws_internet_gateway.cluster_gateway"]
availability_zone = "${element(keys(var.subnets), count.index)}"
}
// Create a route table allowing all addresses access to the IGW.
resource "aws_route_table" "public" {
vpc_id = "${aws_vpc.cluster.id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.cluster_gateway.id}"
}
}
// Now associate the route table with the public subnet - giving
// all public subnet instances access to the internet.
resource "aws_route_table_association" "public-subnet" {
count = "${length(var.subnets)}"
subnet_id = "${element(aws_subnet.public-subnet.*.id, count.index)}"
route_table_id = "${aws_route_table.public.id}"
}
这里有几点值得注意。首先,我们可以使用 aws_subnet
资源的 count
字段轻松构建一个可变数量的子网
resource "aws_subnet" "public-subnet" {
count = "${length(var.subnets)}"
availability_zone = "${element(keys(var.subnets), count.index)}"
cidr_block = "${element(values(var.subnets), count.index)}"
}
通过使用 Terraform 插值语法,特别是 count
、keys
、values
和 element
函数,我们可以从变量中获取子网名称和 CIDR 块。
Web 服务器集群
该模块创建了一个负载均衡器后面的 Web 服务器集群,以证明其有效性。脚本中没有什么特别值得注意的地方,除了子网的引用方式
resource "aws_autoscaling_group" "cluster_node" {
name = "cluster_node"
vpc_zone_identifier = ["${aws_subnet.public-subnet.*.id}"]
launch_configuration = "${aws_launch_configuration.cluster_node.name}"
}
请注意,我们可以使用资源路径中的 *
符号指定整个子网 ID 列表 - ["${aws_subnet.public-subnet.*.id}"]
。
就是这样!
这基本上就是全部内容。我非常喜欢这种方法。我认为它使基础设施的运作方式非常清晰,并且易于管理。
可能会有人问,为什么我不使用 cidrsubnet
函数自动计算子网的 CIDR 块。原因纯粹是出于偏好 - 我更喜欢显式指定 CIDR 块,并使用各种模式来设置约定。例如,如果我看到一个 IP 地址,如 10.0.3.121
,那么它就在我的公共子网的第三个可用区,或者 10.2.2.11
就在我的锁定数据区的第二个可用区。
您可以在以下位置查看使用此模式的示例 Terraform 模块:github.com/dwmkerr/terraform-aws-vpc-example。该模块还具有基本的构建管道,并发布在 Terraform Registry 上。我也会更新我的 AWS Openshift 模块以使用此模式。