Terraform 通过状态管理资源。
如果状态文件中已经存在资源,并且 Terraform 没有检测到配置、状态和提供者中的任何差异之间的任何偏差(例如,AWS 控制台或其他工具中的某些内容发生了更改),那么它将显示没有变化。如果它确实检测到某种形式的漂移,那么plan 将向您展示它需要进行哪些更改才能将提供程序中的现有事物状态推送到 Terraform 代码中定义的状态。
不同环境之间的分离状态
如果您想拥有多个环境,甚至是其他资源,它们彼此分开,并且不由同一个 Terraform 操作(例如 plan、apply 或 destroy)管理,那么您希望将这些资源分开进入不同的状态文件。
一种方法是按环境分离 Terraform 代码,并使用与代码库目录结构匹配的状态文件。一个简单的示例可能如下所示:
terraform/
├── production
│ ├── main.tf -> ../stacks/main.tf
│ └── terraform.tfvars
├── stacks
│ └── main.tf
└── staging
├── main.tf -> ../stacks/main.tf
└── terraform.tfvars
stacks/main.tf
variable "environment" {}
resource "aws_lambda_function" "foo" {
function_name = "foo-${var.environment}"
# ...
}
生产/terraform.tfvars
environment = "production"
staging/terraform.tfvars
environment = "staging"
这使用符号链接,以便将登台和生产保持在代码中,唯一的更改由 terraform.tfvars 文件引入。在这种情况下,它会更改 Lambda 函数的名称以包含环境。
这是我通常推荐用于静态环境的方法,因为通过查看存在哪些环境的代码/目录结构会更清楚。
动态环境
但是,如果您有更多动态环境,例如每个功能分支,那么直接在 terraform.tfvars 文件中硬编码环境名称是行不通的。
在这种情况下,我会推荐这样的东西:
terraform/
├── production
│ ├── main.tf -> ../stacks/main.tf
│ └── terraform.tfvars
├── review
│ ├── main.tf -> ../stacks/main.tf
│ └── terraform.tfvars
├── stacks
│ └── main.tf
└── staging
├── main.tf -> ../stacks/main.tf
└── terraform.tfvars
它的工作方式相同,但我会从 review 结构中省略 environment 变量,以便以交互方式或通过 CI 环境变量设置它(例如 export TF_VAR_environment=${TRAVIS_BRANCH} 在 Travis CI 中运行时,调整它以支持任何 CI您使用的系统)。
在不同分支的审查环境之间保持状态分开
这只会让你成功,因为当另一个人尝试将它与另一个分支一起使用时,如果你只是使用默认的 @987654321,他们会看到 Terraform 想要销毁/更新通过运行 Terraform 创建的任何资源@。
工作区提供了一种以更动态的方式分离状态的选项,还允许您interpolate the workspace name into Terraform code:
resource "aws_instance" "example" {
tags {
Name = "web - ${terraform.workspace}"
}
# ... other arguments
}
相反,审查环境将需要创建或使用仅适用于该分支的动态工作区。您可以通过运行以下command:
terraform workspace new [NAME]
如果工作区已经存在,那么您应该改用以下command:
terraform workspace select [NAME]
在 CI 中,您可以使用与以前相同的环境变量来自动使用分支名称作为工作区名称。