概要
機能開発時の動作検証を迅速におこなうため、特定のバージョンのサービスを必要に応じて動的に起動し、使い終わったら破棄する仕組みを構築しました。
背景
開発中の機能をローカルだけではなく実際の AWS 環境にデプロイし、プロダクト観点も含めて検証をおこなうことがあります。そのための検証環境を 3 つ用意しておき、デプロイ先を切り替える仕組みを利用していました。各環境は 5 つのサービス (Pod) から構成され、合計で 15 個が常に動作しています。データベースなどその他のリソースは共有します。

この環境での運用には、いくつかの課題が存在しました。
- 常に複数の環境が動作しているためコストがかかる
- 各環境の使用状況を管理するため、Slack で呼びかけたりカレンダーで管理しており、手間がかかる
- 連絡漏れやミスによりバッティングしてしまう可能性がある
- 各環境に古いサーバーが残り続けないよう、定期的に更新する必要がある
- 状況によっては 3 環境では足りない
これらを解消するため、特定のブランチから一時的に環境を立ち上げることができる仕組みを構築しました。
仕組み
外資就活ドットコムは現在 EKS (Kubernetes) を使用しており、ArgoCD による GitOps でデプロイされています。そのため Git リポジトリのマニフェストに定義を追加することで追加のサービスを起動することができるはずです。しかし現在、運用負荷の低減を目的に Amazon ECS へのリプレイスが予定されているため、ECS を使った仕組みで進めることにしました。
指定したブランチからコンテナイメージをビルドしてサービスをデプロイ、固有の URL でアクセスできるようにします。具体的には以下のような処理をおこないます。
- ECS Task Definition の作成
- 各サービスごとにテンプレートを用意しておく
- ビルドしたコンテナイメージを指定
- 環境変数は Secrets Manager から展開する
- API エンドポイントなどの環境変数は環境ごとに変更する
- ECS Service の起動
- 作成した Task Definition を使用してサービスを起動する
- ALB: Target Group, Listener Rule の作成
- ロードバランサーから、ホスト名に応じて起動したコンテナへルーティングするための Target Group を作成し、Listener Rule に追加する
- Route53: Hosted Zone にエントリーを追加
- 一時的なホスト名で ALB にアクセスするための DNS エントリーを追加する
- ホスト名はブランチ名やコミットハッシュを元に動的に生成する
リクエストのインタフェースとしては Slack を使用し、全体の流れとしては以下のようになりました。
- Slack から一時検証環境作成のリクエストをおこなう
- Slack App から各リポジトリの GitHub Actions ワークフローを起動する
- ワークフローでイメージをビルド後、一時検証環境デプロイ Lambda 関数を呼び出す
- Lambda 関数から必要なリソースを作成する
削除の場合は GitHub Actions を経由せず直接デプロイ Lambda 関数を呼び出します。

補足
- CI/CD によるイメージビルドは元々 GitHub Actions を使用しており、既存の仕組みを使うため、リクエストからデプロイまでの流れがやや入り組んでしまいました。CodeBuild など AWS 内で完結できるとシンプルになると思います。
- 各環境にある 5 つのサービスは互いに依存関係があるため(例えばフロントエンド+API サーバーなど)、複数のサービスの組み合わせをセットでデプロイする必要があります。サービスごとにリポジトリが分かれているため GitHub Actions の呼び出しはそれぞれリポジトリへおこない、完了後にそれぞれのワークフローからデプロイ Lambda 関数を呼びサービスを起動します。すべてのサービスの起動に完了したら、通知をおこなうようにしました。
- GitHub Actions ワークフローの失敗が取得できません。とりあえず時間が経っても完了しなかったらワークフローの実行結果をチェックする、という運用をしています。
- 作成した環境を削除する際、ECS サービスだけでなく ALB, Route53 の設定も適切に削除する必要があります。DynamoDB に必要なリソースの ID を保持して削除しています。一連の処理の途中で失敗した場合にも中途半端に残ることがないよう考慮しました。
- Kubernetes では Secrets Manager に保存した JSON からまるごと環境変数として起動する機能がありそれを使用していますが、ECS ではそれができません。既存の Secret から JSON を読み込み、すべての要素を Task Definition の secret に設定するようにしました。
ランニングコスト
追加の固定費としては Route53 と ALB で、約 20 USD/月。
作成する環境に対しては、基本は Fargate の最小スペックで動作できているため、8 時間起動しても 0.1~0.4 USD くらい。実測で 20~30 USD/月くらい利用されています。
まとめ
この仕組みにより、開発者はいつでも気軽に検証できるようになりましたし、開発者に限らず環境を共有することで、開発中に実際にさわってもらいながら、より良いプロダクト作りに役立てることができようになったと思います。
弊社では、一緒に技術的な課題に取り組んでくれるエンジニアを募集中です!
現在募集中の採用情報の詳細は下記をご覧ください。