LASSIC Media らしくメディア
環境変数の基礎|アプリ設定を外部化する仕組み
環境変数とは
環境変数とは、OSやコンテナなどの実行環境があらかじめ保持している「名前=値」の組み合わせのことです。アプリケーションはプログラムを起動した実行環境からこの値を読み取り、接続先やAPIキーといった設定として利用します。
多くのアプリケーションには、データベースの接続先、外部サービスのAPIキー、動作モードの切り替えフラグなど、環境によって値が変わる設定項目があるものです。こうした値をソースコードに直接書き込んでしまうと、環境が変わるたびにコードを書き換える必要が生じ、修正のたびにビルドやデプロイをやり直す手間もかかりやすくなります。
環境変数は、こうした設定値をコードの外、つまり実行環境側に持たせておく仕組みだといえるでしょう。アプリケーションのコード自体は変えずに、実行環境が渡す値だけを差し替えることで、同じプログラムを異なる状況で動かせるようになります。
なお、環境変数と混同されやすいものに、特定の秘密情報管理サービス(シークレットマネージャ)の導入がありますが、両者は役割が異なります。本記事で扱うのは、言語やOSを問わず広く使われている環境変数という一般的な仕組みそのものであり、特定製品の選定や導入手順ではなく、設定を外部化するという考え方の基礎を整理するのが狙いです。
環境変数という考え方自体は古くから存在しており、OSがプロセスに情報を渡す標準的な手段として、多くのプログラミング言語やフレームワークが共通して対応しています。特定の言語やクラウドサービスに依存しない汎用性の高さも、環境変数が広く使われ続けている理由の一つといえるでしょう。
なぜ環境変数を使うのか
環境変数を使う理由は、大きく分けて三つあります。
- 環境ごとの使い回しがしやすくなる:開発・検証・本番という複数の環境で、同じコードをそのまま動かせます。接続先のデータベースやAPIキーだけを環境変数として差し替えれば、コード自体に手を入れずに済みます。
- 設定変更のたびにコードを直さずに済む:外部サービスのエンドポイントや動作フラグといった値を環境変数にしておくと、値の変更だけで対応でき、コードの修正・再ビルドという工程を省きやすくなります。
- 機密情報をソースコードやGitの履歴に残しにくくなる:APIキーやパスワードをコードに書き込んでしまうと、バージョン管理システムの履歴に残り続けます。環境変数として外部に持たせておけば、少なくともソースコードそのものには値が記載されない形にできます。
この考え方は、一般に「設定とコードの分離」と呼ばれています。アプリケーションのふるまいを決めるロジックと、環境ごとに変わる設定値を切り離しておくことで、コードの再利用性や保守性が高まりやすくなるという発想です。クラウド向けアプリケーションの設計指針として知られる「The Twelve-Factor App」でも、設定は環境変数に格納するという方針が示されています。
反対に、設定値をコードに埋め込んだままにしておくと、環境ごとに異なるコードを保守する形になったり、設定変更のたびにデプロイ作業が発生したりと、運用の負担が増えていきやすい傾向があるでしょう。
例えば、検証環境向けのAPIキーを本番環境向けのコードに書き込んでしまうと、環境を切り替えるたびにコードの該当箇所を探して書き換える作業が発生します。担当者が変わった際に修正箇所を見落とすと、誤った接続先のまま動かしてしまう恐れも出てくるでしょう。環境変数として外部化しておけば、コードは共通のまま、実行環境側の値を切り替えるだけで対応できます。
コードに直接書き込む方法(ハードコーディング)と環境変数を使う方法を比べると、次のような違いがあります。
| 観点 | コードに直接書き込む場合 | 環境変数を使う場合 |
|---|---|---|
| 環境を追加・変更したとき | 該当箇所を探してコードを修正し、再ビルドが必要になりやすい | 実行環境側の値を差し替えるだけで対応できる |
| 機密情報の履歴 | バージョン管理システムの履歴に残り続ける | コードには記載されず、外部に持たせられる |
| 他の開発者への影響 | 環境ごとにコードの差分ができ、レビューの対象が増える | コードは共通のままで、設定値だけが変わる |
使い方の基本
環境変数は、OS側で設定する方法と、アプリケーション側で読み取る方法の両方を押さえておくとイメージがつかみやすくなります。
OS側での設定には、一時的な設定と永続的な設定の二通りがあります。
| 設定方法 | 特徴 | 主な用途 |
|---|---|---|
| 一時的な設定(シェル上でexport等) | そのシェルセッションを終了すると値は消える | 動作確認や一時的な切り替え |
| 永続的な設定(設定ファイル・OS機能・サービス定義) | 再起動後も値が保持される | 本番環境やサーバの常設設定 |
一時的にターミナル上で設定する例は、次のようになります。
# Linux/macOSのシェルでの一時的な設定例
export DATABASE_URL="postgres://localhost:5432/dev_db"
アプリケーション側では、プログラミング言語ごとに用意された機能を通じて環境変数を読み取ります。Node.jsであればprocess.env、Pythonであればosモジュールのenvironを経由して値を取得するのが一般的です。
// Node.jsでの読み取り例
const dbUrl = process.env.DATABASE_URL;
# Pythonでの読み取り例
db_url = os.environ.get("DATABASE_URL")
開発環境では、環境変数を一つずつコマンドで設定するのではなく、.envという名前のファイルにまとめて記述し、起動時に読み込むことが多いのが実情です。設定項目が増えてくると、この形にしておいたほうがチーム内での共有や管理がしやすくなります。
# .envファイルの例
DATABASE_URL=postgres://localhost:5432/dev_db
API_KEY=xxxxxxxxxxxx
ここで注意したいのが、.envファイルの取り扱いです。.envには接続先やAPIキーといった値がそのまま書かれているため、バージョン管理システムにコミットしてしまうと、機密情報がリポジトリの履歴に残ってしまいます。.gitignoreに.envを追加し、コミット対象から外しておくことが基本の対応になるでしょう。
# .gitignoreへの記載例
.env
チームで開発する場合は、.envそのものではなく、キー名だけを記載したサンプルファイル(.env.exampleなど)を共有しておく方法もよく使われます。値を空欄にしたひな形を用意しておけば、新しく参加したメンバーも、どの項目を設定すればよいかを把握しやすくなるでしょう。
機密情報の扱いと注意点
環境変数は設定を外部化するうえで広く使われている仕組みですが、機密情報の保護という観点では万能ではありません。環境変数の値は、サーバやコンテナにアクセスできる利用者・プロセスであれば平文のまま参照できてしまうため、環境変数に入れておけば機密情報が守られるとは言い切れない点に注意が必要です。
例えば、次のような場面で意図せず値が漏れてしまう可能性があります。
- デバッグ目的で環境変数の一覧をログに出力し、そのログが広く閲覧できる状態になっている
- エラー画面やスタックトレースに環境変数の値がそのまま含まれてしまう
- コンテナの設定情報やプロセスの情報を、権限を持つ第三者が閲覧できる状態になっている
より厳格な管理が求められる場面では、環境変数だけに頼らず、秘密情報を専用に管理するサービス(シークレットマネージャ)を併用するという選択肢もあります。こうしたサービスは、アクセス権限の細かい制御や値の暗号化、利用履歴の記録といった機能を備えているものが多く、環境変数だけでは対応しにくい要件を補う役割を持ちます。ただし、どの仕組みを選ぶかは扱う情報の重要度や運用体制によって変わるため、一律の正解があるわけではないでしょう。
個人情報や決済情報を扱うシステムであれば、環境変数に加えてこうした専用サービスの導入を検討する価値があるでしょう。反対に、社内向けの小規模なツールであれば、環境変数と適切なアクセス権限の管理だけで足りる場面も少なくありません。扱う情報の性質と運用体制を踏まえて、どこまでの対策が見合うかを判断する視点が求められます。
図にすると、コードと実行環境、環境変数の関係は次のようになります。
開発環境で使う.envファイルについても、共有ドライブやチャットツールへの安易な貼り付けは避け、必要な担当者だけがアクセスできる形で管理しておくことが望まれます。加えて、担当者の異動や退職に伴ってAPIキーなどを更新する運用ルールも、あわせて決めておくとよいでしょう。
また、環境変数はプロセスが動いている間だけメモリ上に保持される情報である一方、稼働中のコンテナやサーバに管理者権限で入れる立場の人であれば、その値を確認できてしまう場合があります。開発者本人だけでなく、運用や監視を担当するメンバーがどこまでアクセスできるかも、あわせて整理しておく観点の一つでしょう。
実務での関わり
設定を環境変数として外部化する考え方は、クラウドサービスやコンテナを使ったシステム運用の前提になっています。多くのクラウドサービスやコンテナ基盤では、環境変数の注入やファイルのマウントを通じて設定値をアプリケーションに渡す仕組みが標準的に用意されており、デプロイ先の環境に応じて値を切り替えられるようになっているものです。
発注やレビューの場面では、次のような観点を確認しておくと、後々の手戻りを減らしやすくなります。
- APIキーやパスワードなどの機密情報が、ソースコードに直接書き込まれていないか
- 開発・検証・本番といった環境ごとの設定値が整理され、切り替えの手順が明確になっているか
- .envファイルなど機密情報を含むファイルが、バージョン管理の対象から除外されているか
- 環境変数の一覧やログに、機密情報がそのまま出力されていないか
設定とコードが分離されていないシステムでは、環境を追加するたびにコードの改修が発生し、開発の負担が積み上がっていく傾向があります。設計の初期段階から設定の外部化を意識しておくと、後から環境を増やす場面でも対応しやすくなるでしょう。
特に、複数のベンダーやチームが関わる開発では、誰がどの環境変数を管理しているかが曖昧になりやすいものです。設定項目の一覧と管理者を対応表として整理しておくと、環境変数が増えてきた段階でも把握しやすくなり、引き継ぎの際の混乱も抑えやすくなるでしょう。
取引先から開発を任されている立場からすると、こうした基礎的な設計が整理されているかどうかは、システム全体の保守性を測る一つの目安になり得るものです。設定項目が仕様書やREADMEなどにまとめられておらず、担当者の記憶に頼っている状態は、引き継ぎや障害対応の場面で負担になりやすいため、早めに文書化しておく価値があるでしょう。
まとめ
環境変数は、アプリケーションの設定値をコードの外、つまり実行環境側に持たせる仕組みです。同じコードを開発・検証・本番で使い回せるようになるほか、設定変更のたびにコードを直す手間を減らし、機密情報をソースコードに残しにくくする効果も期待できます。OSやコンテナが提供する標準的な機能であるため、特定の言語や製品に縛られずに導入できる点も扱いやすさにつながっています。
一方で、環境変数は平文で参照できてしまう性質を持つため、機密情報の保護という点では単体で完結する仕組みではありません。ログへの出力やエラー画面への表示に注意しながら、用途に応じて秘密情報の専用管理サービスを併用するなど、扱う情報の重要度に見合った運用を検討しておくとよいでしょう。設定を外部化するという基礎を押さえておくことが、クラウドやコンテナを前提とした運用への足がかりにもなります。
相談するメリット
「環境ごとの設定がコードに散らばっていて整理しきれていない」「機密情報の管理方法を見直したいが、どこから手を付ければよいか分からない」といったお悩みがあれば、LASSICにご相談ください。
LASSICでは、ニアショア開発体制を活かし、設定管理の見直しや機密情報の取り扱い設計、クラウド・コンテナ環境への移行支援まで、受託開発の一環として対応しています。既存システムの設定まわりを棚卸しするところから、あわせてご相談いただけます。
よくある質問
.envファイルはGitにコミットしてよいのでしょうか。
.envには接続先やAPIキーなど機密情報が含まれることが多いため、コミットは避けるのが一般的です。.gitignoreに追加してバージョン管理の対象から外し、代わりに項目名だけをまとめたサンプルファイルを共有する運用がよく用いられます。
環境変数に入れておけば機密情報は守れるのでしょうか。
環境変数は平文のまま参照できる仕組みのため、それだけで機密情報を守り切れるとは言えません。ログへの出力やエラー画面への表示に注意しつつ、重要度に応じて秘密情報の専用管理サービスの併用も検討するとよいでしょう。
環境変数とシークレットマネージャは何が違うのですか。
環境変数は名前と値の組み合わせを実行環境に持たせる一般的な仕組みで、言語やOSを問わず利用できます。シークレットマネージャは、機密情報の暗号化やアクセス権限の管理、利用履歴の記録といった機能を備えた専用サービスで、より厳格な管理が必要な場面で環境変数と組み合わせて使われることがあります。
本番環境と開発環境で設定を分けるにはどうすればよいですか。
環境ごとに異なる値を環境変数として用意し、コード側は同じロジックのまま、どの環境変数を参照するかだけを共通化しておく方法がよく使われます。開発環境では.envファイルにまとめ、本番環境ではサーバやコンテナ基盤の設定機能から値を渡す形が一般的です。
著者:テレリモ総研編集部 鈴木 亮佑