65.9K
CodeProject 正在变化。 阅读更多。
Home

Terraform 中动态且可配置的可用性区域

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2018年12月12日

CPOL

2分钟阅读

viewsIcon

5755

Terraform 中动态且可配置的可用性区域

Dynamic and Configurable Availability Zones in Terraform

在构建 Terraform 模块时,一个常见的需求是允许客户端选择资源创建的区域和使用的可用区。

我见过几种实现方法,但没有一种完全让我满意。经过一番试验,我找到了一种我认为非常有效的方法。该方案避免了预先知道我们将支持多少个可用区。

Dynamic and Configurable Availability Zones in 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 插值语法,特别是 countkeysvalueselement 函数,我们可以从变量中获取子网名称和 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 模块以使用此模式。

© . All rights reserved.