简体   繁体   English

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

[英]Terraform use case to create multiple almost identical copies of infrastructure

I have TF templates whose purpose is to create multiple copies of the same cloud infrastructure.我有 TF 模板,其目的是创建同一云基础架构的多个副本。 For example you have multiple business units inside a big organization, and you want to build out the same basic networks.例如,您在一个大型组织中有多个业务部门,并且您想要构建相同的基本网络。 Or you want an easy way for a developer to spin up the stack that he's working on.或者您想要一种让开发人员轻松启动他正在处理的堆栈的方法。 The only difference between "tf apply" invokations is the variable BUSINESS_UNIT, for example, which is passed in as an environment variable.例如,“tf apply”调用之间的唯一区别是变量 BUSINESS_UNIT,它作为环境变量传入。

Is anyone else using a system like this, and if so, how do you manage the state files ?有没有其他人使用这样的系统,如果是,你如何管理状态文件?

You should use a Terraform Module .您应该使用Terraform 模块 Creating a module is nothing special: just put any Terraform templates in a folder.创建模块没什么特别的:只需将任何 Terraform 模板放在一个文件夹中。 What makes a module special is how you use it.模块的特殊之处在于您如何使用它。

Let's say you put the Terraform code for your infrastructure in the folder /terraform/modules/common-infra .假设您将基础设施的 Terraform 代码放在文件夹/terraform/modules/common-infra Then, in the templates that actually define your live infrastructure (eg /terraform/live/business-units/main.tf ), you could use the module as follows:然后,在实际定义实时基础架构的模板中(例如/terraform/live/business-units/main.tf ),您可以按如下方式使用该模块:

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

To create the infrastructure for multiple business units, you could use the same module multiple times:要为多个业务部门创建基础架构,您可以多次使用同一个模块:

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"
}

If each business unit needs to customize some parameters, then all you need to do is define an input variable in the module (eg under /terraform/modules/common-infra/vars.tf ):如果每个业务单元都需要自定义一些参数,那么您只需在模块中定义一个 输入变量(例如在/terraform/modules/common-infra/vars.tf下):

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

Now you can set this variable to a different value each time you use the module:现在您可以在每次使用模块时将此变量设置为不同的值:

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"
}

For more information, see How to create reusable infrastructure with Terraform modules and Terraform: Up & Running .有关更多信息,请参阅如何使用 Terraform 模块Terraform:启动和运行创建可重用基础设施

There's two ways of doing this that jump to mind.有两种方法可以做到这一点。

Firstly, you could go down the route of using the same Terraform configuration folder that you apply and simply pass in a variable when running Terraform (either via the command line or through environment variables).首先,您可以继续使用您应用的相同 Terraform 配置文件夹,并在运行 Terraform 时简单地传入一个变量(通过命令行或通过环境变量)。 You'd also want to have the same wrapper script that calls Terraform to configure your state settings to make them differ.您还需要使用相同的包装器脚本调用 Terraform 来配置您的状态设置以使其不同。

This might end up with something like this:这可能会以这样的方式结束:

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"
}

Which creates an EC2 instance and an RDS instance.这将创建一个 EC2 实例和一个 RDS 实例。 You would then call that with something like this:然后你会用这样的东西调用它:

#!/bin/bash

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

business_unit=$1

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

As an alternative route you might want to consider using modules to wrap your Terraform configuration.作为替代路线,您可能需要考虑使用模块来包装您的 Terraform 配置。

So instead you might have something that now looks like:因此,您现在可能会看到如下所示的内容:

web-instance/main.tf网络实例/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数据库实例/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"
}

And then you might have different folders that call these modules per business unit:然后你可能有不同的文件夹来调用每个业务部门的这些模块:

business-unit-1/main.tf业务单元 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}"
}

and

business-unit-2/main.tf业务单元 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}"
}

You still need a wrapper script to manage state configuration as before but going this route enables you to provide a rough template in your modules and then hard code certain extra configuration by business unit such as the instance size or the number of instances that are built for them.您仍然需要一个包装器脚本来像以前一样管理状态配置,但是通过这条路线,您可以在模块中提供一个粗略的模板,然后按业务单位硬编码某些额外的配置,例如实例大小或构建的实例数量他们。

This is rather popular use case.这是相当流行的用例。 To archive this you can let developers to pass variable from command-line or from tfvars file into resource to make different resources unique:要存档此文件,您可以让开发人员将变量从命令行或从 tfvars 文件传递​​到资源中,以使不同的资源具有唯一性:

main.tf:主要.tf:

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

$ terraform apply -var 'BUSINESS_UNIT=unit_name'

PS: We do this often to provision infrastructure for specific git branch name, and since all resources are identifiable and are located in separate tfstate files, we can safely destroy them when we don't need them. PS:我们经常这样做是为了为特定的 git 分支名称提供基础设施,并且由于所有资源都是可识别的并且位于单独的 tfstate 文件中,因此我们可以在不需要它们时安全地销毁它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM