Terraform 用例创建多个几乎相同的基础设施副本

Terraform use case to create multiple almost identical copies of infrastructure

我有 TF 模板,其目的是创建同一云基础架构的多个副本。例如,您在一个大组织中有多个业务部门,并且您想要构建相同的基本网络。或者您想要一种简单的方法让开发人员启动他正在处理的堆栈。 "tf apply" 调用之间的唯一区别是变量 BUSINESS_UNIT,例如,它作为环境变量传入。

还有其他人在使用这样的系统吗?如果是,您如何管理状态文件?

这是一个相当流行的用例。要存档此内容,您可以让开发人员将变量从命令行或 tfvars 文件传递​​到资源中,以使不同的资源独一无二:

main.tf:

resource "aws_db_instance" "db" {
  identifier = "${var.BUSINESS_UNIT}"
  # ... read more in docs
}

$ terraform apply -var 'BUSINESS_UNIT=unit_name'

PS:我们经常这样做是为了为特定的 git 分支名称提供基础设施,并且由于所有资源都是可识别的并且位于单独的 tfstate 文件中,所以我们可以在不使用时安全地销毁它们不需要它们。

我想到了两种方法。

首先,您可以继续使用您应用的同一 Terraform 配置文件夹,并在 运行 Terraform 时简单地传入一个变量(通过命令行或通过环境变量)。您还希望拥有调用 Terraform 的相同包装器脚本来配置您的状态设置以使其不同。

结果可能是这样的:

variable "BUSINESS_UNIT" {}
variable "ami" { default = "ami-123456" }

resource "aws_instance" "web" {
    ami = "${var.ami}"
    instance_type = "t2.micro"
    tags {
        Name = "web"
        Business_Unit = "${var.BUSINESS_UNIT}"
    }
}

resource "aws_db_instance" "default" {
  allocated_storage    = 10
  engine               = "mysql"
  engine_version       = "5.6.17"
  instance_class       = "db.t2.micro"
  name                 = "${var.BUSINESS_UNIT}"
  username             = "foo"
  password             = "bar"
  db_subnet_group_name = "db_subnet_group"
  parameter_group_name = "default.mysql5.6"
}

创建一个EC2实例和一个RDS实例。然后你可以这样调用它:

#!/bin/bash

if [ "$#" -ne 1 ]; then
    echo "Illegal number of parameters - specify business unit as positional parameter"
fi

business_unit=

terraform remote config -backend="s3" \
                        -backend-config="bucket=${business_unit}" \
                        -backend-config="key=state"

terraform remote pull

terraform apply -var 'BUSINESS_UNIT=${business_unit}'

terraform remote push

作为替代途径,您可能需要考虑使用模块来包装您的 Terraform 配置。

因此,您可能拥有现在看起来像这样的东西:

web-instance/main.tf

variable "BUSINESS_UNIT" {}
variable "ami" { default = "ami-123456" }

resource "aws_instance" "web" {
    ami = "${var.ami}"
    instance_type = "t2.micro"
    tags {
        Name = "web"
        Business_Unit = "${var.BUSINESS_UNIT}"
    }
}

db-instance/main.tf

variable "BUSINESS_UNIT" {}

resource "aws_db_instance" "default" {
  allocated_storage    = 10
  engine               = "mysql"
  engine_version       = "5.6.17"
  instance_class       = "db.t2.micro"
  name                 = "${var.BUSINESS_UNIT}"
  username             = "foo"
  password             = "bar"
  db_subnet_group_name = "db_subnet_group"
  parameter_group_name = "default.mysql5.6"
}

然后您可能有不同的文件夹调用每个业务单元的这些模块:

business-unit-1/main.tf

variable "BUSINESS_UNIT" { default = "business-unit-1" }

module "web_instance" {
  source = "../web-instance"
  BUSINESS_UNIT = "${var.BUSINESS_UNIT}"
}

module "db_instance" {
  source = "../db-instance"
  BUSINESS_UNIT = "${var.BUSINESS_UNIT}"
}

business-unit-2/main.tf

variable "BUSINESS_UNIT" { default = "business-unit-2" }

module "web_instance" {
  source = "../web-instance"
  BUSINESS_UNIT = "${var.BUSINESS_UNIT}"
}

module "db_instance" {
  source = "../db-instance"
  BUSINESS_UNIT = "${var.BUSINESS_UNIT}"
}

您仍然需要一个包装器脚本来像以前一样管理状态配置,但是走这条路可以让您在模块中提供一个粗略的模板,然后按业务单元硬编码某些额外的配置,例如实例大小或实例数量为他们构建的实例。

你应该使用 Terraform Module。创建模块没什么特别的:只需将任何 Terraform 模板放在一个文件夹中即可。模块的特别之处在于您如何使用它。

假设您将基础架构的 Terraform 代码放在文件夹 /terraform/modules/common-infra 中。然后,在实际定义您的实时基础设施的模板中(例如 /terraform/live/business-units/main.tf),您可以按如下方式使用该模块:

module "business-unit-a" {
  source = "/terraform/modules/common-infra"
}

要为多个业务部门创建基础架构,您可以多次使用同一个模块:

module "business-unit-a" {
  source = "/terraform/modules/common-infra"
}

module "business-unit-b" {
  source = "/terraform/modules/common-infra"
}

module "business-unit-c" {
  source = "/terraform/modules/common-infra"
}

如果每个业务单元都需要自定义一些参数,那么只需要在模块中定义一个input variable(例如/terraform/modules/common-infra/vars.tf下):

variable "business_unit_name" {
  description = "The name of the business unit"
}

现在您可以在每次使用该模块时将此变量设置为不同的值:

module "business-unit-a" {
  source = "/terraform/modules/common-infra"
  business_unit_name = "a"
}

module "business-unit-b" {
  source = "/terraform/modules/common-infra"
  business_unit_name = "b"
}

module "business-unit-c" {
  source = "/terraform/modules/common-infra"
  business_unit_name = "c"
}

有关详细信息,请参阅 How to create reusable infrastructure with Terraform modules and Terraform: Up & Running