ã¯ããã«
newmoã§ã¯Google Cloudçã®ãªã½ã¼ã¹ç®¡çã«Terraformã使ã£ã¦ãã¾ããã¾ããnewmoã§ã¯Monorepoã使ã£ã¦éçºãã¦ãã¾ãã Monorepoã«ã¤ãã¦ããã§ã¯è©³ãã説æãã¾ããããããã¯ã¨ã³ãã®Goã®ã³ã¼ããããã³ãã¨ã³ãã®TypeScriptã®ã³ã¼ããTerraformã®ã³ã¼ãããã¹ã¦åãGitHubã®ã¬ãã¸ããªã§ç®¡çãéçºãè¡ã£ã¦ãã¾ãã
Terraformã®ã³ã¼ããMonorepoã§ç®¡çãããã¨ã§ã以ä¸ã®è¦ç´ ãçµ±ä¸çã«å¶å¾¡ã§ããããã«ãªãã¾ãã
- CICDãã¤ãã©ã¤ã³
- Terraformã¨Providerã®ãã¼ã¸ã§ã³
- ã»ãã¥ãªãã£ããªã·ã¼
- Lintã«ã¼ã«
- ã¯ã©ã¦ããªã½ã¼ã¹ã®æ§æ
- ããã©ã¼ãã³ã¹ã¨ã³ã¹ãã®æé©å
ãªã½ã¼ã¹ãTerraformã®ã³ã¼ãã§ç®¡çããå ´åã«ç¨æããGitHubã§ã®Workflowã¯ä¸è¬çã«ã¯ä»¥ä¸ã®ãããªãã®ã«ãªãã¨æãã¾ãã
- Terraformã®ã³ã¼ããæ¸ãã¦Pull Requestã使ãã
- èªåçã«Terraformã®Planãå®è¡ããã
- Terraformã®ã³ã¼ãã¨Planã®çµæãã¬ãã¥ã¼ãã¦æ¿èªãã
- Mainãã©ã³ãã«ãã¼ã¸ããã¨èªåçã«Terraform Applyãå®è¡ããã

ç§ãããã¾ã§ä½åº¦ããã®ãããªWorkflowã使ãã¦å©ç¨ãã¦ãããã¨ãããã¾ããåç´ã«Planã¨Applyãå®è¡ããã ããªãé£ãããã¨ã¯ãã¾ããªãã®ã§ãããMonorepoã§ä»å¾åºãé·ã使ãããWorkflowã¨ãããã¨ã§ããå°ãè¦ä»¶ãåºã¦ãã¾ããã
- è¤æ°ã®Terraform stateã«é¢é£ããPull Requestã¯ä¸¦åã«å®è¡ããã
- Terraform ã®Plan, ApplyçµæãPull Requestã®ã³ã¡ã³ãã§éç¥ããã
- Applyã«å¤±æããã¨ãã«ããªãã©ã¤ããã
- 䏿çãªã¨ã©ã¼ã«ããApplyã失æããã±ã¼ã¹ãå¤ãããããªãã©ã¤æ©è½ã¯éè¦ã§ã
- Terraform stateãé²ãã§ããå ´åã«ã¯Applyããããªã
- ä»ã®Pull Requestãå ã«ãã¼ã¸ãããå ´åã«ã¯stateãå¤ãã£ã¦ããã®ã§ãPlançµæã¨ã¯éã夿´ãè¡ããã¦ãã¾ãã®ãé²ããã
- GitHub ã® Require branches to be up to date before mergingã§é²ããã¨ãã§ããããMonorepoã§æå¹ã«ããã¨ãã¼ã¸å¾ ã¡ãå¤ãçºçãã¦ãã¾ããããæå¹ã«ããããªã
- terraform fmt, terraform validateã«å ãã¦TFLintãTrivyã§ã³ã¼ãã®ãã§ãã¯ãããã
以ä¸ã®ãããªè¦ä»¶ããã¹ã¦èªåã§å®è£ ããã®ã¯çµæ§å¤§å¤ãªã®ã§å©ç¨å¯è½ãªãã¼ã«ãæ¢ãã¦ããã¨ããã tfaction ãç¥ãã¾ããã
tfactionã¨ã¯
tfaction - GitHub Actions ã§è¯ãæãã® Terraform Workflow ãæ§ç¯ ã«æ¦è¦ãæ¸ããã¦ãã¾ãããèªåãä¸ã§æãã¦ããè¦ä»¶ãæºãããããªGitHub Actionsã®Workflowãç°¡åã«æ§ç¯ã§ããActionã®ã»ããã§ãã
tfactionã®ä¸»ãªæ©è½ã¨ç¹å¾´
ããã§ã¯å®éã«ç§ãã¡ãå©ç¨ãã¦ããæ©è½ã ãç´¹ä»ãã¾ãã
1:é«åº¦ãªPlan/Apply管ç
- Pull Requestã³ã¡ã³ãã«Plançµæã表示
- Apply失ææã«Follow-up Pull Requestã®ä½æ
- plan fileãå©ç¨ããå®å ¨ãªApply
- remote stateãé²ãã å ´åã®Pull Requestã®èªåupdate
2: Planã¨Applyã®ä¸¦åå®è¡
GitHub Actions build matrixãå©ç¨ããWorkflow
3: ã»ãã¥ãªãã£ã¨ã³ã¼ãå質
- TFLint, Trivy, Conftestãªã©ã®ãµãã¼ã
- terraform fmtã®èªåå®è¡ï¼fmtãã¦ã³ããããã¦ãããï¼
4: local moduleã®ãµãã¼ã
ãããã®æ©è½ãGitHub Actionsã®Workflowãæ¸ãã ãã§å©ç¨ãããã¨ãã§ãã¾ãã AtlantisãHCP Terraformãªã©ã¨ã¡ããã¨æ¯è¼ããããã§ã¯ãªãã®ã§ãããtfactionã§ãããããã¨ãå®ç¾ã§ãã¦ãã¾ãã
newmoã§ã®å©ç¨
Monorepoã«ããããã£ã¬ã¯ããªæ§æ
newmoã§ã¯Monorepoã® lib/terraform 以ä¸ã«Terraformé¢é£ã®è¨å®ããã¨ãã°Terraform Moduleãtfactionã®è¨å®ãTFLintã®ã«ã¼ã«ãªã©ãç½®ãã¦ãã¦ãTerraformã®å®éã®ã³ã¼ãã¯ããã¤ãã®ãã£ã¬ã¯ããªã«åããã¦ãã¾ãã
Terraform stateã®ãµã¤ãºã管çå¯è½ãªç¯å²ã«ä¿ã¤ããããµã¼ãã¹åä½ã¨Provideråä½ã§ãã£ã¬ã¯ããªãåå²ãã¦ãã¾ãã
.
âââ lib
â âââ terraform
â âââ tfaction-root.yaml
â âââ tflint.hcl
â âââ modules
â â âââ # å
±éã§ä½¿ç¨ããTerraformã¢ã¸ã¥ã¼ã«
â âââ templates
â âââ # å
±éã§ä½¿ç¨ããTerraformãã³ãã¬ã¼ã
âââ server
âââ a
â âââ terraform
â âââ dev
â â âââ googlecloud
â â âââ cloudflare
â âââ prod
â âââ googlecloud
â âââ cloudflare
âââ b
âââ terraform
âââ dev
â âââ googlecloud
âââ prod
âââ googlecloud
tfactionã使ã£ãTerraform Workflowã®è¨å®
GitHub Actionsã®Workflowã®è¨å®ã®ä¾ã以ä¸ã«è¼ãã¦ããã¾ãã ããªãã³ã¼ããçç¥ãã¦ããã®ã§ãã®ã¾ã¾ã§ã¯åãã¾ããããè¨å®ã®é°å²æ°ã¯ä¼ãããã¨æãã¾ãã ãã¼ã¸ã§ã³ãçç¥ãã¦ãã¾ãããã®è¨å®ã®æç¹ã§ã¯tfaction v1.7.0ãå©ç¨ãã¦ãã¾ããã
name: CI Terraform Plan on: pull_request: paths: - lib/terraform/** - server/**/terraform/** concurrency: group: ${{ github.workflow }}--${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true env: AQUA_CONFIG: "${{ github.workspace }}/lib/terraform/aqua.yaml" TFACTION_CONFIG: "${{ github.workspace }}/lib/terraform/tfaction-root.yaml" jobs: setup: timeout-minutes: 10 outputs: targets: ${{ steps.list-targets.outputs.targets }} steps: - uses: actions/checkout - uses: aquaproj/aqua-installer - uses: suzuki-shunsuke/tfaction/list-targets id: list-targets plan: name: "terraform plan (${{ matrix.target.target }})" timeout-minutes: 30 needs: setup # skip if targets is empty if: join(fromJSON(needs.setup.outputs.targets), '') != '' strategy: fail-fast: false matrix: target: ${{ fromJSON(needs.setup.outputs.targets) }} env: TFACTION_TARGET: ${{ matrix.target.target }} TFLINT_CONFIG_FILE: "${{ github.workspace }}/lib/terraform/tflint.hcl" TRIVY_SEVERITY: HIGH,CRITICAL steps: - uses: actions/checkout with: sparse-checkout: | .github/actions lib/terraform ${{ matrix.target.working_directory }} - uses: aquaproj/aqua-installer - uses: suzuki-shunsuke/tfaction/get-target-config - run: github-comment exec -- github-comment hide - uses: suzuki-shunsuke/tfaction/setup - uses: suzuki-shunsuke/tfaction/test - uses: suzuki-shunsuke/tfaction/plan - name: Playbook if: failure() uses: ./.github/actions/playbook with: message: | # ${{ github.job }} ã失æãã¾ãã ## å½±é¿ - ãã®ã¾ã¾ã§ã¯ Terraform applyãã§ãã¾ãã ## èª¿æ»æ¹æ³ - Jobã®è½ã¡ã¦ãã¹ãããã®ã¨ã©ã¼ãã°ã確èªãã¦ãã ãã ## ä¿®æ£æ¹æ³ - Jobãretryãããã¨ã§è§£æ±ºããå ´åãããã¾ã - åãããªãå ´å㯠Platform Teamã¡ã³ãã¼ ã«èãã¦ãã ãã
æå¾ã®stepã«ããPlaybookã«ã¤ãã¦ã¯ GitHub Actionsã®Jobãè½ã¡ãã¨ãã«ä½ãããã¹ãããè¨è¿°ããPlaybookã®ä»çµã¿ãä½ã£ã¦éç¨ãã¦ãã話 - newmo æè¡ããã° ã®è¨äºã§è©³ããç´¹ä»ãã¦ãã¾ãã
tfactionã«ã¤ãã¦ã¯ã»ã¨ãã©ããã©ã«ãã®è¨å®ã®ã¾ã¾ä½¿ã£ã¦ãã¾ãã
tfaction-root.yamlã®è¨å®ã®ä¸é¨
# é«éåã®ããparallelism ã50ã«å¤ãã (defaultã¯10) env: TF_CLI_ARGS_plan: "-parallelism=50" TF_CLI_ARGS_apply: "-parallelism=50" # lintã®æå¹åï¼ããã©ã«ãã§æå¹ï¼ tflint: enabled: true trivy: enabled: true
TFLintã®è¨å®ã¯ãã¾ã ç¹å¥ãªãã®ã¯ãªãã§ãã
plugin "terraform" { enabled = true preset = "recommended" } plugin "google" { enabled = true version = "0.28.0" source = "github.com/terraform-linters/tflint-ruleset-google" } rule "terraform_naming_convention" { enabled = true }
ä»å¾ã®æ¹å
newmoã®Terraform Workflowã«ãããä»å¾ã®æ¹åç¹ã¨ãã¦èãã¦ãããã®ã«ã¯ä»¥ä¸ã®ãããªãã®ãããã¾ãã
TerraformãTerraform providerã®ãã¼ã¸ã§ã³ãçµ±ä¸ãã
monorepo内でのパッケージのバージョンを1つだけに統一するOne Version Ruleをpnpm catalogで実装する - newmo 技術ブログ ã§ç´¹ä»ããããã«ãnewmoã§ã¯ã§ããéãMonorepoå ã®TerraformãTerraform Providerã®versionãçµ±ä¸ãããã¨èãã¦ãã¾ããTerraformã¨ãã¦terraform.tfã«è¨è¿°ãããã¼ã¸ã§ã³ãå¤ããæå®ããæ©è½ã¯èªåãç¥ãéããªãã®ã§ãTerragrunt ãªã©ã®ãã¼ã«ã試ãã¦ã¿ãããããã¾ããã
ã»ã«ããµã¼ãã¹å
ç¾å¨ã¯Platform teamãä¸å çã«ã³ã¼ãã¬ãã¥ã¼ãè¡ã£ã¦ãã¾ãããéçºãã¼ã ã®å®å ¨ã§èªå¾çãªéç¨ã«åãã¦ä»¥ä¸ã®åãçµã¿ãæ¤è¨ãã¦ãã¾ã
- Terraform Moduleããé«åº¦ãªæ½è±¡å
- ãã¾ãã¾ãªã»ãã¥ãªãã£ããªã·ã¼ã®èªåãã§ãã¯
- TerraformãProviderã®èªåã¢ãããã¼ã
Workflowã®é«éå
ãµã¼ãã¹ãPlatformã®æé·ã¨ã¨ãã«ãWorkflowã®stepãå¢ãããTerraform stateã大ãããªã£ãããã¦Terraform Workflowã«ãããæéãå¢å ãã¦ãããã¨ãäºæ³ããã¾ãã ä»ã¯ã¾ã åé¡ã«ãªããã¨ã¯ãªãã§ãããTerraform Workflowã«è¦ããæéãè¨æ¸¬ãã¦ç¶ç¶çã«æ¹åãã¦ããããã¨èãã¦ãã¾ãã
OpenTofu?
ç§»è¡ãããã¨ã¯èãã¦ããªãã§ãããæ°ã«ãªã£ã¦ãã¾ãã
ã¡ãªã¿ã«tfactionã¯OpenTofuãTerraguntããµãã¼ããã¦ãããããªã®ã§ãã®ç¹ãå®å¿ã§ãã
ã¾ã¨ã
以ä¸ã®ããã«newmoã§ã¯Monorepoã«ããã¦tfactionãå©ç¨ãã¦Terraform Workflowãæ§ç¯ãã¦ãã¾ãã ç¹ã«ä»¥ä¸ã®ç¹ã§å¹æã宿ãã¦ãã¾ãï¼
- éç¨ããããã·ã³ãã«ãªWorkflowã®è¨å®
- Workflowã®èªååã«ããéç¨å¹çã®åä¸
- ã»ãã¥ãªãã£ã¨ã³ã¼ãå質ã®ç¢ºä¿
- ã¤ã³ãã©å¤æ´ã®å®å ¨æ§åä¸
GitHub Actionsã§ã®Terraform Workflowæ§ç¯ãæ¤è¨ããã¦ããçµç¹ã«ã¨ã£ã¦ãtfactionã¯åªãã鏿è¢ã¨ãªãã§ãããã 以åã¯ããã¤ãnewmoã®ã¬ãã¸ããªã«ãã£ããããªãé¨åããã£ãã®ã§ãããä½è ã® suzuki-shunsuke ããã«ç¸è«ãã¦v1.6.0ã«å ¥ãã¦ããã£ãæ¹åã«ãã£ã¦ä»¥åããå¿«é©ã«ä½¿ããããã«ãªãã¾ããã
æ¸ãã人: tjun