こんにちは、サーバーサイドエンジニアの @kimihiro_n です。
今回はみんなが利用するテスト環境の渋滞を解消したはなしを。
テスト環境の渋滞
最近開発チームのメンバーが増えてきたりして、「テスト環境の渋滞」というのがよく発生するようになりました。 テスト環境というのは動作検証目的で AWS 上に作成している環境で、本番と同じようなシステム構成でデータだけダミーのものを用意してあるような環境です。
ローカルの Docker Compose で開発や動作確認が全部完結出来るというのが理想なのですが、「常時入ってくるデータを扱いたい」「本番に近いデータ量でパフォーマンスをみたい」「エミュレーションでは動くけれど実際に動くか確認したい」など、テスト環境を利用しないと分からないことが結構出てきます。 また「アプリと繋ぎこんで動作確認したい」「PO や非エンジニアに確認してもらいたい」みたいなケースでもテスト環境での確認が必要になってきます。 一方テスト環境はというと、1つの環境しか用意できておらず、使いたい人たちで譲り合って使うような形になっていました。
折角開発者が増えて機能開発速度も増えてきているのに、テスト環境の渋滞待ちがボトルネックとなってしまってはもったいないです。
API の テスト環境
そこで SRE チームに協力してもらい、テスト環境の API を簡単に複数立ち上げられるようにしてもらいました。
詳しくはスライド もしくは解説記事の方を参照していただきたいですが、 git にブランチを push するだけで個々のブランチがテスト環境として並列に動くようになりました。
これで「テスト環境の待ちがなくなる!」と期待していたのですが実際にはもう一つ課題がありました。
今のプロダクトはマイクロサービス的な指向でレポジトリを分けており、APIとそれを利用するフロントのレポジトリも分離されています。 なので、APIが複数用意されているだけでは不十分で、フロント側の接続先を変更して初めて複数のテスト環境を用意できたといえます。
フロントから API を呼び出す
フロントの方は静的なファイルを配信するだけなので、API のように Kubernetes でテスト環境を立ち上げなくても簡単にブランチごとの環境を作れるようになっていました。 ただ CIOps を採用してデプロイしているため、API の向き先を変えたい場合でも、都度コミットする必要がありました。
- export API_ENDPOINT=branch1.api.example.com + export API_ENDPOINT=branch2.api.example.com
コミットで接続先を管理してしまうと「プロダクトに関係ないコミットで汚れてしまう」「操作ミスで本番を壊しかねない」「非エンジニアが触りにくい」といった問題が出てきたため別のアプローチが必要となりました。
URLパラメータ & Cookie による動的つなぎ替え
紆余曲折あったのですが、最終的に以下の要件が満たせればよさそうということになりました。
- コミットやデプロイに紐付かず設定出来る
- 非エンジニアでも簡単に接続先が変更出来る
- AWS 上の設定を変えるやブラウザの開発コンソールから操作も NG
- ブラウザに古い API 接続先情報が残らない
- 間違ったAPIを参照することによるトラブルを減らしたい
- 同じフロントのテスト環境から API 1、API 2 へつなぎ替えられるようにしたい
- API だけの開発を進める場合、同じフロントのコードから別の API をみたいというパターンも
これらを実現するために URLパラメータとセッション Cookie を利用することにしました。
URLパラメータというのはおなじみの ?param=hogefuga
みたいなURLの末尾に付与出来るパラメータです。
セッション Cookie は Cookie の一種で、有効期限を設定しない Cookie を指します。有効期限を指定しない場合、ブラウザを終了する度 Cookie がリセットされるようになります。1
組み合わせることで、URL として簡単に設定でき、かつブラウザ終了などで簡単にリセットも出来るような設定変更が実現出来ます。
const TEST_API_NAME = 'custom_env' const TEST_API_NAME_COOKIE = 'api_name' // URL パラメータから取り出して Cookie にセット if (IS_TEST_ENV) { const urlParams = new URLSearchParams(window.location.search) if (urlParams.has(TEST_API_NAME)) { const envName = urlParams.get(TEST_API_NAME) if (envName === '') { // 空文字がセットされていたら Cookie をリセット Cookie.remove(TEST_API_NAME_COOKIE) } else { Cookie.set(TEST_API_NAME_COOKIE, envName) } } } // API の向き先を変更 const API_ENDPOINT = (() => { if (!IS_TEST_ENV) return 'https://api.example.com' const envName = Cookie.get(TEST_API_NAME_COOKIE) if (envName === undefined) return 'https://api.example.com' return `https://${envName}.api.example.com/` })()
コードとしてはこのような感じです。 本番環境で向き先が変わってしまうと困るので、テスト環境かどうかをチェックするコードも入れてあります。
https://front.example.com?custom_env=hoge
のようにアクセスすると、api_name=hoge
という Cookie がセットされ、https://hoge.api.example.com
へ接続されるようになります。
どのように組み合わせてほしいかという情報も URL 1つで共有できるので、 エンジニア以外に確認してもらうときも簡単です。
また利便性向上のため、APIの向き先がデフォルトでない場合は「画面上にどのAPIを向いているかのラベル」と「デフォルトに戻すボタン」を表示するようにしています。 画面上に出すことでちゃんと向き先変更出来ているかが分かりますし、画面のスクショからでも問題の切り分けがしやすいです。
おわりに
上記の仕組みにより、API とフロントのテスト環境を気軽に作って使い分けが実現出来ました。 環境の順番待ちを強いられていた部分が解消したので、開発者の作業効率もグッと良くなりました。
API のテスト環境を複数作れるようにしてくれた SRE チームに感謝しながら終わりたいと思います。
-
ブラウザのセッション復元機能によりブラウザを閉じても保持される場合もあります。https://developer.mozilla.org/ja/docs/Web/HTTP/Cookies#define_the_lifetime_of_a_cookie↩