LoginSignup
4
2

More than 3 years have passed since last update.

GitHub ActionsでTerraformのCI環境を構築してみた

Last updated at Posted at 2020-04-19

概要

以前、個人開発 Advent Calendar 2019 に寄稿させて頂きました 副業でTerraform化した時のお話 の環境に対して、GitHub Actions上でTerraformのCI(fmt, validate, planなど)を実行してくれる環境を作ってみたもののまとめです。

現状のTerraformの構成

上記の記事でも書かせて頂いておりますが、現状のAWSやアプリケーションの構成上、下記の方針に沿った構成にしております。

  • 各アプリケーションの構成がそれぞれでそんなに異ならないので、何度も同じ記述をするのは避けたい → moduleを使って各アプリケーションの構築を簡単に作れるようにする
  • test、staging、productionのように、各環境にアプリケーションを構築したい → workspaceを使って環境毎の構築を簡単に作れるようにする

その構成は構成※にしてみました(一部抜粋)。

├── app
│   └── serviceA
│       ├── _tfvars
│       │   └── <<各種環境毎のtfファイル>>
│       └── <<各種tfファイル>>
├── modules
│   ├── codebuild
│   │   └── <<各種tfファイル>>
│   ├── codepipeline
│   │   └── <<各種tfファイル>>
│   └── ecs
│       └── <<各種tfファイル>>
├── network
│   └── <<各種tfファイル>>
├── pipeline
│   └── serviceA
│       └── <<各種tfファイル>>
└── その他のファイル(READMEなど)

※前回の記事に引き続き、「なんでそこ分けた?」などあるかもしれませんが、現状のネットワークやアプリケーション構成などに合わせたこともありこのような構成にしております。もしこういう構成にするともっと良いかも!などありましたら、ご教授いただけると嬉しいですmm

やりたいこと

今回のCI環境構築にむけてやりたかったこと、いわゆる要件は下記になります。

  1. 変更した箇所に応じて、fmt, validate, planを実行してほしい(修正した箇所と関係ない箇所は、特に何もしない)
  2. planの実行結果などはPull Requestのコメントとかに貼ってくれると嬉しい
  3. アプリケーション環境はtest, staging, productionの3つあるので、アプリケーションに関係する箇所の修正が入ったら、その3つの環境(workspace)でplanの実行はしてほしい
  4. CI実行タイミングとしては、Pull Requestを作成(reopenや再度commitなども含む)したタイミングと、masterにマージしたタイミング
  5. masterにマージした際の結果は、リポジトリのトップページ(README)でbadgeとして見れるようにしたい

やったこと

0. 作成したワークフロー

今回対応してみたのは、上記構成の中でも下記の3つを対応してみました。

  1. network
  2. pipeline
  3. application

applicationはmoduleを使いつつ、かつworkspaceも使っていたので、そこを中心に記載していきたいと思います。

1. 変更した箇所に応じてCI実行

この変更した箇所に応じて〜というのは、GitHub Actionsの on.<push|pull_request>.paths を指定することで実現できます。

application.yaml
・・・・・
on:
  pull_request:
    types: [opened, synchronize, reopened]
    branches: [master]
    paths:
      - modules/hogehoge/**
      - modules/fugafuga/**
      - app/serviceA/**
  push:
    branches: [master]
    paths:
      - modules/hogehoge/**
      - modules/fugafuga/**
      - app/serviceA/**
・・・・・・

上記のように paths に対して、指定のファイル or ディレクトリに修正が入ったら(正確にPull Request or Pushされたら)、
該当のワークフローが動くようにしました。
modules に修正が入った場合でも、それを使用しているアプリケーション(この場合だとserviceA)のplan結果が問題ないかもチェックしたいので、pathsにmodulesも指定しております。

2. planの実行結果などはPull Requestのコメントとかに貼ってくれると嬉しい

GitHub Actions上でTerraformを動かすサンプルに関しては、 Terraform公式のGet Startedが参考になります。
実際の init , fmt , validate , plan はこのサンプルをほぼそのまま使っております。

application.yaml
・・・・・
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: Terraform Init
        uses: hashicorp/terraform-github-actions@master
        with:
          tf_actions_version: 0.12.24
          tf_actions_subcommand: "init"
          tf_actions_working_dir: ${{ matrix.workdir }}
          tf_actions_comment: true
      - name: Terraform Validate
        uses: hashicorp/terraform-github-actions@master
        with:
          tf_actions_version: 0.12.24
          tf_actions_subcommand: "validate"
          tf_actions_working_dir: ${{ matrix.workdir }}
          tf_actions_comment: true
      - name: Terraform Plan
        uses: hashicorp/terraform-github-actions@master
        with:
          tf_actions_version: 0.12.24
          tf_actions_subcommand: "plan"
          tf_actions_working_dir: ${{ matrix.workdir }}
          tf_actions_comment: true
・・・・・

${{ matrix.workdir }} はこの後に出てきます><

特に plan の結果はPull Requestに貼ってほしいので、 tf_actions_comment: true にしております。
これで下記のようにコメントを貼ってくれます。

スクリーンショット 2020-04-19 16.32.01.png

Show Output をクリックすると、詳細なplanの結果が表示されます

3. 各環境毎にplanを実行してほしい

GitHub Actionsには jobs.<job_id>.strategy.matrix というものがあり、その中の説明を引用すると、下記になります。

様々なジョブの設定のマトリックスを定義できます。 マトリックスによって、単一のジョブの定義内の変数の置き換えを行い、複数のジョブを作成できるようになります。

これを利用して各環境(workspace)毎にplanを実行してもらえば良さそうです。
ここで1つ気になったのが、
「アプリケーションのplanは各環境(workspace)毎に実施してほしいが、fmtは環境毎じゃなくて、対象のディレクトリ配下だけ良い」
としたい場合、job(job_id配下)にまとめて実行してほしいことを指定しまうと、環境毎にfmtを実行されてしまう?という部分でした。そのため、

  • まずは対象のディレクトリ配下に対してfmt を実行
  • fmtが問題なければ、各環境(workspace)毎にplan を実行

のように直列でやってみることにしました。

まずは対象のディレクトリ配下に対してfmtを実行は下記。

application.yaml
・・・・・
jobs:
  format:
    name: Terraform Format
    runs-on: ubuntu-latest
    strategy:
      matrix:
        workdir: [./modules/hogehoge, ./modules/fugafuga, ./app/serviceA]
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: Terraform Format
        uses: hashicorp/terraform-github-actions@master
        with:
          tf_actions_version: 0.12.24
          tf_actions_subcommand: "fmt"
          tf_actions_working_dir: ${{ matrix.workdir }}
          tf_actions_comment: true
・・・・・・
・・・・・

workdir に実行したディレクトリ毎にfmtを実行してくれます。ちなみにfmtはデフォルトで -recursive がつくみたいなので、指定したディレクトリを再起的にチェックしてくれます。

その後に 各環境(workspace)毎にplan を実行したいので、下記のようにします。

application.yaml
・・・・・
  check:
    name: Terraform Init, Validate, Plan
    runs-on: ubuntu-latest
    needs: format
    strategy:
      matrix:
        env: [test, staging, production]
        workdir: [./app/serviceA]
    env:
    # GitHubのsecretsに登録したもので必要なものをここで変数定義してあげる
      TF_WORKSPACE: ${{ matrix.env }}
      TF_CLI_ARGS_plan: "--var-file=\"_tfvars/${{ matrix.env }}.tfvars\""
    steps:
      # 上記の2で紹介した内容と同様、下記は一部抜粋
      - name: Terraform Plan
        uses: hashicorp/terraform-github-actions@master
        with:
          tf_actions_version: 0.12.24
          tf_actions_subcommand: "plan"
          tf_actions_working_dir: ${{ matrix.workdir }}
          tf_actions_comment: true
・・・・・

まずは needsformat を指定することで、 fmt が完了したらplanなどが実行されるようにしております。

あとはこちらも jobs.<job_id>.strategy.matrixenv のように環境毎(workspace毎)の値を指定して、環境毎にパラレルでplan等が実行できるようにしてみました。

その際、 TF_WORKSPACE: ${{ matrix.env }} のようにすることで、Terraformのplan実行時のworkspaceを指定できます。
それと、各環境毎で必要な hogehoge.tfvars は、

TF_CLI_ARGS_plan: "--var-file=\"_tfvars/${{ matrix.env }}.tfvars\""

のように指定するば、plan実行時のパラメータとして渡されます。

このtfvarsですが、現状はcredentialのようなGitHubにあげるとまずい情報は入っていないので良いですが、
ここにGitHubにあげるとまずい情報が入り、それが環境毎に異なるとなると、実行方法を考え直さないといけないかもしれません。

4. CI実行タイミング

こちらは1ですでに出ておりますが、

application.yaml
・・・・・
on:
  pull_request:
    types: [opened, synchronize, reopened]
    branches: [master]
    paths:
      - modules/hogehoge/**
      - modules/fugafuga/**
      - app/serviceA/**
  push:
    branches: [master]
    paths:
      - modules/hogehoge/**
      - modules/fugafuga/**
      - app/serviceA/**
・・・・・・

こちらのように on にトリガーとしたいアクションを追加すれば良いだけです。
上記ではbranchのみ指定しておりますが、tagなども指定できるようです。

5. GitHub Actionsの結果badge

GitHub Actionsはbadgeも提供してくれているようで、こちらにbadge URLの命名規則が載っております。

もしくは下記のように Actions のページで 対象ワークフロー を選択し、 Create Status BadgeをクリックするとbadgeのURLを表示してくれます。
スクリーンショット 2020-04-19 17.14.14.png

しかもbranchやEventが選択可能で、それに応じたURLを生成してくれます。
スクリーンショット 2020-04-19 17.17.46.png

あとは、そのURLをREADMEに貼っておくと下記のように表示されます。
スクリーンショット 2020-04-19 17.20.10.png

今後

以上が現状の構成に対してGitHub Actionsを導入してCI環境を構築してみたまとめになります。

あとは、masterにマージしたら自動で実行する部分も入れていきたいのですが、
Terraform運用がまだ短く、自動で実行するのがちょっとだけ怖いので、applyは今も手動で実行しております。
ゆくゆくはapplyする環境(CD環境)もGitHub Actionsに組み込んでいきたいです。

最後に、拙い文章で大変恐縮ではございましたが、読んでいただきましてありがとうございました。

参考

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2