estieでSRE, Platform Engineeringを推進している徳原です。
estieでは、組織横断でSREプラクティスやPlatform Engineeringを推進するPlatformチームが発足しました。この記事では、その取り組みの一つであるPreview環境実装について紹介させていたします。
Preview環境の導入
Preview環境とは、プルリクエストで提案された変更内容をもとに、自動的にコンテナイメージをビルドし、専用のURLを発行してその動作を確認できる環境のことです。この仕組みにより、コードレビュー時にコードだけではなく、実際の画面での動作も確認できるという大きなメリットがあります。一般的に、Preview環境の利点としては「コードだけでなく、UIや挙動も視覚的に確認できる」といった点がよく挙げられますが、estieではさらに次のような背景を考慮し、導入を決定しました。
導入背景
- プロダクトが増えてきたことによる中途入社者オンボーディングやチーム異動にかかる負荷の低減
- Git ブランチ戦略やシステム環境面(Development, Staging, Production)の統一により、運用負荷やプロダクト差異を吸収
- 品質確保をQAエンジニアに任せきりにせず、各チームで品質確保ができる状況を作り出す
- estieではチーム枠を超えてコラボレーションすることを良しとする文化がある。他チームのプロダクトにちょっとした変更を加えたい時にいちいち手元で開発環境を再現する手間をなくしたい
といった背景からです。
また、導入に当たり、プロダクトチームに定常的に活用してもらえるツールにするため、
- 基本的に1アクションでトリガーされ、数分で払い出しが完了する
- 不要になった環境削除は自動的に行われる
という点を大事にしています。
状態を持つリソースどうする問題
プロダクトには、AWS S3やAurora RDSといった、データを保存しているリソースがあります。estieでは大体どのプロダクトでもAurora RDSを使っており、そういった状態を持つリソースをどうするかが問題になります。ここではDBについて取り上げます。
結論からいうと「DBはStaging環境で利用しているものを流用する」としています。
初期案ではDBも既存環境からコピーして新規Preview環境用に構築する想定でいました。しかし問題として、
- Preview環境作成のジョブで既存DBからSnapshotを取得して新規DBインスタンスを起動する方式
- 時間がかかりすぎる
- 日時でPreview環境用のDBを作成を前もってしておくという方式
- 使われない時もコストが垂れ流しになる
- DB Dumpを取得してMysqlコンテナを起動し、Dumpを投入する方式
- DBサイズによるが、コンテナのディスクサイズの制限や、Dump投入時間で運用していると問題が出てきそう
と、どれも微妙な選択肢でした。
そこで、プロダクト開発者に相談したところ、「DBは既存のものをそのまま参照してもユースケースを十分に満たせるのではないか?」という意見をもらいました。まずはその方法で進めてみることにし、実際にStaging環境で使用しているDBを参照する形で実装を進めました。
振り返ってみると、estieのプロダクトはDaaSが多く、アプリケーションは基本的にReadが大半を占めているため、このアプローチは非常に有効でした。相談して正解だったと感じており、無駄な仕組みを作らずに済んだことは大きなメリットでした。
コンテナどう動かす問題
検討開始時点では、 ecs-mirage というOSSを使う想定でした。しかし、ecs-mirageはECS Service Connectが使えないことがわかり (estieではプロダクト間連携にECS Service Connectを利用しています) 、結局は通常のデプロイで使用している ecspresso
を使った形式でいくことにします。
ECS Serviceを作る形になるので、URLを発行しアクセスをさせるためには、LB Listener Rule, LB Target Group, Route53 Recordを作成するPreview環境ごとに作る必要があります。estieではTerraformでインフラリソースを管理していますが、今回Preview環境で必要となるリソースはTerraformの管理から外すこととしました。理由としては、Preview環境で短い期間に作っては消されるリソースを管理対象とするのは得策ではなく、またTerraform管理しているリソースとコンフリクトが起きないからです。
次にアプリケーションを動かすECSについてです。estieでは、ecspressoを使ってECS Deployなどをしています。 ecspresso
には render
というコマンドがあり、これを使うことでコピー元となるstaging環境のECS Serviceの設定ファイルをうまいこと使い回せそうです。
元々リソース名に使用する APP_NAME
、環境を表す ENV
、terraformのtfstateを参照するのでそのpathである TFSTATE
、デプロイする対象イメージを指定する IMAGE_TAG
は変数として持っていたので、以下のようなコマンドを実行することで、deployする対象であるイメージだけ書き換えたサービス定義、タスク定義ファイルが作成できます。
APP_NAME=$APP_NAME ENV=$ENV TFSTATE=$TFSTATE IMAGE_TAG=preview-1 ecspresso render servicedef --config staging_config.yml APP_NAME=$APP_NAME ENV=$ENV TFSTATE=$TFSTATE IMAGE_TAG=preview-1 ecspresso render taskdef --config staging_config.yml
jsonファイルとして出力されるので、後は jq
コマンドなりを利用して、変数や、利用するtarget groupを書き換えてやればpreview環境用の定義ファイルが完成します。あとはそれを使って ecspresso deploy
すればpreview環境の完成です。
全体展開に当たっての戦略
設計が終われば後は実装、そして全体展開です。
現在プロダクトが10前後、リポジトリ数では数十以上あります。そうなると展開は大変そうに思えるかもしれません。が、実は過去に実施したCI/CDのテンプレート化、それに伴うGitHub ActionsのPrivate Reusable Workflow管理により展開は思った以上に簡単に実現できてます。
過去施策: CI/CD テンプレート化 & Reusing Workflow 管理
2024年前半に行った対応の一つです。estieでは全てのプロダクトでコンテナ技術が使われており、そのエコシステムとして AWS ECS を利用しています。deployに関しては ecspresso, ecschedule を利用しています。私が入社した際に、この状況がすでにできていました。先人の方々本当にありがとうございます。
せっかくここまで統一されているので、それを動かすGitHub Actionsも統一しようということで、GitHub ActionsのPrivateなReusing Workflowリポジトリを作成し、そちらにContainer Build, ecspresso, ecschedule を利用したデプロイフローのテンプレートを作成し、それを全プロダクトにばらまくことで、全プロダクト統一された仕様で実施できるようにしました。またそれらを、それぞれのworkflowとして分けて作成していたため、応用が利くようになっています。
Preview環境のコンテナビルドはほぼ流用で簡潔
Reusing Workflowを使った通常のDeploy FlowとPreview環境用のDeploy Flowの関係図が上になります。 GitHub Actions自体はそれぞれのプロダクトリポジトリで動作するので、preview.ymlのファイルを各リポジトリにばらまいていくという作業は必要になりますが、その中身についてはほぼコピペ(Reusing Workflowで指定する変数の中身は異なる)で完了します。
過去に実施した施策と連動することで、Preview環境欲しいと言われて数時間後には使っていいよ〜という状態が作れてます。
Platform Engineeringの醍醐味@estie
estieは100名規模のスタートアップです。その半数がDev組織に所属しており、エンジニアとしては30~40人程度といった状況です。その人数で複数のプロダクトを持つには、「少人数で爆速で高品質なアウトプットを出しつづける」ことが大事と考えています。我々Platformチームは、どうやればプロダクト開発チームが爆速で価値を生み出せ続けることができるか、それに対して何ができるかを常に考えているチームです。
これまで作ったもの、これから作るものがそれぞれつながり、想像以上の成果につながることを個人的には「ナイス基盤」といっています。
最後に
ナイス基盤やりたい人、ナイス基盤を体験したい人は今すぐestieのカジュ面をしてみよう!!!