設定値をどこで持つか — 環境変数・設定ファイル・設定管理の使い分け

設定値の管理は「後で整理すればいい」と後回しにされやすいが、サーバー台数が10台を超えたあたりから設定ドリフトが表面化し、環境の再現が困難になる。どの値を環境変数で持ち、どの値を設定ファイルに落とし、いつ設定管理ツールやパラメータストアへ移すか——この判断軸を設計初期に定めていないと、構築担当者は「どこに何があるかわからない」状態に陥る。本記事では、値の性質と変更頻度を軸に、設定値の置き場所を体系的に整理する。

設定値が散らばって再現できなくなる構造

設定ドリフトが起きる典型パターン

新しくサーバーを追加するたびに「前のサーバーと同じ設定のはずなのに動きが違う」という状況は、現場でよく報告される。原因を追うと、環境変数をサーバーごとに手動で設定し、設定ファイルをSCPで転送し、一部の値だけSSHで直接書き換えていた、というケースが多い。台数が3〜4台のうちは問題が顕在化しないが、20台を超えたあたりで「どのサーバーが正しい状態か」を誰も把握できなくなる。設定の出所が複数に分散すると再現性の担保が難しくなり、担当者が変わったときに引き継ぎ資料に載っていない「口頭で伝えてきた設定値」が残り、新しい担当者は検証環境で再現できない不整合に直面する。

設定値の出所が3か所以上になると何が壊れるか

設定値の出所が「環境変数・設定ファイル・起動スクリプト内のハードコード」の3か所に分散した段階で、優先順位の問題が生じ始める。アプリケーションが起動時にどの順序で設定を読み込むかによって、意図しない値が使われることがある。特にコンテナ環境では、コンテナイメージに焼き込まれた設定ファイルと起動時に渡される環境変数の両方が存在し、どちらが優先されるかを把握していない担当者も少なくない。障害事例として、ステージング環境では問題なく動いていたアプリケーションが本番でエラーを出したとき、原因が「設定ファイルの値が環境変数に上書きされていると思っていたが実際は逆だった」というケースが報告されている。設定の読み込み順序はドキュメント化されていないことが多く、担当者の記憶にのみ依存する状態になりやすい。

「動いているから触るな」が招く設定の不透明化

本番環境で動き続けているサーバーの設定ファイルは、「動いているから触るな」という暗黙のルールによって変更が抑制されることが多い。その結果、設定ファイルの内容がコードリポジトリの最新版と乖離していても誰も気づかずに数ヶ月が過ぎることがある。こうした状況を放置すると、次のインフラ更新や移行プロジェクトの際に現状の設定を棚卸しするだけで数日〜1週間の工数が発生する。設定値の「正の出所(ソース・オブ・トゥルース)」をどこに置くかを決めていないと、設計どおりの状態かどうかを検証する手段がなくなる。

環境変数に置くべき値・置くべきでない値の判断

環境変数が適している値の条件

環境変数は、デプロイ環境ごとに異なる値で、かつアプリケーションの起動時に参照する設定に向いている。データベースのホスト名・ポート番号、外部APIのエンドポイントURL、ログレベルなど、「環境(dev/stg/prod)が変わるだけで値が変わる」ものが該当する。The Twelve-Factor Appの考え方では、コードと設定を分離するために環境変数を使うことを推奨しており、コンテナオーケストレーション環境やCI/CDパイプラインとの親和性が高い。同じコンテナイメージを異なる環境に展開するときに、イメージを再ビルドせずに設定だけを切り替えられる点は、設計上の大きなメリットになる。

環境変数に置いてはいけない値の特徴

一方で、環境変数には適さないケースもある。複数行にわたる値(TLS証明書の内容、JSON形式の設定ブロックなど)を環境変数で渡そうとすると、シェルのエスケープ処理や改行の扱いで問題が起きやすい。構造化されたデータ(設定の階層・配列)を環境変数で表現するためにプレフィックスで命名規則を作るアプローチは、値の数が20〜30個を超えると管理コストが増大する。「変わることが想定されない値」——たとえばアプリケーションのタイムゾーン設定や文字エンコーディング——を環境変数で持つ必要はなく、設定ファイルまたはコード内に直接書いておくほうが設定の意図が明確になる。

プロセス起動コンテキストと変数スコープの設計

環境変数はプロセスのスコープに紐づくため、サービス単位・コンテナ単位での管理が基本になる。Systemdのユニットファイルにenvironmentファイルを指定する方法や、コンテナランタイムでenvファイルを渡す方法は、手動でexportするよりも設定の出所を明示できる。手を動かす具体的な手順はリファレンスに委ねるが、設計上のポイントは「どのサービスがどの設定ファイルを読むか」の対応関係を明文化しておくことだ。複数のサービスが同じ環境変数名を使っている場合は値が競合することがあるため、サービス名をプレフィックスにした命名規則を採用し、サービスごとに環境変数ファイルを分離しておくと後の変更コストが大幅に下がる。

比較:環境変数・設定ファイル・設定管理ツール・パラメータストア

4手段の特性を整理する

設定値の置き場所を選ぶ前に、4つの手段それぞれが持つ特性の違いを把握しておく必要がある。選択を誤ると、変更のたびにデプロイが必要になったり、機密値がログに平文で残ったりする設計上の落とし穴が生じる。

手段 主な用途 機密値の適性 変更の反映タイミング 履歴管理 向いていない値
環境変数 環境依存の接続先・フラグ △(ログに出やすい) プロセス再起動時 なし(自前管理) 構造化データ・複数行値
設定ファイル アプリ・ミドルウェアの動作設定 △(暗号化が別途必要) 再起動またはリロード時 Gitで管理可能 環境ごとに頻繁に変わる値
設定管理ツール(Ansible等) 複数台への設定の一括適用 △(Vault連携で対応) ツール実行時 コードで管理 リアルタイムの頻繁な設定変更
パラメータストア(SSM/Vault等) 機密値・環境ごとの差分値 ◎(暗号化・アクセス制御) 参照タイミング(オンデマンド) バージョン管理あり 変更頻度が極端に高い値

どの組み合わせが現場に合うか

この表のポイントは「機密値の適性」と「変更の反映タイミング」の2軸だ。環境変数は手軽だが、プロセスのenviron一覧をダンプすると機密値が平文で見えることがある。設定管理ツールは複数台への一括適用に強いが、1台だけ緊急で変更したいケースでは手順が重くなる。用途に応じて手段を組み合わせることが、柔軟性と安全性を両立させる設計の鍵になる。多くの現場では「アプリの固定設定は設定ファイル・接続先は環境変数・機密値はパラメータストア」という3層構造が、管理コストとセキュリティのバランスをとりやすい。

環境ごとに変わる値をどう分離するか

ベース設定と環境差分の分離パターン

設定ファイルを「ベース」と「環境差分」に分離するパターンは、環境数が増えるほど管理コストを下げる効果がある。dev/stg/prodの3環境を持つシステムでは、共通のベースファイルに加えて各環境の差分ファイルをオーバーライドする構成が有効だ。新しい環境を追加するときに差分ファイルだけを作成すればよく、ベース設定を複製して環境ごとに全体管理するよりも変更箇所が格段に少なくなる。落とし穴は「差分だけを見ていると全体像が把握しにくくなる」点で、差分ファイルが肥大化するとベース設定の意味が薄れて結果的に全部差分になる状況に陥ることがある。差分ファイルに入れてよい値のルールを設計時に定め、ベースと差分の役割を明確にしておく必要がある。

環境変数とファイルを組み合わせるレイヤー設計

実際のシステムでは、設定ファイルだけあるいは環境変数だけで完結することは少ない。前述の3層構造(固定設定はファイル・接続先は環境変数・機密値はパラメータストア)をレイヤーとして設計段階で明示しておかないと、担当者ごとに違う層に設定値を追加してしまい設定が分散する。レイヤーを明示する方法として、設定値の種別ごとに置き場所のルールをADR(アーキテクチャ決定記録)や設計書に書き残しておくことが有効だ。判断基準があると、新しい担当者が加わったときのオンボーディングコストも下がる。

「ステージング=本番の縮小版」の前提を崩さない工夫

ステージング環境が本番の縮小版として機能するためには、設定の構造が本番と同じでなければならない。設定管理ツールや環境変数の渡し方が本番と異なると、ステージングで問題がなくても本番で設定起因の障害が発生することがある。現場で多い失敗は、ステージング環境だけ環境変数を直接exportしていて、本番はSystemdのEnvironmentFileで管理している——という構成の違いが積み重なって、本番での動作が予測できなくなるケースだ。「値」が合っていても「渡し方の機構」が違うことで挙動が変わるため、構成の差異をゼロにすることが理想だが、難しい場合は差異をリストアップして明示的に管理する。

機密と非機密の設定値の扱いを分ける境界

機密判定の基準をどこに置くか

「機密値」の定義があいまいなまま運用すると、すべての設定値をパラメータストアに入れる過剰設計になるか、逆にパスワードをplain textの設定ファイルにそのまま書く事故が起きる。機密値の判断基準は「流出したときに影響が出るか」というシンプルな軸で決める。データベースのパスワード・APIの秘密鍵・証明書の秘密鍵は機密値に該当し、ログレベル・タイムアウト秒数・機能フラグのON/OFFは非機密値として扱える。この分類を明文化しておくことが、後の管理を安定させる。

シークレットをコードベースから完全に分離する設計

機密値をGitリポジトリに含めないことは、現代のインフラ設計における最低基準といえる。しかし「.envファイルを.gitignoreに追加してローカルに保持する」運用は、開発者のローカル環境での管理が属人化し、新しいメンバーが環境を再現するたびに口頭で値を伝えるというアンチパターンを生む。より堅牢な設計は、開発環境も含めてパラメータストアやシークレット管理サービスから値を取得する構成にすることだ。ローカル開発時は開発環境用のシークレットを専用のパスから取得し、本番は本番用のパスから取得する設計にすることで、シークレットのローテーションをコード変更なしに実施できる。

ローテーションと参照方法の設計

機密値を静的に持つ設計の問題は、ローテーション(定期的な値の更新)のたびにデプロイや再起動が必要になることだ。パラメータストアやVaultのダイナミックシークレット機能を使うと、アプリケーションが参照するタイミングで最新の値を取得できるため、ローテーションをアプリケーションの稼働から切り離して実施できる。ただし、パラメータストアへのアクセスが失敗したとき(ネットワーク障害・権限設定のミスなど)にアプリケーションが起動できなくなる可能性があるため、タイムアウト設定とフォールバック戦略を設計段階で決めておく必要がある。

一元管理しすぎて硬直する境界の見極め

過剰集中が生む変更コスト

設定管理ツールをすべての設定値の唯一の出所にしようとする設計は、一見整然としているが、実際には「小さな変更にも大きな手続きが必要」という状況を作り出す。たとえば、設定管理ツールを経由しなければ設定値を1つも変更できない構成にすると、緊急の設定変更時に実行権限を持つ担当者を探すところから始める必要が生じる。変更のリードタイムが長くなると、担当者は「とりあえず直接サーバーに入って変更する」という回避行動を取り始め、ツールの管理外の設定ドリフトが再び発生する。一元管理は「どこを見れば状態がわかるか」を明確にするためのものであり、すべての変更を一つの手順に集約することが目的ではない。

チーム単位で管理できる粒度の設計

マイクロサービスやチーム分割が進んだ組織では、全サービスの設定を一つのリポジトリや一つのツールで一元管理しようとすると、担当チームの境界とツールの境界が合わなくなる問題が生じる。あるチームがサービスの設定を変更するたびに別のチームの承認が必要になる構成は、デプロイ速度とチームの自律性を損なう。共通設定(インフラ基盤・ネットワーク・セキュリティポリシー)は中央管理し、サービス固有の設定は各チームに委ねる分散設計が、実際の組織構造に合致しやすい。

設定の「変更頻度」でレイヤーを分ける

設定値の置き場所を決める軸として「変更頻度」は有効な切り口だ。変更頻度の低い設定(インフラの基本構成・サービスのデフォルト動作)は設定管理ツールで管理し、変更頻度の高い設定(機能フラグ・実験的なパラメータ)は別のレイヤー(フィーチャーフラグサービスやパラメータストア)で管理する構成が合理的だ。頻度の高い値を設定管理ツールのコードに直接書くと、フラグを切り替えるたびにコードのレビューと適用手順が必要になり変更のスピードが落ちる。「変更の速さ」と「管理の厳密さ」はトレードオフであるため、値のカテゴリごとにどちらを優先するかを設計段階で決めておく必要がある。

設定管理設計チェックリスト

初期設計で決めておく判断軸

設計の初期段階で以下の項目を確認することで、後から設定ドリフトが発生しにくい構成を組むことができる。

  1. 設定値の正の出所を定めているか
    環境変数・設定ファイル・設定管理ツール・パラメータストアのうち、どれが「正」であるかを値の種別ごとに明文化しているか。
  2. 機密値と非機密値の分類基準があるか
    「流出したときに影響が出るか」を基準に機密値の定義を明文化し、同じ場所に混在させていないか。
  3. 設定値の出所が3か所以上に分散していないか
    優先順位の衝突が起きる構造になっていないか。設定の読み込み順序をドキュメント化しているか。
  4. 環境ごとの設定の「渡し方」が統一されているか
    dev/stg/prodで設定を渡す仕組みが同じ構成になっているか。差異がある場合は明示的に管理しているか。
  5. 変更頻度の高い値と低い値を別レイヤーで管理しているか
    機能フラグや実験的なパラメータを設定管理ツールのコードに直書きしていないか。
  6. シークレットのローテーション手順を設計しているか
    機密値を更新する際にアプリケーションの再起動が必要かどうか。不要にする設計を検討しているか。

チーム運用・変更管理で確認する視点

構成が固まった後も、チーム体制の変化や運用の実態に合わせて定期的に見直す必要がある。

  1. 設定管理ツールの外で変更が発生するケースを把握しているか
    緊急時に設定管理ツールを経由せず変更した場合の後処理(コードへの反映・ドリフトの解消)のフローが決まっているか。
  2. チームの境界と設定管理の粒度が合っているか
    他チームの承認なしに自チームのサービス設定を変更できる構成になっているか。
  3. 設定の棚卸し手順があるか
    実際のサーバーの設定と設計上の設定が乖離していないかを定期的に検証する仕組みがあるか。

▶ 手を動かして本番まで到達する

脱属人化の第一歩は「読める・書けるスクリプト」から始まります

ここまでの設計判断は、読めば腹に落ちます。ですが「自分の手で本番まで通しきる自信」は、それとは別の話になります。

自動化の設計を、手を動かして身につける2日間です。手順書に閉じ込めた構築を、他人が読めて再現できる形へ変えていきます。

設定管理の設計をスクリプトで身につける2日間へ →

シェルスクリプトマスターセミナー|自動化の設計を手で身につける2日間