Terraform 可能是部署基础设施的最佳工具,因此它是将自动缩放组部署到 AWS 的明显选择。我们要从事的项目要求我们在 AWS 中的实例上部署服务。该服务无状态,且配置简单,可通过 cloud-init轻松配置。
我们的目标是使用 Terraform 配置所有内容。每当我们要进行配置更改时,就会更新 Terraform 配置并再次应用。我们希望在进行任何配置更改时获得干净的实例,而不是就地更新。
在整个示例中,我们为简洁起见省去了某些配置元素的创建。其他一些元素会注入为变量,这些元素也未显示于此。
首先创建启动模板
# Query for the latest Ubuntu 18.04 AMI in the region
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
resource "aws_launch_template" "mysvc" {
name = "mysvc"
ebs_optimized = true
image_id = data.aws_ami.ubuntu.id
instance_initiated_shutdown_behavior = "terminate"
instance_type = "c5.large"
key_name = var.key_name
network_interfaces {
associate_public_ip_address = true
subnet_id = var.subnet_id
security_groups = var.security_groups
delete_on_termination = true
}
tag_specifications {
resource_type = "instance"
tags = {
Name = "mysvc"
}
}
user_data = base64encode(templatefile("${path.module}/user_data.yaml", {
web_password = var.web_password,
ssl_private_key = tls_private_key.mysvc.private_key_pem,
ssl_certificate = tls_self_signed_cert.mysvc.cert_pem
}))
# we don't want to create a new template just because there is a newer AMI
lifecycle {
ignore_changes = [
image_id,
]
}
}
启动模板定义实例的关键元素,还会从用户数据文件加载服务配置。用户数据文件是一个模板,它计算到一个有效的 cloud-init 配置文件。
现在我们创建自动缩放组
resource "aws_autoscaling_group" "mysvc" {
name = "mysvc-${aws_launch_template.mysvc.latest_version}"
health_check_type = "ELB"
health_check_grace_period = 120
termination_policies = ["OldestInstance"]
launch_template {
id = aws_launch_template.mysvc.id
version = aws_launch_template.mysvc.latest_version
}
min_size = 1
max_size = 10
lifecycle {
create_before_destroy = true
}
target_group_arns = [aws_lb_target_group.svc.arn]
}
这里有一些需要注意的事情
这样很好,完全符合我们的需要。或者是这样吗?
如果我们已将组扩展为具有更多实例,并且更改了配置,会发生什么情况?使用当前配置,我们将用一个仅包含 1 个实例的组替换运行的组(例如,包含 5 个实例)。我们希望能够创建一个包含 5 个实例的新组。
为了保留所需的容量的当前值,我们需要在某种程度上首先获得该值。
让我们获取当前启动模板(如果存在的话)
data "aws_launch_template" "current" {
filter {
name = "launch-template-name"
values = ["mysvc"]
}
}
现在让我们查看是否具有使用该启动模板的最新版本的自动缩放组`
data "aws_autoscaling_groups" "current" {
filter {
name = "key"
values = ["mysvc-template-version"]
}
filter {
name = "value"
values = ["${coalesce(data.aws_launch_template.current.latest_version, 0)}"]
}
}
我们使用到目前为止尚未被添加到自动缩放组的标签。有关自动缩放组资源的更改,请参见下方。
这里的想法可能是 data.aws_launch_template.current.latest_version具有值,也可能是 null。如果存在值,我们会期望获得最多一个元素的列表。如果它是 null,那么我们就查找不存在的自动缩放组,并获得一个长度为零的列表。
现在我们可以在当前自动缩放组上获取信息
data "aws_autoscaling_group" "current" {
count = length(data.aws_autoscaling_groups.current.names)
name = data.aws_autoscaling_groups.current.names[count.index]
}
本质上,使用 count 可创建一到零个资源,具体取决于 data.aws_autoscaling_groups.current.names的大小。
现在我们可以更新自动缩放组资源
resource "aws_autoscaling_group" "mysvc" {
name = "mysvc-${aws_launch_template.mysvc.latest_version}"
health_check_type = "ELB"
health_check_grace_period = 120
termination_policies = ["OldestInstance"]
launch_template {
id = aws_launch_template.mysvc.id
version = aws_launch_template.mysvc.latest_version
}
min_size = 1
max_size = 10
desired_capacity = length(data.aws_autoscaling_groups.current.names) > 0 ? data.aws_autoscaling_group.current[0].desired_capacity : var.default_desired_capacity
tag {
key = "mysvc-template-version"
value = aws_launch_template.mysvc.latest_version
propagate_at_launch = false
}
lifecycle {
create_before_destroy = true
}
target_group_arns = [aws_lb_target_group.svc.arn]
}
在此,我们通过检查是否可以找到任何当前自动缩放组来定义所需的容量。如果可以,那么我们使用第一个(也是唯一一个)所需容量的自动缩放组值。但是,如果找不到任何当前组,那么我们使用默认值。我们还记得添加我们需要查询的自动缩放组标签。
Terraform 很棒,而且可以用于许多事情。有些需要多一点弯路,但值得拥有一款所有功能的工具。