Terraform 84個の tfstate と 5つのリポジトリをモノレポ化した話と Terraform の運用について考える with Atlantis

技術本部 サービスリライアビリティグループ(SRG)の長谷川(@rarirureluis)です。
#SRG(Service Reliability Group)は、主に弊社メディアサービスのインフラ周りを横断的にサポートしており、既存サービスの改善や新規立ち上げ、OSS貢献などを行っているグループです。
本記事は、Terraform の運用について今一度考えてみた記事です。
 
 

モノレポ化する前の話


今回のサービスの Terraform では下記のように、環境ごと、リソースごとに完全に分離された構造となっています。
 
上記のようなディレクトリ構造を持ったリポジトリが5つ、AWS アカウントも5つあります。
このディレクトリ構造によるメリット・デメリットの話は割愛しますが、今回はこれらを全て1つのリポジトリにまとめ、CI も1つで管理することで Toil を削減することがゴールになります。
 

Terraform の運用はどうしてますか?


このサービスでは、Terraform を GitHub Actions または CodeBuild で運用していました。
この運用では PR を作成すると Plan が走り、問題がなければマージして Apply が実行されるフローになっています。

Apply が失敗するパターン

Plan は成功しても Apply が失敗する場合があります。
例えば、ECR のリポジトリの中身が空じゃなかったり、EC2, ALB などに削除保護が有効になっている場合です。
この状況になった場合、再度 Plan/Apply をするために随時 PR を作成 → Plan → Approve → Merge(Apply) を繰り返し行っていました。
これは SRE としては無視できない Toil です。
 

Atlantis はもっと早く導入すべきだった…


Atlantis は Terraform 用の CIツールです。
 

Atlantis が解決する問題

  • Apply が失敗するパターンを防げる
    • IssueOps、ブランチデプロイメントによりマージされたものは正しく Apply された状態を作れる
  • state の更新のコンフリクトを防げる
    • 現在オープンな PR から変更をしようとしている state の一覧を確認できる
と Atlantis を導入することで多くの問題を解決することができます。
 

Apply が失敗するパターンを防げる

Atlantis では全て Issue上(PR)のコメントで操作を行います。
例えば です。
つまり、マージ後に Apply が失敗して再度 Plan/Apply のために PR を作成するといった問題が発生しない状態になります。
Apply が失敗すればコードを修正し、PR 上で再度 をコメントするだけで良いわけです。
 
これはマージされたものは正しく Apply された状態になり、手法で言うと「ブランチデプロイメント」と言います。
先日、GitHub 公式がブログで紹介されていました。
 

state の更新のコンフリクトを防げる

Atlantis では PR による state の変更に対し、ロックを取ることができます。
これにより、別 PR でその state の変更を検知すると、既にロックされている旨のエラーを返してくれます。
ロックされた state は Atlantis の Web 上で確認することができ、この Web GUI では Terraform の実行ログも確認することができます。
 

Atlantis の構築方法

今回は Atlantis 公式の Terraform モジュールを利用しました。
 

Atlantis の仕組み


ここで Atlantis が動作する仕組みを解説します。
Atlantis は GitHub(それ以外のサービスにも対応しています)からの Webhook をトリガーに動作し、Atlantis から GitHub へは API を通じてコミニュケーションが行われます。
そのため、Atlantis を構築する際には GitHub App もしくは、Personal Access Token が必要になります。
 
Git フローでは、PR を作成したタイミングで Plan が走ります。
Apply するに最低でも1つの Approve を必須とし、Apply が完了すると PR は自動的にクローズされ、ブランチも自動で削除するようにしました。
ここらへんのポリシーは atlantis.yaml で詳細に決めることができます。
 

1つの Atlantis から複数の AWS 環境へ

Terraform では Assume Role に対応しているため下記のような構成にしました。
 

Tips


既に紹介した内容以外に良いところをご紹介します。

ディレクトリごとに Terraform のバージョンを指定できる

これは大変良い機能です。
モノレポ前でも完全に分離された状況だったのですが、この機能のお陰でモノレポへ移行する段階で Terraform バージョンを統一する必要がありません。

parallel_plan と parallel_apply

Atlantis では変更されたディレクトリを自動的に変更対象としてくれますが、今回のように一気に40個のディレクトリを放り込んだ場合、Plan, Apply に相当な時間がかかってしまいます。
しかし、並列実行が可能なオプションがあるため待ち時間が相当短縮されます。
💡
40個など一気にやった場合、Timeout が発生しました。 この場合は、タスクの vCPU やメモリを増やしてみてください。
 

終わりに


Atlantis は OSS であり、構築のための Terraform も柔軟性があり、かつ Atlantis 自体がシンプルな作りのため本番運用していても手軽に再作成を行うことができます。
すでに Terraform の CI 環境が整っている状態から Atlantis へ移行しましたがメリットしかなく、デメリットと言えば GitHub Actions / CodeBuild よりも若干月額コストが増えたこと、モノレポへの移行作業が地獄だったぐらいです。
インフラコストの面では Fargate 0.5vCPU / 1GB のスペックで全く問題がないので微々たるものかと思います。
今更 Atlantis の紹介をしましたが、これを機会に Atlantis への導入を考えてみてはどうでしょうか?
SRG では一緒に働く仲間を募集しています。 ご興味ありましたらぜひこちらからご連絡ください。
 
SRG では最近出たホットなIT技術や書籍などについてワイワイ雑談するポッドキャストを運営しています。ぜひ、作業のお供に聞いていただければ幸いです。
このエントリーをはてなブックマークに追加