我们希望将每个terraform环境放在一个单独的AWS帐户中,这样可以避免意外地将其部署到生产中。如何做到最好?
答案 0 :(得分:4)
我们假设一个帐户专用于生产,另一个帐户专用于Production,并且可能其他沙箱环境也具有唯一的帐户,也许基于每个管理员。另一种假设是,每个AWS账户中都有一个特定于您的环境的S3存储桶。另外,我们希望您的AWS账户凭证将通过〜/ .aws / credentials(或可能具有IAM角色)进行管理。
平台后端配置
有两种状态。对于主要状态,我们使用Partial Configuration的概念。我们无法通过模块或其他方式将变量传递到后端配置中,因为在确定变量之前先读取变量。
Terraform Config设置
这意味着我们声明缺少一些细节的后端,然后将它们作为terraform init
的参数提供。初始化后,将对其进行设置,直到删除.terraform
目录为止。
terraform {
backend "s3" {
encrypt = true
key = "name/function/terraform.tfstate"
}
}
工作流程注意事项
我们只需要更改初始化方式即可。我们在-backend-config
上使用terraform init
自变量。这提供了配置的缺失部分。我正在~/.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
,其值特定于该帐户。然后,我们有一堆输出,可以像这样简单地查找map变量。
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 Config设置
首先,我们必须将aws-account传递给模块。这可能在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-account模块无法识别的无效值,它将多次返回错误,包括“指定的无效AWS帐户”字符串,因为这是查找的默认值。如果aws-account正确传递,但与terraform init中标识的值不匹配,则它将失败,因为所使用的aws凭证将无法访问所标识的S3存储桶。
答案 1 :(得分:3)
我们遇到了类似的问题,并且解决了(部分)在Jenkins或任何其他CI工具中创建管道的问题。
我们有3个不同的环境(dev,staging和prod)。相同的代码,不同的tfvar,不同的AWS帐户。
将terraform代码合并到master时,可以将其应用于登台,并且只有在登台为Green时,才可以执行生产。 没有人在产品中手动运行terraform,aws凭据存储在CI工具中。
此设置可以解决您所描述的事故,但也可以防止不同的用户应用不同的本地代码。