使用Git管理Terraform多个环境

3

我对如何更好地管理多个环境进行了一些研究和观看了一些视频,但仍然对如何更好地管理它感到困惑。

假设我有一个具有以下结构的单一存储库:

main.tf
variables.tf
backend.tf
dev/
   variables.tfvar
   backend.dev.hcl
prod/
   variables.tfvar
   backend.production.hcl

接下来,在我的代码库中有两个分支(dev和main)。 在dev分支提交生产环境的变量值是否合理?请问如何遵循最佳实践来处理这种情况?

另外一个问题是,一旦在dev分支做出任何更改,最好的方法是将这些更改合并到prod分支而不会丢失任何dev / prod terraform配置?

提前感谢!


你有研究过 Terraform 工作区吗?不知道正在进行什么样的开发,无法百分之百确定它是否适合你的情况。但我认为值得去探索一下 :D - Vidura Dantanarayana
谢谢,Vidura。我已经看过了 Terraform 工作区,但我觉得我的疑问更多的是如何将 Terraform 代码从 Dev 推送到 Prod。例如,tfstate 存储在一个桶中,但如果 dev 环境有任何更改,它会在本地更新一个 tfstate 文件。我需要提交这个文件然后也推送到 Prod 分支吗?那会弄乱(覆盖)Prod tfstate 文件。 - CaioT
一个基本的Terraform原则是不要将状态文件提交到任何版本控制系统中。我们也不应该在Terraform之外修改状态文件。因此,工作区的想法是为单个配置维护多个状态文件。在这里,您可能需要为2个环境维护2个基础架构,但只有一个配置。在配置文件中,您可以根据活动工作区指定资源应如何创建。 - Vidura Dantanarayana
1个回答

8
这个问题的答案通常取决于您是在谈论Terraform配置本身的多个部署阶段,还是在谈论将在Terraform管理的基础设施上运行的任何应用程序/服务的多个部署阶段。区分这一点的一种方式是考虑您将使用多个阶段来实现什么目标。如果您的目标是在生产之前有一个尝试运行“terraform apply”的地方,则正在讨论Terraform配置的多个部署阶段。如果您的目标是创建一个长期的暂存环境,以便您将应用程序/服务部署到其中,则通常从部署流程的角度来看,暂存环境也是“生产环境”,因此应该相应地处理。

在将 Terraform 配置应用到“真实基础设施”之前,您可以使用 Terraform CLI 工作区 创建临时附加状态,与您的配置相关联,以便尝试应用更改,而不会影响代表“默认”工作区中的主要基础架构:

使用terraform workspace new temp-test创建一个临时工作区。 使用您的版本控制系统选择最近应用于default工作区的提交。这通常位于版本控制存储库的主分支上,但根据您使用VCS的方式,您可能需要选择早期提交以排除尚未应用于真实系统的任何更改。 使用terraform apply创建等效基础设施以成为测试的基础。 使用您的版本控制系统切换回您打算测试的配置。这通常是存储库中的功能分支,可能附加到拉取请求上。在此工作流程的实际版本中,将临时工作区命名为分支名称可能很有帮助,因此您的同事可以轻松地查看哪些分支和工作区彼此相关。 再次使用terraform apply计划并应用新配置所表示的更改。 如果应用成功,请检查它创建的基础设施,以确保其按照您预期的方式运行。 完成后:
  • terraform destroy销毁temp-test基础设施
  • terraform workspace select返回默认工作区
  • terraform workspace delete temp-test删除临时工作区
为了使此方法有效,您需要小心避免与远程系统中的现有生产对象发生冲突,特别是在需要唯一名称的情况下。对于具有单独命名空间帐户概念的系统,常见选择是使用不同的帐户和完全分离的凭据进行测试,这意味着您可以使用远程系统的访问控制来避免意外干扰“真实”基础设施。
创建一个长期的暂存或开发环境,以测试在其自身部署管道中某些高级组件需要不同的策略:在这种情况下,支持暂存环境的基础设施就是“生产”部分,就应该按照此方式进行建模,因此通常应将其作为“生产”处理。
为了实现这一点,同时确保两个基础设施堆栈除了有意差异之外保持相等,请将您的通用基础设施代码拆分成一个或多个模块,然后对生产基础设施和每个其他环境的基础设施分别调用这些模块。
根据系统的预期故障域,您可以选择在单个配置中表示生产和暂存基础设施,其中包含对同一模块的两个调用。
module "network-production" {
  source = "../modules/network"

  cidr_block = "10.1.0.0/16"
  # etc...
}

module "network-production" {
  source = "../modules/network"

  cidr_block = "10.2.0.0/16"
  # etc...
}

或者,为了确保它们都是独立可维护的,您可以编写两个单独的配置,它们都调用同一模块,并分别进行terraform申请。
在这两种情况下,思路是使用输入变量来表示不同环境之间的不可避免的差异,但在两种情况下保持申明的资源相同,但将它们都视为应用程序流水线从“生产基础架构”的角度处理,通过将它们都放在名为"default"的命名空间中,在一个配置文件或跨多个配置文件中,并使用版本控制中的同一主分支同时表示它们的“最新版本”。
如果您想测试对配置文件的更改,这些配置文件共同表示应用程序流水线所依赖的所有环境,您可以通过创建一个临时工作区,代表整个堆栈或一个特定的环境,并在将其合并到主分支并将其应用于默认工作区之前,从分支中应用配置来结合这两种方法。
这个答案是对Terraform文档何时使用多个工作区中指导的详细说明。
但总的来说,这是一个有几种不同选项且存在不同权衡的情况,我鼓励您查看文档中的此建议和其他相关内容,并自行决定哪个建议最符合您的需求。 Terraform是一个通用工具,旨在解决各种不同的问题,最终只有您可以将特定的要求映射到Terraform的功能上。

1
嗨,马丁,非常感谢你详细的回答。这正是我在寻找的。谢谢! - CaioT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接