我们希望将每个地形环境都放在一个单独的AWS帐户中,这样就很难意外部署到生产中。这是如何最好地完成的?
我们假设一个帐户专用于生产,另一个专用于预生产,可能还有其他沙箱环境也有唯一的帐户,可能是基于每个管理员。另一个假设是,每个AWS帐户中都有一个S3存储桶,该存储桶是特定于您的环境的。此外,我们希望您的AWS帐户凭据在~/.AWS/credentials中进行管理(或者可能使用IAM角色(。
Terraform后端配置
有两种状态。对于主要状态,我们使用部分配置的概念。我们不能通过模块或其他方式将变量传递到后端配置中,因为它是在确定变量之前读取的。
Terraform配置设置
这意味着我们声明了缺少一些细节的后端,然后将它们作为参数提供给terraform init
。一旦初始化,它就会被设置,直到.terraform
目录被删除。
terraform {
backend "s3" {
encrypt = true
key = "name/function/terraform.tfstate"
}
}
工作流注意事项
我们只需要更改初始化方式。我们在terraform init
上使用-backend-config
参数。这提供了配置中缺少的部分。我通过~/.bash_profile
中的bash别名提供了所有缺失的部分,如下所示。
alias terrainit='terraform init
-backend-config "bucket=s3-state-bucket-name"
-backend-config "dynamodb_table=table-name"
-backend-config "region=region-name"'
意外错误配置结果
如果省略了相应的必需-backend-config
参数,初始化将提示您输入这些参数。如果提供错误,则可能会由于权限原因导致失败。此外,远程状态必须配置为匹配,否则也会失败。为了部署到生产部门,在确定适当的客户环境时必须出现多个错误。
Terraform远程状态
下一个问题是远程状态也需要更改,并且无法通过从后端配置中提取配置来进行配置;但是,可以通过变量设置远程状态。
模块设置
为了简化帐户切换,我们设置了一个非常简单的模块,该模块接收单个变量aws-account
,并返回一组输出,远程状态可以使用这些输出和适当的值。我们还可以包括其他特定于环境/帐户的内容。该模块是一个简单的main.tf
,具有映射变量,这些变量具有aws-account
键和特定于该帐户的值。然后,我们有一组输出,它们像这样简单地查找映射变量。
variable "aws-region" {
description = "aws region for the environment"
type = "map"
default = {
Production = "us-west-2"
PP = "us-east-2"
}
}
output "aws-region" {
description = “The aws region for the account
value = "${lookup(var.aws-region, var.aws-account, "invalid AWS account specified")}"
}
Terraform配置设置
首先,我们必须将aws帐户传递给模块。这可能接近main.tf
的顶部。
module "environment" {
source = "./aws-account"
aws-account = "${var.aws-account}"
}
然后在variables.tf
中添加一个变量声明。
variable "aws-account" {
description = "The environment name used to identify appropriate AWS account resources used to configure remote states. Pre-Production should be identified by the string PP. Production should be identified by the string Production. Other values may be added for other accounts later."
}
现在,我们已经从模块输出了特定于帐户的变量,它们可以在远程状态声明中使用,如下所示。
data "terraform_remote_state" "vpc" {
backend = "s3"
config {
key = "name/vpc/terraform.tfstate"
region = "${module.environment.aws-region}"
bucket = "${module.environment.s3-state-bucket-name}"
}
}
工作流考虑
如果在这样设置后工作流没有任何变化,则每当执行计划/应用等时,都会通过这样的提示提示用户提供aws-account
变量的值。提示的内容是对variables.tf
中变量的描述。
$ terraform plan
var.aws-account
The environment name used to identify appropriate AWS account
resources used to configure remote states. Pre-Production should be
identified by the string PP. Production should be identified by the
string Production. Other values may be added for other accounts later.
Enter a value:
您可以通过在命令行上提供类似以下的变量来跳过提示
terraform plan -var="aws-account=PP"
意外错误配置结果
如果未指定aws-account
变量,则会请求它。如果提供了aws帐户模块不知道的无效值,它将多次返回错误,包括字符串"指定的无效aws帐户",因为这是查找的默认值。如果aws帐户传递正确,但与terraform init中标识的值不匹配,则它将失败,因为正在使用的aws凭据无法访问正在标识的S3存储桶。
我们遇到了类似的问题a,我们解决了(部分(在Jenkins或任何其他CI工具中创建管道的问题。
我们有3个不同的env(dev、staging和prod(。相同的代码,不同的tfvars,不同的aws帐户。
当地形代码合并到master时,可以应用于暂存,只有当暂存为绿色时,才能执行生产。没有人在prod中手动运行terraform,aws凭据存储在CI工具中。
此设置可以解决您所描述的事故,但也可以防止不同的用户应用不同的本地代码。