GitHub Actions × Terraform Cloud

こんにちは Development Team の滝波です。

今回は GitHub Actions と Terraform Cloud を連携させたことによって、AI Shiftのインフラ構築の開発フローが劇的に改善した内容やその連携方法、はまりポイントなどを紹介していきたいと思います。

はじめに

AI Shift では Terraform Cloud (ver 0.13.6) を使用してインフラのコード化を行っており、GitHub とも連携してプルリクエストのマージをトリガーにTerraform Cloud 上で Terraform コマンドが実行されるフローを採用していましたが、そこにはいくつかの課題がありました。

  • プルリクエストをマージしてからでないと terraform plan の実行結果が確認出来ないため※1、マージ後に plan が失敗してしまうと、修正したプルリクエストを都度上げ直す必要がありました。そのため動作しない可能性のあるコードがマージされてしまう問題があるうえに、失敗した場合のプルリクエストの生成が非常に手間になっていました。
  • 実行結果の確認を Terraform Cloud のコンソールに移動しないと出来なかったため、GitHub と Terraform Cloud の画面を行ったり来たりする必要があり、これもまた効率の悪いフローになっていました。

しかし、そんな中、去年の8月にGitHubが Forkされたリポジトリからのプルリクでも、GitHub Actions が実行可能 になるアップデートが行われたことによって、AI Shift でも GitHub Actions と Terraform Cloud を連携して、大幅に開発フローの改善を実現することができました。※2

下記は、今回の実行フローの改善前の Before と改善後の After になります。そして図からもわかるように、開発者のやりとりするインターフェイスは1つに集約され、plan の結果はプルリクエストのマージ前に確認することができるようにもなったので、仮に plan が失敗しても、Before では複数画面を行き来しながら 1~4 を繰り返す必要があったのに対して、 After は GitHub を介して 1,3 のみで完結するようになりました。

Before

After


※1 セキュリティの観点から、Forkされたリポジトリからのプルリクエストでplan 実行が許可されてませんでした

※2 GitHub Flow を採用して開発しているため、それまで GitHub Actions が使えない状態でした

ディレクトリ構造

今回はもともと workflow が VCS (GitHub) と連携しているのを前提に連携手順を進めていきたいと思いますが、新規で workflow を作成する場合でも同じような手順になります。
さて、手順を説明するその前に、簡単に AI Shift で Terraformの各種設定ファイルをどのようなディレクトリ構成で管理しているかを紹介したいと思います。

AI Shiftでは Standard Module Structure というモデルをベースに、各環境毎にエントリーポイントとなる Root module を作成して各 Module を管理する構成をとっています。Moduleは mysql、pubsub のようにサービス毎にディレクトリを分け、それぞれに必要な設定を記述しています。
環境毎に設定が分かれているため、冗長になりやすい面はありますが、それ以上に直感的な構造になっているので Terraform に精通していないメンバーでも短い期間でキャッチアップできるメリットがあると感じています。

 dev
 ├── README.md
 ├── main.tf
 ├── variables.tf
 ├── outputs.tf
 ├── modules/
 │   ├── mysql/
 │   │   ├── README.md
 │   │   ├── variables.tf
 │   │   ├── main.tf
 │   │   ├── outputs.tf
 │   ├── pubsub/
 │   ├── .../

それでは、実際に連携手順を説明していきましょう。

設定手順

1. workflowをAPIで連携するように変更

現状の State は維持したいので、新しい WorkSpace は作らず、既存の WorkSpace の連携方法を Version control workflow から API-driven workflow に変更します。

これにより、今までプルリクがマージされてから実行されていたものが、API経由(今回は GitHub Acitions)で実行されるようになります。

2.GitHub Actions を設定

実行内容は以下の通りです。

  1. terraform fmt -check -recursive
  2. terraform init
  3. terraform plan
  4. terraform apply -auto-approve

AI-Shift では各開発環境毎に Terraform の workspace を作成しているため、環境毎に GitHub Actions の workflow を作成して、各環境のファイルが変更された場合のみ Terraform が反応するように paths で制御を行っています。

workflowの設定は以下になります。

on:
  push:
    paths:
    - your/terraform/path/dev/**
    branches:
      - master
  pull_request:
    paths:
    - your/terraform/path/dev/**
jobs:
  terraform:
    name: 'Dev Networking Terraform'
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./your/terraform/path/dev
    steps:
    - name: Checkout
      uses: actions/checkout@v2
    - name: Setup Terraform
      uses: hashicorp/setup-terraform@v1
      with:
        cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
    - name: Terraform Format
      id: fmt
      run: terraform fmt -check -recursive
    - name: Terraform Init
      id: init
      run: terraform init
    - name: Terraform Plan
      id: plan
      if: github.event_name == 'pull_request'
      run: terraform plan
      continue-on-error: true
    - name: Terraform Plan Status
      if: steps.plan.outcome == 'failure'
      run: exit 1
    - name: Terraform Apply
      if: github.ref == 'refs/heads/master' && github.event_name == 'push'
      run: terraform apply -auto-approve

3. main.tf に追記

VCS と連携している場合には下記設定は不要でしたが、今回はAPIで連携することなるので、下記設定を追加する必要があります。

terraform {
  backend "remote" {
    organization = "your-organization"

    workspaces {
      name = "your-workspace-dev"
    }
  }
}

以上、ここからはさっそく設定した内容でプルリクを投げて見て、動作を確認してみましょう。

動作確認

今回は動作確認用にグローバルIPを発行してみます。

プルリクエストを生成

プルリクエストを投げると、GitHub Actions が起動し、設定した各 Terraformコマンドを実行してくれます。

GitHub Actions の画面で Plan 内容の確認

Planが成功していることが確認できたので、実際にマージしてみます。

Actions タブで apply が成功しているのを確認

もちろんTerraform Cloudのコンソール画面からも確認することができます。

はまりポイント

Terraform Cloud のバージョンが0.12系の場合にはじめてAPI連携を行うと、初期化時に0.13系へアップデートをするようエラーが出る場合があるのですが、これはTerraform Cloud のコンソールからバージョンを上げるだけでは解決しないのでご注意ください。
この場合、コンソールからバージョンを上げたあとに Terraform Cloud 上の state を更新する必要があるため、別途適当なプルリクエストをマージして state を更新する必要があります。

これはAPI連携に限らず、「Terraform Cloud のコンソールでバージョンを上げても現状の stateは更新されない」ということだけ覚えておくといいかもしれません。

おわりに

以上、GitHubActions と Terraform Cloud の連携方法とはまりポイントの紹介になりました。
Terraform Cloud は比較的に新しいサービスということもあって情報が少なく困ることも多いですが、AI Shift では積極的に活用してるサービスの1つでもあるので、アップデート情報などあれば随時情報発信していきたいと思っています。

それでは、Happy Terraforming!

参考

https://learn.hashicorp.com/tutorials/terraform/github-actions