🔖

AtlantisとTerragruntを合わせてIaCのPipelineを構築する

2024/08/13に公開

はじめに

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 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の結果がコメントされていることが確認できます。
pr
pr

コメントにあるatlantis apply -d envs/dev/aws/vpc -w envs_dev_aws_vpcというコマンドが表示されていますが、これはTerragruntのワークスペース名を指定してapplyを実行するためのコマンドです。
早速コメントに返信してapplyを実行してみます。

comment

想定通り、applyが実行され、applyの結果がPRにコメントされていることが確認できます。
apply

まとめ

今回はAtlantisとTerragruntを合わせてIaCのPipelineを構築する方法を紹介しました。
完璧な解決策ではないですが、Atlantisを導入することで、チームメンバーがTerraformを実行するための権限を渡さなくてもよくなり、applyの実行履歴がPRに残って確認しやすくなります。
ご自身のプロジェクトに合わせて、Atlantisを導入するかどうか検討してみてください。

Discussion