2022年1月1日 星期六

我的 2021 Terraform Codebase 專案結構

Terraform Codebase 專案紀錄: Terragrunt, Terraform module and maintain tips


使用工具:

  • Terragrunt (可以生成模板進行操作)
  • Terraform

專案目錄結構:

├── auto-deploy.sh (自動套用指令)
├── backend.tf (*Terragrunt)
├── data.tf (定義 terraform 資料)
├── destroy.sh (刪除指令)
├── main.tf (主檔案)
├── modules (獨立模組資料夾)
│   ├── bucket
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   └── vars.tf
│   ├── cloudflare_dns
│   │   ├── main.tf
│   │   ├── provider.tf
│   │   ├── terragrunt.hcl
│   │   └── vars.tf
│   ├── deployment_group
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── terrgrunt.hcl
│   │   └── vars.tf
│   ├── ecr
│   │   ├── main.tf
│   │   └── vars.tf
│   ├── eks_aws_origin_deprecated
│   │   ├── iam.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── provider_conf.tf
│   │   ├── sg.tf
│   │   ├── vars.tf
│   │   ├── versions.tf
│   │   └── vpc-zone.tf
│   ├── eks_node_group
│   │   ├── README.md
│   │   ├── context.tf
│   │   ├── iam.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── providers.tf
│   │   ├── subnet.tf
│   │   ├── variables.tf
│   │   ├── versions.tf
│   │   └── vpc.tf
│   ├── elasticache
│   │   ├── main.tf
│   │   └── terragrunt.hcl
│   ├── large-build-pipeline
│   │   ├── main.tf
│   │   ├── terragrunt.hcl
│   │   └── vars.tf
│   ├── peering
│   │   ├── main.tf
│   │   └── var.tf
│   ├── pipeline
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── schedule.tf
│   │   ├── terragrunt.hcl
│   │   └── vars.tf
│   ├── rabbitmq
│   │   ├── main.tf
│   │   ├── output.tf
│   │   ├── sg.tf
│   │   ├── subnet.tf
│   │   ├── vars.tf
│   │   └── vpc.tf
│   ├── rds-mysql
│   │   ├── db.tf
│   │   ├── iam.tf
│   │   ├── main.tf
│   │   ├── sg.tf
│   │   ├── subnets.tf
│   │   ├── terragrunt.hcl
│   │   ├── vars.tf
│   │   └── vpc.tf
│   ├── rds-postgresql
│   │   ├── db.tf
│   │   ├── iam.tf
│   │   ├── main.tf
│   │   ├── output.tf
│   │   ├── sg.tf
│   │   ├── subnets.tf
│   │   ├── terragrunt.hcl
│   │   ├── vars.tf
│   │   └── vpc.tf
│   ├── server
│   │   ├── iam.tf
│   │   ├── main.tf
│   │   ├── output.tf
│   │   ├── sg.tf
│   │   ├── subnets.tf
│   │   ├── terragrunt.hcl
│   │   ├── vars.tf
│   │   └── vpc.tf
│   ├── server_with_rds
│   │   ├── db.tf
│   │   ├── iam.tf
│   │   ├── main.tf
│   │   ├── output.tf
│   │   ├── sg.tf
│   │   ├── subnets.tf
│   │   ├── terragrunt.hcl
│   │   ├── vars.tf
│   │   └── vpc.tf
│   └── web
│       ├── main.tf
│       ├── outputs.tf
│       └── vars.tf
├── output.sh (把 terraform 輸出丟到 ansible, k8s 資料夾的指令)
├── output.tf (輸出資料定義)
├── policies (各種 AWS Policies JSON 描述檔案)
│   ├── aws_load_balancer_controller_policy.tpl
│   ├── build_role_assume_policy.tpl
│   ├── build_role_policy.tpl
│   ├── codedeploy_assume_policy.tpl
│   ├── codepipeline_assume_policy.tpl
│   ├── codepipeline_policy.tpl
│   ├── deploy_policy.tpl
│   ├── ec2_assume_policy.tpl
│   ├── ec2_role_policy.tpl
│   ├── eks_role_assume_policy.tpl
│   ├── node_instance_role_policy.tpl
│   ├── public_bucket_policy.tpl
│   └── registerer_policy.tpl
├── provider.tf (*Terragrunt 會產生的檔案)
├── terragrunt.hcl (*Terragrunt)
├── vars (*Terragrunt 讀取的環境變數)
│   ├── common.yml
│   └── production.yml
└── vars.tf (terraform 的變數)


專案結構是採模組化,不把 resource 直接寫在 main.tf,在 main.tf 中的都是用 module xxx {} 進行引用。

模組化的功能都會放在 modules,然後 policies 裡面會放 Assume Role, Policy 的描述 JSON 檔案。

採用模組化的話,一個模組的單位可以被實作為兩種風格,但建議只選擇一種風格:
  1.  通用模組
  2.  特定規格模組

建議是不要混用,尤其是不要在特定規格模組中使用 "自訂" 的通用模組,應該要把這兩個風格區分,建議要不就是全部都走通用模組,那整個建構邏輯就會在 main.tf,如果要走特定規格模組,就是要針對每個不同需求的基礎建設設計 tf 檔案。

模組內,通常一個領域就會是一個檔案名稱,常見像是:
  • provider.tf
  • version.tf
  • vars.tf
  • output.tf
  • main.tf
  • data.tf
除了基本款的 tf 以外,也會按照雲端資源區分,像是:

  • iam.tf
  • vpc.tf
  • subnet.tf
  • sg.tf (security_group)
  • ec2.tf
  • rds.tf
  • loadbalance.tf
  • route53.tf
  • storage.tf
  • bucket.tf
  • cloudfront.tf
  • codecommit.tf

2021 還沒解掉的問題: 我用了 cloudflare 的 terraform 模組,就算寫了 depends_on ,我都還是要 apply 兩次才能夠成功更新紀錄,我猜是 EIP 的問題。


一些常用的自動化指令腳本



我自己有寫自動化執行的腳本,主要是 output.sh ,可以輸出相對應的資源到 ansible 上,這樣我就不用手動去拿 IP,比較方便快速。

詳情腳本可以參考: https://github.com/hpcslag/infrastructure_boilerplate/blob/main/terraform/output.sh

關於套用模組自動化,我自己有寫一個 auto_apply.sh 腳本,裡面就是 init, plan, apply 三行一起執行,這樣我就不用手動重新輸入指令。


關於一些雲端資源模組的習慣


有一些資源我傾向不透過 Terraform 管理,或是要區分 Workspace、TF 檔案,不要寫在一起:

  1. CodeCommit
  2. 重要檔案的 S3

這些東西如果不小心被 destroy 掉會很危險,我的作法是不管理,把名稱 Hard  Code 到模組變數或 var 中就好,要不然就是區分 terraform 腳本,這個腳本應該要是很少更新的 workspace。

另一個習慣是盡量自己寫模組,就算是參考別人的範例,也要 copy 出來自己改,基本上我會需要對每一個資源有一定程度的了解,我從新手到了解模組是有經過蠻長一段時間陣痛期,因為資源太多,有些資源並不是真的很了解它的用途,但如果要做 DevOps 是一定要看白皮書,也要全盤理解的。

對於他人的模組,我會盡量少用,除非自己建立真的壞處很多,像是 EKS 這種龐大資源我就會使用 cloudposse,但還是希望有朝一日可以拔掉它。


我覺得一個更重要的習慣是,Subnet、VPC 也很重要!  很多資源範例都會隨便給 VPC, Subnet 分配,但其實這個是很重要的課題,如果你需要區分相同服務的內網,你可能就會需要共用一個 VPC 給好幾個服務,如果你的機器底下有分配網段需求,你的 VPC CIDR 切的 Subnet Mask 就要事前先算好,網路上有一些子網路計算機,可以幫助你了解 10.0.0.0/N 要開多少,符合你機器的要求。

特別是 Subnet 有些都會套用 public, private 或甚至 available_zone 在不同區域,那你就必須確保這個地址夠用。

也就是說,複製範例上用的 VPC CIDR,也記得要調整一下可用網段,要不就共用需要的資源服務。

沒有留言:

張貼留言

© Mac Taylor, 歡迎自由轉貼。
Background Email Pattern by Toby Elliott
Since 2014