HCP Terraform の GitHub 連携: VCS-driven workflow の設定

公開

インフラの変更は、アプリのコードと同じように PR でレビューしてから反映したい。

HCP Terraform の workspace を GitHub のリポジトリにつなぐと、run(plan や apply の実行)を GitHub の操作から始められる。

PR を出すと plan が実行され、マージすると apply まで進む。

この記事では、workspace をリポジトリにつないで、次の 3 つを確かめる。

  • PR を出したときに始まる run と、PR に表示される結果
  • main にマージしたときに始まる run が、承認なしで apply まで進むこと
  • つないだあとは、ローカルの terraform apply が断られること

前提

workspace tfc-study-stg が AWS の S3 バケットを 1 つ管理していて、run はローカルの terraform コマンドから始めている状態(「HCP Terraform の AWS 連携: Dynamic provider credentials の設定」を参照)から始める。

VCS-driven workflow の仕組み

VCS は version control system の略で、この記事では GitHub のこと。

HCP Terraform の run を始める形は 2 つある。

  • CLI-driven workflow
    • ローカルの terraform plan や terraform apply が run を始める
    • run に使う .tf は、コマンドがローカルのディレクトリから送る
  • VCS-driven workflow
    • リポジトリへの push や PR が run を始める
    • run に使う .tf は、HCP Terraform がリポジトリから取得する

この記事では、CLI-driven workflow の workspace を VCS-driven workflow に変える。

GitHub の操作と run の対応

workspace は、リポジトリの 1 つのブランチ(この記事では main)につなぐ。つなぐと、GitHub の操作で次の run が始まる。

GitHub の操作 始まる run apply
main 宛ての PR を作る、更新する plan だけの run(speculative plan) 進めない
main に push する、PR をマージする plan と apply の run plan のあと、承認を待つか自動で進む

push や PR があったことは、GitHub が HCP Terraform に通知(webhook)する。

設定するもの

GitHub に 1 つ、HCP Terraform の workspace に 2 つ設定する。

  • GitHub App
    • HCP Terraform 用のアプリで、名前は Terraform Cloud。GitHub のアカウントにインストールする
    • HCP Terraform がリポジトリの中身を読み、push や PR の通知を受け取れるようになる
  • VCS connection
    • workspace の設定。run に使う .tf をどのリポジトリのどのブランチから取得するかを決める
  • auto-apply
    • workspace の設定。plan が成功した run を、承認を待たずに apply まで進める

run に使う .tf を GitHub のリポジトリに置く

workspace につなぐリポジトリを GitHub に作り、main ブランチに次のファイルを置く。

  • .tf ファイル
  • .terraform.lock.hcl(provider のバージョンを固定するファイル)
  • .gitignore(.terraform/ をリポジトリに入れないため)

この記事で変更するのは、S3 バケットを定義している main.tf。

main.tf
resource "random_pet" "name" {
  length = 2
}

resource "aws_s3_bucket" "study" {
  bucket = "tfc-study-${var.environment}-${random_pet.name.id}"

  tags = {
    Environment = var.environment
    Owner       = var.owner
  }
}

リポジトリの .tf は、workspace の state と差分がない状態にしておく。つないだ直後の run で、意図しない変更が出ないようにするため。

GitHub の操作で run が始まるように workspace をリポジトリにつなぐ

HCP Terraform の画面で workspace を開き、左のメニューの Settings → Version Control から設定する。

  1. Connect to version control を押し、Version control workflow を選ぶ
  2. 接続先に GitHub.com を選ぶ
  3. リポジトリの一覧から、.tf を置いたリポジトリを選ぶ
  4. 設定を確認して Update VCS settings を押す

GitHub App にリポジトリを見せる

  1. の一覧に出るのは、GitHub App(Terraform Cloud)が見えるリポジトリだけ。一覧が空のときは、GitHub で次の設定をする。

  2. GitHub の Settings → Applications で、Terraform Cloud の Configure を開く

  3. Repository access で Only select repositories を選び、つなぎたいリポジトリを追加する

アプリに見せるリポジトリは、このように使うものだけに絞れる。

VCS connection の設定

  1. の画面には次の設定がある。この記事ではすべて既定のままにした。
設定 既定 意味
Terraform Working Directory リポジトリの直下 terraform を実行するディレクトリ
Automatic Run Triggering Always trigger runs run を始めるきっかけになるファイル。既定はすべてのファイル
VCS Branch 既定のブランチ push で run を始めるブランチ
Automatic speculative plans 有効 PR で plan だけの run を始めるか

つないだ直後に始まる run

つなぐと、HCP Terraform が main の最新のコミットを取得し、run が 1 つ始まる。

Run List の先頭の run。名前はコミットメッセージの Add S3 bucket for tfc-study、triggered via GitHub、Branch main、コミットのハッシュが表示され、状態は Planned and finished

一覧から読み取れることは 3 つ。

  • run の名前はコミットメッセージになる
  • triggered via GitHub と、ブランチ、コミットのハッシュが表示される。どのコミットの .tf で実行した run かが分かる
  • リポジトリの .tf と state に差分がないので、plan だけで終わっている(Planned and finished)

リポジトリ以外から変更が入らないようにローカルの apply は断られる

リポジトリにつないだ workspace では、ローカルの terraform apply を実行できない。

$ terraform apply
╷
│ Error: Apply not allowed for workspaces with a VCS connection
│
│ A workspace that is connected to a VCS requires the VCS-driven workflow to ensure that the VCS remains the single source of truth.
╵

ローカルの .tf をそのまま apply できると、main にない変更が AWS に入ってしまう。apply の入口をリポジトリだけにすることで、それを防いでいる。

terraform plan は実行できる。plan だけの run で、state を変えないため。PR を作る前に、ローカルで差分を確かめたいときに使える。

マージで apply まで進めるために auto-apply を有効にする

VCS-driven workflow の run は、既定では plan のあとで止まり、画面の Confirm & Apply が押されるのを待つ。

マージしたらそのまま反映したい workspace では、Settings → General の Auto-apply を有効にする。

有効にすると、plan が成功した run は承認を待たずに apply まで進む。

マージで始まる run が plan で止まるか apply まで進むかは、この設定 1 つで決まる。

マージ前に差分を確かめるために PR を出す

バケットにタグを 1 つ追加する変更で PR を作る。main.tf の tags に ManagedBy の行を追加する。

main.tf
  tags = {
    Environment = var.environment
    Owner       = var.owner
    ManagedBy   = "terraform"
  }

ブランチ add-managed-by-tag にコミットして push し、main 宛ての PR を作る。

PR を作ると、起きることは 5 つ。

sequenceDiagram
    participant me as 自分
    participant gh as GitHub
    participant hcp as HCP Terraform
    participant env as run の実行環境

    me->>gh: 1. PR を作る
    gh->>hcp: 2. PR ができたことを通知する
    hcp->>gh: 3. PR のブランチの .tf を取得する
    hcp->>env: 4. plan だけの run を実行する
    hcp->>gh: 5. 結果を PR に返す
  1. main 宛ての PR を作る
  2. GitHub が HCP Terraform に通知する
  3. HCP Terraform が、PR のブランチ(add-managed-by-tag)の .tf を取得する
  4. その .tf と workspace の state で、plan だけの run を実行する
  5. plan が成功したかどうかを、PR に返す

PR に表示される結果

PR のページのチェックの欄に、HCP Terraform の結果が 1 行出る。

GitHub の PR のページ。Checks の欄に Terraform Cloud で始まる名前のチェックが 1 件あり、Success と表示されている
  • 名前は Terraform Cloud/<organization>/repo-id-<ID> の形
  • plan が成功すると Success になる
  • PR に出るのは成功か失敗かだけ。plan の中身は、この行のリンクから HCP Terraform の run のページを開いて確かめる

plan だけで終わる run

PR から始まった run のページは次のとおり。

PR から始まった run のページ。状態は Planned and finished。triggered a pull request run (#1) from GitHub と表示され、plan は 1 to change で、aws_s3_bucket.study の tags と tags_all に ManagedBy が追加される。下に This run was started from a pull request and cannot be applied と表示されている
  • triggered a pull request run (#1) from GitHub と表示される。PR の番号が入る
  • plan は 0 to add, 1 to change, 0 to destroy。バケットの tags に ManagedBy が追加される
  • 状態は Planned and finished。apply の段階はなく、Confirm & Apply も出ない

ページの下には次の文が出る。

This run was started from a pull request and cannot be applied. To apply these changes the pull request must first be merged into the default branch.

(この run は PR から始まったもので、apply できない。変更を apply するには、先に PR を既定のブランチにマージする必要がある)

PR の run は、マージしたら何が起きるかを見せるだけ。state も AWS のバケットも変えない。

マージして apply まで進むことを確かめる

PR をマージすると、main に新しいコミットが入り、run が始まる。

マージで始まった run のページ。名前は Merge pull request #1、状態は Applied。triggered a run from GitHub と表示され、Plan finished は 1 to change、Apply finished は 1 changed で、aws_s3_bucket.study が Updated になっている
  • run の名前はマージコミットのメッセージ。triggered a run from GitHub と表示される
  • plan の結果は PR のときと同じ 1 to change
  • Confirm & Apply で止まらず、そのまま apply に進んで Applied で終わる。auto-apply を有効にしたため

AWS のバケットを確かめると、タグが追加されている。

$ aws s3api get-bucket-tagging --bucket tfc-study-stg-national-starfish
{
    "TagSet": [
        {
            "Key": "Environment",
            "Value": "stg"
        },
        {
            "Key": "Owner",
            "Value": "<owner>"
        },
        {
            "Key": "ManagedBy",
            "Value": "terraform"
        }
    ]
}

HCP Terraform の画面でも、ローカルの terraform コマンドでも操作していない。PR のマージだけで AWS に反映された。

PR のチェックの欄は、plan の結果のまま変わらない。HCP Terraform は apply の結果を PR に返さない。

apply が成功したかは、HCP Terraform の run のページで確かめる。

全体像

CLI-driven workflow と VCS-driven workflow を並べる。

CLI-driven workflow VCS-driven workflow
run を始めるもの ローカルの terraform plan、terraform apply PR(plan だけ)、main へのマージ(plan と apply)
run が使う .tf ローカルのディレクトリのもの リポジトリのコミットのもの
apply の前の承認 ローカルで yes、または画面の Confirm & Apply auto-apply が有効なら不要。無効なら画面の Confirm & Apply
ローカルの terraform apply 実行できる 断られる
ローカルの terraform plan 実行できる 実行できる
変数、state、AWS の認証 workspace のもの workspace のもの

PR とマージで動いたものは次のとおり。

flowchart LR
    me[自分]

    subgraph gh[GitHub のリポジトリ]
        pr["PR<br>ブランチ add-managed-by-tag"]
        main["main ブランチ"]
        check["PR のチェックの欄"]
    end

    subgraph hcp[HCP Terraform]
        subgraph ws["workspace: tfc-study-stg"]
            state[state]
        end
        specrun[["plan だけの run"]]
        run[["plan と apply の run<br>auto-apply で承認なし"]]
    end

    subgraph aws[AWS]
        bucket[("S3 バケット")]
    end

    me -- "PR を作る" --> pr
    me -- "マージする" --> main
    pr -- "通知" --> specrun
    specrun -- "plan の結果" --> check
    main -- "通知" --> run
    run -- "タグを追加する" --> bucket
    run -- "書き込む" --> state

図から読み取れることは 3 つ。

  • 変更を入れるために操作するのは GitHub だけ
  • PR から始まる run は、plan の結果を PR に返すだけで、AWS にも state にも書き込まない
  • マージから始まる run が apply まで進むのは、workspace の auto-apply が有効なため

まとめ

  • workspace を GitHub のリポジトリのブランチにつなぐと、run は GitHub の操作から始まる。run に使う .tf は、HCP Terraform がリポジトリから取得する
  • PR を作ると plan だけの run が始まり、成功か失敗かが PR に表示される。この run は apply できない
  • つないだブランチにマージすると、plan と apply の run が始まる。plan のあとで承認を待つか、そのまま apply に進むかは、workspace の auto-apply で決まる
  • つないだ workspace では、ローカルの terraform apply は断られる。terraform plan は実行できる

参考 URL

Ritolabo

100%