この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは。かたいなかです。
現在関わっているプロジェクトで、Terraformの適用をイイ感じに行う方法を検討しています。
そのなかで、GitHubのPRコメントのコマンドでTerraformのplan
やapply
を行う、Atlantisというツールが良さそうだったのでご紹介します。
Atlantisとは
Cloud Posseにより開発されている、GitHub/GitLab/BitBucketのPull Request上のコマンドでTerraformのワークフローを実行するツールです。
Atlantisを使用すると、例えば以下のような開発フローが実現できます
- Terraformのコードを変更し、GitHub上でPull Requestをオープン
- 開発環境と本番環境それぞれのディレクトリで
plan
が自動で実行され、結果がPR上にコメントとして追加 - PR上からコマンドで変更を開発環境に適用する
- 開発環境への適用が問題ないことを確認する
- PR上からコマンドで本番環境にも適用する
- 開発・本番の両方の環境への適用が成功したら自動でPRをマージ
個人のローカルマシンに依存せず、かつPR上で記録が残る方法で実行でき、複数stateにも対応できるのが魅力です。
実際にやってみる
環境
- Terraform v0.12.1
事前準備
- Route53でpublic hosted zoneが使用できるドメインが必要です。Webhookの送信先として指定する必要があるためです。
Atlantisで適用するTerraformのコード
今回は以下のようなディレクトリ構造のTerraformのリポジトリの内容をGitHubのPRから適用できるようにしていきます。
.
├── README.md
└── example-project
├── environments
│ ├── development
│ │ └── main.tf
│ └── production
│ └── main.tf
└── modules
└── example
└── main.tf
example-project/envoronments
以下の development
と production
がそれぞれ、開発環境と本番環境に対応しているディレクトリ構成です。
TerraformでAtlantisをデプロイ
FargateにデプロイするためのTerraformのモジュールが提供されています。今回はそれを利用してデプロイします。
まず、以下のようなファイルを作成します。
atlantis/main.tf
provider "aws" {
version = "~> 2.0"
region = "ap-northeast-1"
}
module "atlantis" {
source = "terraform-aws-modules/atlantis/aws"
version = "~> 2.0"
name = "atlantis"
cidr = "10.20.0.0/16"
azs = ["ap-northeast-1a", "ap-northeast-1c"]
private_subnets = ["10.20.1.0/24", "10.20.2.0/24"]
public_subnets = ["10.20.101.0/24", "10.20.102.0/24"]
route53_zone_name = "<atlantisの名前を登録するRoute53のPublic HZのドメイン名>"
policies_arn = [
# Terraformを実行するため、
# AdministratorAccessをAtlantisのECSのタスク実行ロールにアタッチしています。
# 必要に応じてロールの指定を置き換えてください。
"arn:aws:iam::aws:policy/AdministratorAccess"
]
atlantis_github_user = "<Botに使用するGitHubユーザ>"
atlantis_github_user_token = "<ボットユーザのGitHubトークン(repo権限を付けてください)>"
atlantis_repo_whitelist = ["github.com/<リポジトリのGitHubユーザ名>/*"]
}
output "webhook_url" {
description = "Github webhook URL"
value = module.atlantis.atlantis_url_events
}
output "webhook_secret" {
description = "Github webhook secret"
value = module.atlantis.webhook_secret
}
次に以下のコマンドで準備したTerraformのファイルをapply
します。
$ cd <atlantis用のmain.tfを作成したディレクトリ>
$ terraform init
$ terraform apply
terraform apply
が完了すると以下のような結果が出力されます。
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
webhook_secret = "XXXXXXXXXXXXXXXXXX"
webhook_url = https://<ドメイン名>/events
出力されたwebhook_secret
とwebhook_url
の2つの値は後ほどGitHubのリポジトリでWebhookを登録する際に使用するのでメモっておきます。
Webhookを適用
次にWebhookを登録します。Atlantisのドキュメントを参考に設定していきます。
GitHubのリポジトリのトップ画面から Settings
-> Webhook
-> Add Webhook
と順番に選択し、Webhookの追加画面に移動します。
その画面で以下のような設定を行い、Webhookを作成します。
項目 | 設定値 |
---|---|
Payload URL | <webhook_url として出力されたURL> |
Content type | application/json |
Secret | <webhook_secret として出力された文字列> |
Which events would you like to trigger this webhook? | Let me select individual events |
イベントの種類 | 設定値 |
---|---|
Pull request reviews | ✔ |
Pushes | ✔ |
Issue comments | ✔ |
Pull requests | ✔ |
その他のイベント | チェックしない |
リポジトリに設定ファイルを設置
リポジトリのルートに atlantis.yaml
という名前で以下のような内容のファイルを作成し、GitHubにプッシュしておきます。
version: 3
# applyに成功したら自動でPRをマージ
automerge: true
projects:
# 開発環境の設定
- name: development
dir: example-project/environments/develepment
workspace: default
terraform_version: v0.12.1
autoplan:
# 指定したファイルが変更されたら
# 自動でplanを実行して結果をGitHubのコメントで追加
when_modified: ["*.tf", "../../modules/**/*.tf"]
enabled: true
# 本番環境の設定
- name: production
dir: example-project/environments/production
workspace: default
terraform_version: v0.12.1
autoplan:
when_modified: ["*.tf", "../../modules/**/*.tf"]
enabled: true
動作確認
ここまでできたら正しく動くようになっているはずです。
実際にPRを作って動作を確認してみましょう。今回は開発環境と本番環境の両方に影響するモジュールを修正してPRを作成しました。
すると、environments/development
と environments/production
のそれぞれのディレクトリでplanを行った結果がGitHubのコメントとして追加されます。
まず、開発環境に適用したいので、devの結果を確認し、
問題ないのでbotが付けたコメントの指示にに従って以下のようなコメントをつけます。
すると、開発環境へのapply
が実行されます!実行が終わると結果のコメントが追加されます。
開発環境への適用で問題なかったので次は本番にも適用してみます
すると、本番環境へのapply
が実行されます!今回は他にapply
する対象がないのでPRのマージまで自動で行われました。
GitHubのPR上からコメントを打つだけで、開発環境、本番環境と順番にTerraformを適用していくことができました!!!
まとめ
ご覧いただいたようにAtlantisを使用することで、GitHub上でコマンドを使用してTerraformのplan
,apply
が行なえます。CIツールでの適用では複雑になってしまう複数のstateがあるリポジトリの管理も、このフローであれば問題なく対応できそうです。
個人的にマージする前に apply
するというフローが癖があるのかなと思ったのですが、これはこれで実際に正しくapply
できるもののみ マージされるということで良いのではないかと思います。
Atlantisは設定項目が充実しており、設定によってはapply
前にレビューを必須にする、といったことも行えるようです。また、複数のPRがあるときに競合して不具合が発生しないようにするロック機能もあるようで、複数人での開発にももちろん対応できるようになっています。
参考リンク
- Atlantis
- terraform-aws-atlantis(atlantisをFargateにデプロイするためのTerraformモジュール)
- Atlantis で Terraform プルリクエストの自動化(Qiita上の記事)