Closed3

[Terraform + GithubActions] 複数環境で上手にTerraformの変更を適用するアイディア

harrythecodeharrythecode

課題

TerraformにはWorkspaceと言う環境を分ける際に便利な機能が存在する。環境ごとにTerraformの適用を切り分ける際、GithubActionsを用いた最適解が分からずに困っている。

前提条件

開発、ステージ、本番の3環境があると想定し、以下のディレクトリ構造をもとに解決策を模索する。

├── bootstrap
│   ├── env
│   │   ├── dev.tfvars
│   │   ├── prod.tfvars
│   │   └── staging.tfvars
│   └── terraform-code.tf
└── network
    ├── env
    │   ├── dev.tfvars
    │   ├── prod.tfvars
    │   └── staging.tfvars
    └── terraform-code.tf

[予備知識] 手動での運用

手動で環境を切り替える際の運用例は以下の通り。

$ cd bootstrap/
$ terraform workspace -h
Usage: terraform [global options] workspace

  new, list, show, select and delete Terraform workspaces.

Subcommands:
    delete    Delete a workspace
    list      List Workspaces
    new       Create a new workspace
    select    Select a workspace
    show      Show the name of the current workspace
$ terraform workspace select dev
$ terraform apply -var-file=env/dev.tfvars

Terraformコードは同じものを利用し、変数ファイルを環境に合わせて指定することでコードの簡略化が可能となる。

harrythecodeharrythecode

結論

Atlantis がすごく良さげ。

それ以外の方法

以下は、Atlantisと似たようなことを自作で行う場合の例です。

Workflowを作る。

[.github/workflows/deploy-to-bootstrap.yaml]

name: terraform-project

on:
  push:
    paths:
      - "terraform/bootstrap/**"
    branches:
      - 'main'
  pull_request:
    paths:
      - "terraform/bootstrap/**"

defaults:
  run:
    working-directory: terraform/bootstrap

jobs:
  terraform-example:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        site: [ "dev", "staging", "prod" ]
    steps: 
    - name: Checkout
      uses: actions/checkout@v2

    - name: Check diff
      id: diff
      uses: technote-space/get-diff-action@v6
      with:
        FILES: |
          ${{ matrix.site }}.lastupdate

    - name: Setup Terraform
      if: ${{ contains(env.MATCHED_FILES, matrix.site) }}
      uses: hashicorp/setup-terraform@v1

    - name: Terraform Init
      id: init
      if: ${{ contains(env.MATCHED_FILES, matrix.site) }}
      run: terraform init

    - name: Terraform Validate
      id: validate
      if: ${{ contains(env.MATCHED_FILES, matrix.site) }}
      run: terraform validate

    - name: Terraform Plan
      id: plan
      if: ${{ contains(env.MATCHED_FILES, matrix.site) && github.event_name == 'pull_request' }}
      run: terraform plan -var-file=env/${{ matrix.site }}.tfvars

    - name: Terraform Apply
      if: ${{ contains(env.MATCHED_FILES, matrix.site) && github.ref == 'refs/heads/master' && github.event_name == 'push' }}
      run: terraform apply -auto-approve -var-file=env/${{ matrix.site }}.tfvars

フォルダ構成は以下の通り。

├── change-when-to-apply
│   ├── dev.lastupdate
│   ├── prod.lastupdate
│   └── staging.lastupdate
├── env
│   ├── dev.tfvars
│   ├── prod.tfvars
│   └── staging.tfvars
└── terraform-code.tf

使い方例として、change-when-to-applyフォルダ内の変更対象の環境ファイルをcommitすると、その環境のみterraformコマンドを実行する、という感じです。

このスクラップは2022/03/15にクローズされました