Repro における AWS アカウント分離の取り組み Part4 - Terraform Module の整理

Development Division/Platform Team/Sys-Infra Unit の今(temama)です。 AWS アカウント分離シリーズの Part4 になります。今回は AWS アカウント分離に合わせて進めている Terraform module の整理と移行について紹介します。Terraform module の運用方法に悩んでいる方の参考になれば幸いです。

これまでのあらすじ

アカウント分離のタイミングに合わせて、今まで曖昧だった Terraform module の整理を進めています。Repro では現在、Terraform を管理するリポジトリで 2 つのディレクトリで定義を管理しています。

  • terraform/*: レガシーな構成
  • terraform-new/aws/*: 新しく整理した構成
[root]
 ├── terraform              # レガシー構成
 │   ├── common             # 環境を跨ぐリソース
 │   │   └── [*.tf]
 │   ├── env_dev_staging    # dev_staging
 │   │   └── [*.tf]
 │   ├── env_staging        # staging
 │   │   └── [*.tf]
 │   ├── env_production     # production
 │   │   └── [*.tf]
 │   ├── modules            # 移行前の modules
 │   │   ├── [module]
 │   │   │    └── [*.tf]
 │   │   └── ...
 │   └── [other environments...]
 └── terraform-new          # 移行先
     ├── aws
     │   ├── dev_staging    # dev_staging
     │   │   └── [*.tf]
     │   ├── staging        # staging
     │   │   └── [*.tf]
     │   ├── production     # production
     │   │   └── [*.tf]
     │   ├── internal       # internal (社内向けサービス等)
     │   │   └── [*.tf]
     │   └── modules        # 整理済み module
     │       ├── [module]
     │       │    └── [*.tf]
     │       └── ...
     └── [other providers...]

Part1 の記事でも Terraform module の整理について方針を記載しました。

  • Terraform モジュールの整理
    • ステージ(production, staging, dev_staging)で分岐しているロジックをなくし、同じ構成にする
    • IAM Role 名やリソース名にステージの情報を含めないようにする
    • アプリケーションごとにモジュールを作る
    • 複数のアプリケーションで使い回している IAM Role や IAM Policy を洗い出して、それぞれ専用のものを使うよう変更する
    • IAM Role に付与する権限を最適化する

レガシーな terraform/ の課題

レガシー構成である terraform 以下では各 stage 毎にディレクトリが分かれていますが、作成するリソースは同じ AWS アカウント上でした。そのため、IAM Role や VPC など共通のリソースを利用している箇所があり、そのようなものは common で管理し、各 stage では data source を使って参照していました。 運用してきた期間が長いこともあり、以下のような課題を抱えていました。

1 つの module に複数のコンポーネントのリソースが含まれている

Repro はマイクロサービスアーキテクチャを採用しており、大量のコンポーネントが立ち上がっています。それぞれに必要なリソースを 1 つの module に記載してしまうと、module の再利用性の低さにつながります。また、新規コンポーネントを作成する際に既存の IAM Role を利用してしまい、大量の依存を抱える汎用 IAM Role ができてしまうことがあります。 一度運用されてしまうと、既存リソースを参考に新規リソースを作成してしまうため、汎用 IAM Role はさらに多くのコンポーネントから依存されてしまいます。

セキュリティの観点から権限を削ろうと思った際に、依存しているコンポーネントを洗い出し、全てがどのような権限を必要としているかをチェックしなければならず、非常に労力がかかります。

stage 間で構成がバラバラになっている

production では ECS Cluster が分かれているが dev_staging では分かれていないなど、構成が統一されておらず開発環境で十分な検証ができていませんでした。 特定の stage からしか参照されていない module、あるいは module になっていないリソースなどが存在しているので、このようなリソースは移行に合わせて適切な大きさの module に切り分けます。

terraform-new/aws/ で意識している方針

新しい terraform-new/aws/ では、以下の方針で module を整理しています。

  • module は 1 つのコンポーネントのリソースのみを定義する。
  • 複数の環境で import しても安全なように記述する。
  • module の中で stage 判定をしない (var.stage == "production" ? 1 : 0 のようなロジック)。
    • ただしどうしても stage 別に変更したい場合は commit hash を用いたバージョン指定で部分的に反映する(後述)。
  • module の中で module を使わない。
    • 例外として、あまりにも module 内で毎度書くような内容であったり、変更された際の影響が大きくなるものに関しては小さな module を作成して利用する。
    • AWS アカウント ID 等の定数定義、コンポーネントからミドルウェア群へアクセスを許可する Security Group Ingress Rule を作る module など。

stage 別の変更を実現するための commit hash での module バージョン指定

前提として、Repro では Terraform apply に GitOps (Atlantis1) を採用しており、必然的に Terraform apply をしたコードは master branch に入ります。そのため手元で変更した内容を一時的に apply するといったことはできません。 ですが、業務では dev_staging、staging 環境で確認してから production へ反映したい場面があります。その際は、production の Terraform module source に commit hash をセットすることで、production 環境に影響を与えないまま module を変更できます。

Install a specific version of the module | Terraform

module "repro_alb" {
    # TODO: staging 環境での確認が完了したら commit hash 指定を消して本番反映する
    # source = "../terraform-new/aws/modules/repro_alb"
    source = "git::https://github.com/reproio/[repo]//terraform-new/aws/modules/repro_alb?ref=51d462976d84fdea54b47d80dcabbf680badcdb8"
    ...
}

もちろん commit hash を指定したままでは別の変更を加えられないため、利用する場合は動作確認後すぐに指定を外すようにしています。長期間 commit hash を指定するような場合は variable で機能の有効無効などを操作できるようにするのが望ましいです。

移行作業の進め方

アカウント分離はコンポーネント単位で以下のような順で進めていきました。

  1. module を作成する
  2. 移行前の module から必要なものだけ新 module へコピーしてリソースを作成する
  3. 新アカウントでコンポーネントを動かす
  4. 動かなければ必要なリソースや権限を追加する
  5. 問題なく動いたらコンポーネントを新環境に繋ぎ変え、旧リソースを削除する
  6. 旧 module で作成した既存リソースの参照を moved block を利用して新 module へ移行し、旧 module を削除する

多くのコンポーネントがありますが、基本的に module に入っているのは ECS Service 用の Task Role と Execution Role、ECR Repository、関連するミドルウェアへの接続を許可する Security Group です。ここに SNS や SQS などのコンポーネント固有のリソースを追加します。

module の整理を進めるタイミングとして、AWS アカウント分離は都合が良かったと感じています。最小限のリソースで新環境を作成して動かしてみて動かなかったら調整する、というサイクルを回せるためです。 production に比べれば気楽に触れる dev_staging 環境とはいえ壊れると開発チームに大きく影響を与えてしまうため、破壊的な検証ができる環境を用意しないと思いきった整理は難しいと感じました。

まとめ

本記事では、AWS アカウント分離に合わせて進めている Terraform module の整理と移行について紹介しました。module 整理の方針などについて参考になれば幸いです。

Terraform module の利用については賛否を含め様々な意見がありますが、現状 Repro の module 運用は上手く回っているように感じています。アカウント分離は dev_staging がおおよそ完了したところで、引き続き staging 環境の作成を進めていく予定です。

WE ARE HIRING!

Repro では開発者を募集しています。AWS アカウント分離のような大規模なインフラ移行プロジェクトや、Terraform によるインフラ管理の改善に興味がある方は、ぜひお話ししましょう!


  1. GitHub の Pull request 駆動で Terraform plan や apply を実行できる OSS。