使用 GitHub Actions 进行 Terraform 执行的自动化

想要将其自动化的感觉是什么?

    • Pull Request作成時にterraform planを実行し、その結果をPRにコメントしたい。

 

    • Pull Requestをマージしたときにterraform applyを実行したい。

 

    • tfstateをいい感じに分けたい。

 

    変更した部分だけterraformを実行したい。

下面是实际代码。

    • https://github.com/rinchsan/terraform-github-actions

 

    • ECRのリポジトリを1つ作るだけのシンプルな例です。

 

    公式が出している、GitHub ActionsでTerraformを自動化するチュートリアルは こちら にあります。

讲解

计划.yml

    planはPR作成時や変更時にGitHub Actionsを実行しましょう。
name: Plan
on:
  pull_request:
    branches:
      - master

strategy.matrix に何か配列を指定すると、それぞれを使って並列にジョブを実行することができます。
1つの tfstate ファイルに対応するディレクトリごとに strategy.matrix.dir に追記していくイメージです。

Dev環境、Stg環境などの環境ごとに resources/dev/ 、 resources/stg/ などに分割して strategy.matrix.dir に追加していくのがよくありそうです。

resources/dev/ 配下でさらに resources/dev/api/ とか resources/dev/worker/ みたいな感じでドリルダウンしていくのも良さそうです。

resources/dev/ecs/ とか resources/dev/rds/ みたいにリソースの種類ごとに分けるのもアリかもです。

jobs:
  plan:
    name: Plan
    runs-on: ubuntu-latest
    strategy:
      matrix:
        dir: [
          resources/shd/ecs,
        ]

    • とりあえずCheckoutしてきて、 technote-space/get-diff-action を使ってmasterとの差分を取得しましょう。

自分でgit diffするように実装してもいいと思うんですが、面倒ですよね。

ここで取得した差分が存在するかどうかによって、 matrix.dir ごとに terraform plan を実行するかどうかを後続のstepで判断します。

id に何か文字列を指定しておくと、後続のstepで実行結果などを参照することができます。

先ほど指定していた strategy.matrix.dir は ${{ matrix.dir }} みたいな感じで参照することができます。

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Check diff
        id: diff
        uses: technote-space/get-diff-action@v4.0.2
        with:
          PATTERNS: |
            modules/**/*.tf
            ${{ matrix.dir }}/**/*.tf

    • 今回はAWSを想定しているのでAWSの認証を行いましょう。

 

    ここでは普通にIAM Userのキーペアを使っていますが、会社のセキュリティ事情によってAssumeRoleとかでSessionTokenを取得しないといけなかったりする場合は、頑張ってください。
      - name: Configure aws credentials
        if: steps.diff.outputs.diff
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

    • Hashicorp公式が提供している hashicorp/setup-terraform を使って terraform コマンドをインストールしましょう。

if で steps.diff.outputs.diff を指定することで、 Check diff stepで差分が得られたときのみ実行するようにします。

      - name: Setup terraform
        if: steps.diff.outputs.diff
        uses: hashicorp/setup-terraform@v1.2.1
        with:
          terraform_version: 0.13.2

terraform fmt でフォーマットをチェックしておきます。
フォーマットはPRをマージするまでに直ればいいので、ここでは continue-on-error: true を指定して後続のstepは実行します。

      - name: Check format
        id: fmt
        if: steps.diff.outputs.diff
        run: terraform fmt -check -recursive
        working-directory: ${{ matrix.dir }}
        continue-on-error: true

${{ matrix.dir }} で terraform init を実行しましょう。
今回のサンプルではTerraformのBackend設定やProvider設定などを書いた init.tf をディレクトリごとに用意する想定ですが、このファイルを共通化したい場合はリポジトリルートに init/init.tf などを用意して、 ${{ matrix.dir }} にコピーしてから terraform init を実行したりするとよいでしょう。

${{ matrix.dir }} を元に tfstate の key を指定することもお忘れなく。

      - name: Initialize
        id: init
        if: steps.diff.outputs.diff
        run: terraform init
        working-directory: ${{ matrix.dir }}

terraform get で依存モジュールのダウンロードなどを行い、 terraform validate で設定を検証しましょう。

      - name: Download modules
        if: steps.diff.outputs.diff
        run: terraform get
        working-directory: ${{ matrix.dir }}

      - name: Validate
        if: steps.diff.outputs.diff
        run: terraform validate
        working-directory: ${{ matrix.dir }}

terraform plan を実行しましょう。

terraform plan で -no-color オプションを指定しているのは、後続のstepでPRにコメントを残す際に表示がおかしくなるのを防ぐためです。

      - name: Plan
        if: steps.diff.outputs.diff
        id: plan
        run: terraform plan -no-color
        working-directory: ${{ matrix.dir }}
        continue-on-error: true

actions/github-script を使って terraform fmt や terraform plan の結果をPRにコメントしてもらいましょう。
いちいちGitHub Actionsの実行結果ページへ行く必要がないので楽ですね。
このスクリプトは上述の公式チュートリアルにあるものを拝借しています。

      - name: Comment
        if: steps.diff.outputs.diff
        uses: actions/github-script@v3.0.0
        env:
          PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const output = `## \`${{ matrix.dir }}\`
            #### Terraform Format and Style ?\`${{ steps.fmt.outcome }}\`
            #### Terraform Plan ?\`${{ steps.plan.outcome }}\`

            <details><summary>Show Plan</summary>

            \`\`\`${process.env.PLAN}\`\`\`

            </details>`;

            github.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: output
            })

申请.yml

terraform apply はmasterブランチへのPush時に実行しましょう。

strategy まわりはplanと同様です。

name: Apply

on:
  push:
    branches:
      - master

jobs:
  apply:
    name: Apply
    runs-on: ubuntu-latest
    strategy:
      matrix:
        dir: [
          resources/shd/ecs,
        ]

    • applyでは最新のPRの差分を見て実行するかどうかを判断したいので、 ref と fetch-depth を指定します。

actions/checkout@v2 はデフォルトでは最新のコミット、つまり今回の場合はPRのマージコミットしかfetchしてくれないため、 HEAD^ と HEAD の差分を取得するために fetch-depth: 2 を指定します。

    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          fetch-depth: 2

terraform コマンドのインストールとAWSの認証はplanと同様に行います。

      - name: Setup terraform
        uses: hashicorp/setup-terraform@v1.2.1
        with:
          terraform_version: 0.13.2

      - name: Configure aws credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

    • 最後に HEAD^ との git diff を取って、 resources/ もしくは modules/ に変更があった場合のみ、 terraform apply を実行します。

 

    • 小さいですがあまりスクリプトは書きたくないなと思うので、いい感じに差分を取得できるアクションを書いてみたいですね。

 

    • この結果はGitHub Actionsの実行結果ページに行って確認しましょう。

もし失敗していたら新たに修正ブランチをmasterから切ってそのPRをマージする形で対応しましょう。

      - name: Apply
        run: |
          DIFF=$(git diff --name-only HEAD^ modules ${{ matrix.dir }})
          if [[ ${DIFF} = *resources* || ${DIFF} = *modules* ]]; then
            cd ${{ matrix.dir }}
            terraform init
            terraform get
            terraform apply -auto-approve
          fi
        shell: bash

印象

在一些不支持Orb的CircleCI上努力编写脚本来实现,写得相当漂亮和令人满意。

广告
将在 10 秒后关闭
bannerAds