この記事は、弁護士ドットコム Advent Calendar 2025 の 19 日目の記事です。
はじめに
こんにちは。クラウドサイン SRE チームの岩崎です。
Liverpool FC が大好きなエンジニアです。 今シーズンの Liverpool の周囲の環境はあまり良くないことが多そうですが、Liverpool サポーター (KOP) の皆さん、引き続き応援していきましょう。
今回はそんな環境の中でも、運用環境、開発環境といった環境の話です。
長年、クラウドサインでは運用環境、開発環境といった環境の数が一定でした。 その状況で社員数も増え、使用用途別に環境が必要ということから、新環境を増やしていく試みの最中です。
本記事では、新環境構築で直面した課題をもとに、環境を増やそうとした時に障壁になりやすいポイントをまとめました。
プロダクトによって、どういった単位や方針で環境を作成しているかはそれぞれ異なると思うので、すべてが当てはまったからといって問題であるというわけではないですが、将来的に環境を増やしていくことを検討している方々のチェックシートのような役割を果たせればと思っています。
障壁になるポイント
1. 環境固有の設定値がソースコードにベタ書きされている
既存の環境固有の設定値がソースコードにベタ書きされていると、環境が追加するときも同様にアプリケーションのコードに設定値を追加していかなければなりません。
まず、第一歩として環境固有の設定値は環境名をソースコードにベタ書きはやめ、The Twelve-Factor App の第3原則「Config(設定)」にあるように、環境変数で定義しましょう。
2. 環境名とリソース名の各環境変数をアプリケーション内で組み合わせて使用している
ここで「各環境変数をアプリケーション内で組み合わせて使用している」とは、例えば、
ENV dev HOGE_QUEUE hoge-queue.fifo FUGA_DATABASE_HOST fuga-database
のような環境変数があったときに、アプリケーション内で以下のように組み合わせて利用していることが該当します。
// アプリケーション内での組み合わせ例(問題のあるパターン) env := os.Getenv("ENV") // "dev" hogeQueue := os.Getenv("HOGE_QUEUE") // "hoge-queue.fifo" fugaDBHost := os.Getenv("FUGA_DATABASE_HOST") // "fuga-database" // 環境名とリソース名を組み合わせる queueName := fmt.Sprintf("%s-%s", env, hogeQueue) // "dev-hoge-queue.fifo" dbHost := fmt.Sprintf("%s-%s", env, fugaDBHost) // "dev-fuga-database"
実際にアプリケーションが接続したいのは dev-hoge-queue.fifo や dev-fuga-database です。
一見よさそうに見えます。
そのプレフィックスで指定している環境のリソースにしか接続しないとあれば、全く問題はないでしょう。
しかし、環境がある程度増えてくると、環境ごとにすべてのリソースを用意するのではなく、ある環境は一部のリソースだけ共用環境のものに接続し、それ以外は環境固有のリソースに接続したいような場合があります。
例えば、複数環境があり、環境ごとにアプリケーション、Queue があるとし、アプリケーションは共用環境の DB に接続するような場合を考えてみましょう。
このような場合にはアプリケーションの接続先は dev-hoge-queue.fifo や shared-fuga-database となります。
上記の実装だと、やはり応用が効きづらいです。
そのため、冗長に見えますが、アプリケーション内で組み合わせるのではなく、環境変数のそのままの値だけで完結するようなことが望ましいです。
ENV dev HOGE_QUEUE dev-hoge-queue.fifo FUGA_DATABASE_HOST shared-fuga-database
// 環境変数で完結 (推奨パターン) hogeQueue := os.Getenv("HOGE_QUEUE") // "dev-hoge-queue.fifo" fugaDBHost := os.Getenv("FUGA_DATABASE_HOST") // "shared-fuga-database" // 共用環境のDB
こうすることで、「一部を共用環境に接続、それ以外は環境固有のものを利用したい」といった場合にも簡単に対応できるようになります。
3. 環境変数の値の作成手順が管理されていない
いざ環境を増やそうとして「環境変数を確認していたら、その環境変数の値を作成した方が退職していて、誰もその環境変数の値をどうやって作ったのかわからない」といった事態になることがあります。
これはプロダクトを長年運用している場合に起こる問題です。環境が増えない間は、値の作り方が分からなくても困らないため、長い期間問題が表面化しにくいです。
また別の観点として、外部サービスを利用するための認証情報などは契約形態によって、既存環境のものを新環境で使用して良いのか、そうでないのかが変わります。
大きいプロダクトになると外部連携サービスの数もやはり多くなります。 これらのことから、特に認証情報に関わる環境変数の値に関しては、
- どうやって作成したのか
- 契約形態はどのようになっているのか
- 利用するにあたって何かしらの作業が必要なのか
- 例: IP 許可設定
がわかるドキュメントを、環境変数の追加時に一緒に作成することが重要です。 クラウドサインでは、整備されているものがあれば、ないものもある状態でしたので、今まさにこの運用を整備しようとしています。
4. 特定環境で不要な機能を無効化できない
特に運用面で役立つために導入されている機能などは、特定の環境では必要ではないことがあります。 そういった機能は簡単に機能を無効化できるような仕組みが導入されていないと、新規環境では不要な機能についても用意してしまうことになります。
もしくは、環境構築時に機能を無効化できるように実装の修正をして回らなばならないことになります。
そのため、もし開発している機能が必ずしも必須ではない機能であった場合は、機能を ON/OFF にできる仕組みを導入するべきか検討するのが望ましいです。
参考までに具体的な機能を ON/OFF にする方法は以下です。
- シンプルな方法
- 環境変数の有無や、値を true or false にする
- 例:
ENABLE_HOGE=false
- 例:
- 環境変数の有無や、値を true or false にする
- より柔軟な方法
- AWS AppConfig などの設定サービスで管理
- 再デプロイなしで設定変更可能、複雑な設定も管理しやすい
- AWS AppConfig などの設定サービスで管理
5. 今は不要な環境変数や設定が残っている
使わなくなった時点で消しましょう。 残してしまうと必ず負債になります。
特に人の入れ替わりが激しくなっているこの時代ですから、タイミングを逃したら、不要になった環境変数や設定はいつまでも残り続けます。 例えば、通信経路の許可設定、使わなくなった DB ユーザー、マウントされているが参照されないファイル、などが当てはまります。 どれも本当に使われていないかを確認するには慎重に作業し、モニタリングし、判断しなければなりません。 こういったものがあると新規環境構築はスムーズには行えません。
機能を削除する場合には、関連する環境変数や設定などがないか確認し、ある場合は削除するタスクも行うことをマストにしましょう。
6. インフラがコード管理されていない
インフラがコード管理されていないと、同様のインフラを構築するときに都度設定を調査して差分が発生しないように手作業で構築しなければなりません。 この問題を解決するのに IaC (Infrastructure as Code) ツールが役立ちます。 IaC ツールを使用することで、インフラの構成がコード管理されるため、新規インフラの構築や、環境の複製をやりやすくなります。
しかし、完璧にすべてのインフラがコード管理されているわけではない場合もあります。プロダクト初期に手動で作成したインフラリソースは、コード管理されていなかったりします。
IaC ですべて管理されていると思い、既存のコードをコピーして作ってみたら、何かうまく動かない。 よーく、AWS のコンソールと眺めてみると、IaC で管理されていないリソースが新しい環境にはなかったからだったなんてことは稀によくあります。
このようなリソースは IaC の機能で import しましょう。
まとめ
知っているけど、気づいたらなっていた。
そんなポイントばかりになってしまいました。
本記事では以下の内容について触れました。
1. 環境固有の設定値がソースコードにベタ書きされている
環境変数を使うことで、コード変更なしに環境を追加できるようにする。The Twelve-Factor App の原則に沿ったアプローチです。
2. 環境名とリソース名の各環境変数をアプリケーション内で組み合わせて使用している
環境変数の値だけで完結させることで、一部リソースを共用したい場合にも柔軟に対応できるようにする。
3. 環境変数の値の作成手順が管理されていない
特に外部サービスの認証情報は、作成手順や契約形態をドキュメント化しておくことで、属人化を防ぐ。
4. 特定環境で不要な機能を無効化できない
機能を ON/OFF できる仕組みを導入することで、環境ごとに必要な機能だけを有効化できるようにする。
5. 今は不要な環境変数や設定が残っている
使わなくなった時点で削除することで、新規環境構築時の混乱を避ける。技術的負債の蓄積を防ぐ。
6. インフラがコード管理されていない
IaC で管理することで、環境の複製を容易にする。手動で作成したリソースは import して管理下に置く。
残念ながら、これらのポイントが当てはまったプロダクトは、環境が増やしにくい状態にすでになっている可能性があります。 1度にすべてを解決するのは困難ですが、1つずつ着実に改善していくことが重要です。
これらのポイントを、プロダクトの立ち上げ時点から意識して開発できていると、新規環境構築もやりやすくなるでしょう。
とはいえ、完璧に実践するのが難しい問題でもあります。
例えば、実装ガイドラインを整備しても、必ず実践できるとは限りませんし、必ず防げるわけでもありません。 やはり人力ではなく、仕組みで解決するべき課題です。 そして仕組みで解決する方法を、私たちも模索している最中です。
新環境を増やせるということは、プロダクトが成長し、組織が拡大している証でもあります。
その成長を妨げないためにも、日々の開発の中でこれらのポイントを意識していきたいものです。
この記事が、皆さんのプロダクトの現状を見直すきっかけや、新規環境構築時のチェックリストとして活用していただければ幸いです。