如何为多种环境组织terraform模块?
网络上的每个 Terraform 指南都提供了部分解决方案,几乎总是不是真实的图片。
我明白了,并不是每个人都有相同的基础设施需求,但是让我担心的是常见的场景:
- 多个环境(开发,阶段)
- 远程后端 (s3)
- 一些基本资源(bucket 或 ec2 实例)
没有在真实示例项目中的任何地方出现。
我正在寻找那个,同时,我已经研究并得出结论,除了这些需求之外,我还想要:
- 利用模块
- 不使用工作区,而是使用不同的每个环境目录方法
- 不使用 terragrunt 包装器
我当前的结构,不使用模块 - 只有根模块:
infra/ ------------------------------ 'terraform init', 'terraform apply' inside here*
main.tf ------------------------ Sets up aws provider, backend, backend bucket, dynamodb table
terraform.tfvars
variables.tf ----------------- Holds few variables such as aws_region, project_name...
我想要的结构文件夹树(用于单个存储桶资源的简单开发和暂存模拟)是我认为的事情:
infra/
dev/
s3/
modules.tf ------ References s3 module from local/remote folder with dev inputs
stage/
s3/
modules.tf ------ References s3 module from local/remote folder with stage inputs
但是我以前的根模块中的文件呢?我仍然想像以前一样拥有一个远程后端,刚才我想在同一个后端存储桶中有两个状态文件(dev.tfstate和stage.tfstate)?每个子目录中的backend.tf文件会是什么样子,它们会在哪里?在s3/文件夹或dev/文件夹中?
这是一种令人迷惑,因为我是从过渡根模块“terraform初始化”的办法,具体的子目录“terraform INIT”,这是我不清楚我是否应该还是有一个根模块或称为另一个文件夹,例如全球/这我应该考虑我应该在项目开始时初始化的先决条件,并且从那时起基本上不用管,因为它创建了dev/和staging/可以引用?
还有一个问题是:如果我在每个环境中有s3/ ec2/ ecr/子目录怎么办,我在哪里执行'terraform plan'命令?它是否遍历所有子目录?
当我有了上面的答案和清晰的图片时,通过 DRY 来改进它会很棒,但现在,我重视通过示例提供更实用的解决方案,而不仅仅是理论上的 DRY 解释。谢谢!
回答
我工作terraform5年。在我的职业生涯中,我在模块和环境方面犯了很多错误。下面的文字只是我的知识和经验的分享。他们可能很糟糕。
真正的示例项目可能很难找到,因为terraform它不用于创建开源项目。这往往是不安全的共享terraform文件,因为你是显示所有漏洞从intrastructure
模块用途和尺寸
您应该创建具有单一用途的模块,但您的模块应该是通用的。
示例模块
您可以创建bastion host module,但更好的主意是创建一个module for generic server. 这个模块可能有一些专用于你的业务问题的逻辑,比如CW Log group,一些通用的security group rules等等。
应用模块
有时值得创建更具体的模块。
比方说,你有应用需要Lambda,ECS service,CloudWatch alarms,RDS,EBS等的元素的全部是密切联系的。
您有 2 个选择:
- 为上述每个项目创建单独的模块 - 但是您的应用程序使用 5 个模块。
- 创建一个大模块,然后您可以使用单个模块部署您的应用程序
- 混合上述解决方案 - 我更喜欢
一切都取决于细节和某些情况。
但我将向您展示我如何在不同公司的作品中使用 terraform。
分离资源的分离定义
这是项目,您将环境作为目录。对于每个应用程序、网络、数据资源,您都有单独的状态。我将可变数据保存在单独的目录中(如 RDS、EBS、EFS、S3 等),因此所有应用程序、网络等都可以被销毁和重新创建,因为它们是无状态的。没有人可以销毁有状态的项目,因为数据可能会丢失。这就是我过去几年所做的。
project/
?? packer/
?? ansible/
?? terraform/
? ?? environments/
? ? ?? production/
? ? ? ?? apps/
? ? ? ? ?? blog/
? ? ? ? ?? ecommerce/
? ? ? ?? data/
? ? ? ? ?? efs-ecommerce/
? ? ? ? ?? rds-ecommerce/
? ? ? ? ?? s3-blog/
? ? ? ?? general/
? ? ? ? ?? main.tf
? ? ? ?? network/
? ? ? ? ?? main.tf
? ? ? ? ?? terraform.tfvars
? ? ? ? ?? variables.tf
? ? ?? staging/
? ? ? ?? apps/
? ? ? ? ?? ecommerce/
? ? ? ? ?? blog/
? ? ? ?? data/
? ? ? ? ?? efs-ecommerce/
? ? ? ? ?? rds-ecommerce/
? ? ? ? ?? s3-blog/
? ? ? ?? network/
? ? ?? test/
? ? ? ?? apps/
? ? ? ? ?? blog/
? ? ? ?? data/
? ? ? ? ?? s3-blog/
? ? ? ?? network/
? ?? modules/
? ? ?? apps/
? ? ? ?? blog/
? ? ? ?? ecommerce/
? ? ?? common/
? ? ? ?? acm/
? ? ? ?? user/
? ? ?? computing/
? ? ? ?? server/
? ? ?? data/
? ? ? ?? efs/
? ? ? ?? rds/
? ? ? ?? s3/
? ? ?? networking/
? ? ? ?? alb/
? ? ? ?? front-proxy/
? ? ? ?? vpc/
? ? ? ?? vpc-pairing/
?? tools/
要申请单个应用程序,您需要执行以下操作:
cd ./project/terraform/environments/<ENVIRONMENT>/apps/blog;
terraform apply;
您可以看到所有环境中都有很多目录。正如我所看到的,这些工具各有利弊。
缺点:
- 很难检查所有模块是否同步
- 复杂的CI
- 复杂的目录结构,特别是对于团队中的新人来说,但这是逻辑
- 可能有很多依赖关系,但是从一开始就考虑它,这不是问题。
- 您需要小心,以保持完全相同的环境。
- 需要进行大量初始化,并且很难进行重构。
优点:
- 小改动后快速应用
- 分离的应用程序和资源。在不了解整个系统的情况下,很容易修改小模块或小部署
- 取下东西时更容易清理
- 很容易判断哪个模块需要修复。我使用我编写的一些工具来分析基础设施特定部分的状态,并且我可以向特定开发人员发送电子邮件,他的基础设施由于某些原因需要重新同步。
- 与单体相比,您可以更轻松地拥有不同的环境。如果您在环境中不需要它,您可以销毁单个应用程序
单体架构
上次我开始在新公司工作。他们将基础设施定义保存在几个巨大的存储库(或文件夹)中,并且当您执行 terraform apply 时,您会同时创建所有应用程序。
project/
?? modules/
? ?? acm/
? ?? app-blog/
? ?? app-ecommerce/
? ?? server/
? ?? vpc/
?? vars/
? ?? user/
? ?? prod.tfvars
? ?? staging.tfvars
? ?? test.tfvars
?? applications.tf
?? providers.tf
?? proxy.tf
?? s3.tf
?? users.tf
?? variables.tf
?? vpc.tf
在这里,您为每个环境准备不同的输入值。
例如,您想对 prod 应用更改:
terraform apply -var-file=vars/prod.tfvars -lock-timeout=300s
申请分期:
terraform apply -var-file=vars/staging.tfvars -lock-timeout=300s
缺点:
- 您没有依赖项,但有时您需要手动准备一些环境元素,如域、弹性 IP 等,或者您需要在
terraform plan/apply. 那你有问题 - 由于您同时拥有数百个资源和模块,因此很难进行清理
- 超长的 terraform 执行时间。这里计划/应用单个环境大约需要 45 分钟
- 很难理解整个环境。
- 如果您保持该结构以分离网络、应用程序、DNS 等,通常您需要拥有 2/3 存储库...
- 您需要做更多的工作来处理不同的环境。您需要使用计数等...
优点:
- 很容易检查您的基础设施是否是最新的
- 没有复杂的目录结构...
- 您所有的环境都完全相同。
- 重构可能更容易,因为您在很少的地方拥有所有资源。
- 需要少量初始化。
概括
如您所见,这是更多的架构问题,学习它的唯一方法是获得更多经验或阅读其他人的一些帖子......
我仍在尝试找出最佳方式,我可能会尝试第一种方式。
不要把我的优势当作确定的事情。这篇文章只是我的经验,也许不是最好的。
参考
我将发布一些对我有很大帮助的参考资料:
- https://www.terraform-best-practices.com/
- https://github.com/antonbabenko/terraform-best-practices-workshop
- You are comparing apples and oranges here. The only difference really is wether you have different something.tf files for the different stages or you have different variable files for the stages. The cons for the monolith are basically all incorrect, you simply should not have one deployment for your entire company, but nothing is stopping you from having one repository for one deployable artefact for one team. You should have the different deployables split like in your "micromodules" approach but the different modules should be the same for each environment.