AtlantisとTerragruntを合わせてIaCのPipelineを構築する
はじめに
IaC(Infrastructure as Code)のツールとしてTerraformを使っている方は多いと思います。
Terraformは良いツールですが、プロジェクトが大きくなると、コードの管理や実行の自動化を取り込まないと運用が難しくなります。
コードの管理についてはTerragruntというラッパーツールである程度解決できます:
- Terraformコードの重複を減らす
- モジュールとモジュール間の依存関係を明確にする
- モジュールをまたいて一括で変更を適用する
- 実機の設定を見ながら差分を確認する
- before/afterの hookでtflintやTrivyなどカスタムコードを実行する
しかし、Terragruntによる実行の自動化についてはなかなかやりづらい状況でした。
一番望ましいのは、PRをマージしたら自動でplanして差分を表示して、PRにコメントすることでapplyまで完結させることです。
tfcmtというツールを使ってみましたが、Terragruntに完全対応していなく、ある程度のカスタマイズが必要となり、メンテナンスが大変でした。
そこで、Atlantisというツールを使ってみました。
Atlantisの仕組みとしてはは自分でAtlantisサーバを立てて、GitHubのWebhookを受け取り、Terraformのplan/applyを実行することができます。
この記事では、AtlantisとTerragruntを合わせてIaCのPipelineを構築する方法を紹介します。
なぜAtlantisを使うのか
普段インフラチームは複数人で開発を行うことがほとんどです。
そのため、開発現場では下記のような課題が発生するケースが多いです:
- Terraformをチームメンバーが実行できるために全員強めな権限を渡さないといけない
- applyをいつ、誰が実行したかが把握しづらい、「あれ、stateが変わってる?」と思った際に都度都度会話して確認しないといけない
- plan/applyの結果の共有が面倒、SlackやPRに都度都度貼り付けないといけない
- プロジェクトが大きくなると、applyを実行する人の負担が大きくなる、applyの実行履歴がPRに残っていないため、差分を確認するのが面倒になる
...
これらの課題を解決するために、Atlantisを導入することで、下記のようなメリットがあります:
- チームメンバーがTerraformを実行するための権限を渡さなくてもよい (これがいいかどうかは状況・プロジェクトによる)
- 全員が開発端末にTerraform環境を構築する必要がない
- applyは基本的にAtlantisが実行するため、applyの実行履歴がPRに残って確認しやすい
- plan/applyの結果がPRにコメントされるため、共有・レビューが楽になる
- applyを実行する人の負担が減る
しかしAtlantisも完全な解決策ではなく、下記のような課題もあります:
- 複雑性:Atlantisは基本PRに依存するため、ワークフォローが複雑になる
- Gitの権限管理が面倒:PRにコメント権限さえあれば、誰でもapplyができてしまうため、しっかりと権限管理を行う必要がある
- Atlantisサーバのコスト:Atlantisサーバ自体のコスト、導入のコスト、今後のメンテナンスコストがかかる
- Atlantisはロールバック機能がないため、問題発生時に素早くロールバックする仕組みが必要
Atlantisを導入するかどうかは、これらのメリット・デメリットを踏まえて判断する必要があります。
Atlantisの導入
前準備
GitHub appの作成
まずGitHub Apps から新しいアプリを作成します。
- GitHub App name: 任意の名前
- 説明: 任意
- Homepage URL: 今回はTerragruntと合わせて使うため、Terragruntのリポジトリを指定する
- Permissions:Repository permissionsにて下記権限を付与
- Administration: Read-only
- Checks: Read & write
- Commit statuses: Read & write
- Contents: Read & write
- Issues: Read & write
- Metadata: Read-only
- Pull requests: Read & write
- Webhooks: Read & write
- Members: Read-only
- Subscribe to events: 下記イベントを選択する
- Create
- Pull request
- Push
- Check run
- Delete
- Pull request review
- Pull request review comment
- Pull request review thread
- Webhook URL: AtlantisサーバのURLを指定する、フォーマットは
https://<atlantis-server>/events
となる - Secret: 任意の文字列
作成完了したら、「Generate a private key」ボタンをクリックして秘密鍵をダウンロードします。
GitHub Appのインストール
次に、GitHub Appをインストールします。
GitHub Appsのページから作成したアプリを選択し、Install App
ボタンをクリックします。
「Only select repositories」を選択し、対象のリポジトリを選択します。
Atlantisサーバの構築
今回はEC2上にAtlantisサーバを構築します。
プロジェクトによって機密情報の扱いや環境構築の方法が異なるため、細かいインフラ構成は割愛し、 Terragrunt・Terraformがある前提で、下記のような構成で構築します:
Atlantisのインストール
AtlantisはGitHubのリリースページからダウンロードできます。
wget https://github.com/runatlantis/atlantis/releases/download/v0.28.5/atlantis_linux_amd64.zip
unzip atlantis_linux_amd64.zip
chmod +x atlantis
sudo mv atlantis /usr/local/bin/
atlantis version
repos.yamlの作成
Atlantisはリポジトリに配置するatlantis.yaml
ファイルとサーバに配置するrepos.yaml
ファイルがあります。
Atlantisを動かせるにはどちらでも良いですが、Terragruntの場合全てのパスを書かないといけなく、かなり面倒なので、
今回はterragrunt-atlantis-configを使って、repos.yaml
と合わせて利用します。
まずはterragrunt-atlantis-configをクローンします。
wget https://github.com/transcend-io/terragrunt-atlantis-config/releases/download/v1.18.0/terragrunt-atlantis-config_1.18.0_linux_amd64
chmod +x terragrunt-atlantis-config_1.18.0_linux_amd64
sudo mv terragrunt-atlantis-config_1.18.0_linux_amd64 /usr/local/bin/terragrunt-atlantis-config
terragrunt-atlantis-config version
次に、atlantisサーバに下記のようなrepos.yaml
を作成します。
repos:
- id: "/.*/"
allowed_overrides: [ workflow, apply_requirements ]
allow_custom_workflows: true
workflow: terragrunt
apply_requirements: [ mergeable ]
pre_workflow_hooks:
- run: terragrunt-atlantis-config generate --output atlantis.yaml --autoplan --parallel --create-workspace
workflows:
terragrunt:
plan:
steps:
- run: terragrunt plan -no-color -out=$PLANFILE
- run: terragrunt show -no-color -json $PLANFILE > $SHOWFILE
apply:
steps:
- run: terragrunt apply -no-color $PLANFILE
Atlantisの起動
最後に、Atlantisを起動します。
export URL=https://<atlantis-server> # AtlantisサーバのURL
export SECRET="your-secret" # GitHub App作成の際に設定したSecret
export GITHUB_APP_ID="your-app-id" # GitHub App作成の際に表示されるApp ID
export GITHUB_INSTALLATION_ID="your-installation-id" # GitHub Appをインストールした際に表示されるInstallation ID 例:https://github.com/settings/installations/<installation-id>
export GITHUB_PRIVATE_KEY_FILE="path/to/private-key.pem" # GitHub App作成の際にダウンロードした秘密鍵のパス
export REPO_ALLOWLIST="your-repo" # 対象のリポジトリ 例:github.com/the-exile-110/terragrunt-templates
atlantis server \
--atlantis-url $URL \
--gh-app-id $GITHUB_APP_ID \
--gh-installation-id $GITHUB_INSTALLATION_ID \
--gh-private-key-file $GITHUB_PRIVATE_KEY_FILE \
--gh-webhook-secret $SECRET \
--repo-allowlist $REPO_ALLOWLIST \
--repo-config repos.yaml \
--write-git-creds
動作確認
Atlantisサーバが対象リポジトリのWebhookを受け取り、plan/applyを実行することができるか確認します。
まずサンプルのTerraformコードを作成します。
下記VPCのタグを追記して、PRを作成します。
resource "aws_vpc" "main" {
cidr_block = local.cidr_block
enable_dns_support = true
enable_dns_hostnames = true
assign_generated_ipv6_cidr_block = true
tags = {
Name = "${var.prefix_env}-vpc"
Version = "1.0" # <- ここを追加してみる
}
}
しばらくすると、PRにplanの結果がコメントされていることが確認できます。
コメントにあるatlantis apply -d envs/dev/aws/vpc -w envs_dev_aws_vpc
というコマンドが表示されていますが、これはTerragruntのワークスペース名を指定してapplyを実行するためのコマンドです。
早速コメントに返信してapplyを実行してみます。
想定通り、applyが実行され、applyの結果がPRにコメントされていることが確認できます。
まとめ
今回はAtlantisとTerragruntを合わせてIaCのPipelineを構築する方法を紹介しました。
完璧な解決策ではないですが、Atlantisを導入することで、チームメンバーがTerraformを実行するための権限を渡さなくてもよくなり、applyの実行履歴がPRに残って確認しやすくなります。
ご自身のプロジェクトに合わせて、Atlantisを導入するかどうか検討してみてください。
Discussion