---
title: "環境変数とは？Linux・Windowsの設定方法とDocker・CIでの受け渡し"
url: "https://www.issoh.co.jp/tech/details/17616/"
published: 2026-09-15
updated: 2026-09-23
categories: ["インフラ・クラウド"]
publisher: "株式会社一創"
---

# 環境変数とは？Linux・Windowsの設定方法とDocker・CIでの受け渡し

環境変数は、OSがプロセスへ渡す `name=value` 形式の文字列です。`PATH` のようにOSが用意するものと、接続先URLやログレベルのようにアプリケーション側で決めるものが、同じ仕組みに同居しています。この記事では、POSIXの定義から見た実体、LinuxとWindowsの設定・永続化コマンド、PythonとNode.jsでの読み取りの注意点、Docker ComposeとGitHub Actionsでの優先順位を公式ドキュメントに沿って整理しました。機密情報の線引きと、反映されないときの切り分け手順も後半に置いています。

## まとめ｜環境変数の設定と受け渡しで最初に決める4点

環境変数は name=value の文字列の集まりで、プロセス起動時に親から子へ**コピー**として渡ります。値を書き換えても、すでに動いているプロセスには届きません。「設定したシェル」と「動かしているプロセス」のずれが、反映されない原因の大半です。

永続化の手段はOSで分かれます。LinuxとmacOSはシェルの初期化ファイルか `/etc/environment`、Windowsは `SetEnvironmentVariable` のUser/Machineスコープ。デーモンはシェルを経由しないため、systemdやコンテナ側で別途渡す設計が要ります。値は常に文字列で型を持たず、`"false"` もPythonでもJavaScriptでも真と評価されます。

機密情報は「全部だめ」でも「全部よい」でもありません。**デプロイなしで失効と更新を回せるか**で線を引きます。AWS Lambdaのように合計4KBの上限を持つ実行環境もあり、鍵の類はParameter StoreやSecrets Managerへ逃がすのが実務上の落としどころです。

## 環境変数の実体｜name=value文字列とプロセス継承の仕組み

環境変数が「どこに存在するのか」を仕様で押さえます。ここが曖昧なまま設定コマンドだけ覚えると、反映されない場面で詰まります。

### name=value の文字列配列として子プロセスへ渡る仕組み

POSIX（Open Group Base Specifications Issue 8）は、環境を「name=value の形式を持つ文字列の配列」と定義しています。プログラムからは `environ` という外部変数として見え、name の部分に `=` を含むバイトは置けません（[Environment Variables / The Open Group Base Specifications Issue 8](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1%5Fchap08.html)）。値の側の改行やスペースは可能で、禁止は名前側の等号だけです。

渡され方はコピーです。子が自分の環境を書き換えても親には戻らず、親を書き換えても起動済みの子には反映されません。プロセスが実際に持つ値は、Linuxなら次の3行で確認できます。

```
printenv PATH
env | sort | head -20
tr '\0' '\n' < /proc/self/environ
```

3行目はカーネル側の情報から直接読む方法で、PIDを差し替えれば別プロセスが起動時に受け取った値も見えます。切り分けでは、設定ファイルより実際に渡っている値を先に見ます。

### POSIXが定める命名規則とWindows・Linuxで割れる大文字小文字の扱い

POSIXは、標準ユーティリティが使う環境変数名を「大文字・数字・アンダースコアのみで構成し、数字で始まらない」と規定しました。小文字を含む名前空間はアプリケーション用の予約です。実務では `APP_DB_HOST` のように全大文字とアンダースコアで統一し、プレフィックスで名前空間を切ります。

大文字小文字の区別はOSで割れます。PowerShellの公式ドキュメントは、macOSとLinuxでは名前が区別されるため `$Env:Path` と `$Env:PATH` が別の変数になると注意しています（[環境変数について / Microsoft Learn](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about%5Fenvironment%5Fvariables)）。Windowsでは区別されません。差はランタイムにも出て、Pythonの `os.environ` はWindowsでキーを大文字へ変換して保持します。Windows前提のコードをLinuxコンテナへ載せた途端に値が取れない事故は、ほぼこの仕様差が原因です。

## LinuxとmacOSでの設定手順｜exportと初期化ファイルでの永続化

Unix系ではシェル変数と環境変数が別物で、その境目を作るのが `export` です。

### exportとenv・printenvで設定値を確認するコマンド操作

Bashのリファレンスマニュアルは、シェルが実行するコマンドへ渡される環境について、`export` でマークされた変数が子プロセスの環境へ入ると説明しています（[Environment / Bash Reference Manual](https://www.gnu.org/software/bash/manual/html%5Fnode/Environment.html)）。単に `VAR=value` と書いただけではシェル変数にとどまり、起動したコマンドからは見えません。効く範囲は3段階です。

```
APP_ENV=staging ./run.sh     # このコマンド1回だけ
export APP_ENV=staging       # 今のシェルと、以降そこから起動する子
printenv APP_ENV             # 環境変数として入っているかの確認
set | grep APP_ENV           # シェル変数も含めた一覧（export前でも出る）
```

`printenv` に出ず `set` にだけ出るなら、export 漏れです。この確認を挟むだけで「値は書いたのに読めない」の相当数が片付きます。`env -i` なら環境を空にした状態も再現できます。

### .bashrcとsystemd・/etc/environmentでの永続化の使い分け

ログインのたびに効かせたい値は、シェルの初期化ファイル（bashは `~/.bashrc`、zshは `~/.zshrc`）へ書きます。システム全体に効かせるなら `/etc/environment` へ key=value を並べるか、`/etc/profile.d` にスクリプトを置く方法をMicrosoftの公式ドキュメントも案内しています。前者はシェルスクリプトではないため、変数展開やコマンド置換は書けません。

落ちやすいのがデーモンです。systemdが起動するサービスはログインシェルを経由せず、`~/.bashrc` の値は一切渡りません。ユニットファイルの `Environment=` で明示的に渡します。サービス管理の全体像は[systemdの役割と基本構成の解説](https://www.issoh.co.jp/tech/details/8160/)、Linuxの土台は[Linuxの仕組みとサーバー用途の解説](https://www.issoh.co.jp/tech/details/13160/)で扱っています。

## Windowsでの設定手順｜PowerShellの3スコープと永続化の判断

WindowsにはMachine・User・Processの3スコープがあり、どこに書いたかで再起動後に残るかが決まります。

### $env:による一時設定とSetEnvironmentVariableでの永続設定

PowerShellの `$Env:` ドライブ経由の変更は、現在のセッションにしか影響しません。公式ドキュメントは、これがコマンドシェルの `set` と同じ振る舞いであり、MachineやUserスコープを変えるには **System.Environment** クラスのメソッドが必要だと説明しています。

```
$Env:APP_ENV = 'staging'
[Environment]::SetEnvironmentVariable('APP_ENV', 'staging', 'User')
[Environment]::GetEnvironmentVariable('APP_ENV', 'Machine')
[Environment]::SetEnvironmentVariable('APP_ENV', '', 'User')
```

3番目の引数がスコープです。UserとMachineはレジストリへ書かれるため、プロセスを抜けても残ります。Machineスコープの変更には権限が必要で、足りなければコマンドは失敗。4行目の空文字設定は、そのスコープからの削除として働きます。なお `SetEnvironmentVariable()` へ `$null` を渡しても削除にならない点は、変数構文経由の挙動との差としてドキュメントに注記されています。

### PATHへ追記した値がターミナルの再起動まで反映されない理由

Processスコープの内容は、プロセス起動時にMachineスコープとUserスコープから組み立てられます。コントロールパネルや `SetEnvironmentVariable` でUserスコープへ書いても、開いているターミナルやエディタには伝わりません。開発ツールのインストール直後に `PATH` が通らないのは、この構築タイミングの問題です。ターミナルを開き直すか、統合ターミナルを持つエディタごと再起動すれば解決します。

区切り文字にも差があり、Windowsのパス一覧はセミコロン、Windows以外はコロンです。クロスプラットフォームのスクリプトでは、区切り文字を直書きせず言語側の定数（Pythonなら `os.pathsep`）を使います。

## PythonとNode.jsから環境変数を読む際の型と取得タイミング

アプリケーション側の読み取りには、言語ごとの落とし穴があります。いずれも公式ドキュメントに明記された挙動です。

### os.environがインポート時のスナップショットである点の注意

Pythonの `os.environ` は、`os` モジュールが最初にインポートされた時点（通常は起動時）の環境をキャプチャしたマッピングです。その後にプロセス外部で環境が変わっても反映されません（[os — 雑多なオペレーティングシステムインターフェース / Python 3 ドキュメント](https://docs.python.org/ja/3/library/os.html)）。Python 3.14では、取り込みをやり直す `os.reload_environ()` が追加されました。

書き込み側は非対称です。`os.environ` への代入は内部で `putenv()` を呼ぶため、`subprocess` などで起動する子プロセスへ値が伝わります。一方 `os.putenv()` の直接呼び出しは `os.environ` へ反映されず、`os.getenv()` からも見えません。

```
import os

db_host = os.environ.get('APP_DB_HOST', 'localhost')
debug = os.environ.get('APP_DEBUG', '0') == '1'
os.environ['APP_ENV'] = 'staging'  # 子プロセスへ伝わる
print(db_host, debug)
```

### process.envの値が常に文字列になるNode.jsの取り扱い

Node.jsの `process.env` は、代入した値を暗黙に文字列へ変換します。`null` を代入すれば `'null'` という4文字の文字列です。公式ドキュメントはこの暗黙変換を非推奨と位置づけ、将来のバージョンでは文字列・数値・真偽値以外でエラーを投げる可能性があると予告しました（[process / Node.js ドキュメント](https://nodejs.org/api/process.html)）。削除は `delete process.env.X` です。

ワーカースレッドを使う構成では、各ワーカーが親スレッドの `process.env` のコピーを持ちます。ワーカー内の変更は他スレッドへ見えず、OSやネイティブアドオンから見える変更を行えるのはメインスレッドだけ。しかもWindowsでは、ワーカー側のコピーだけが大文字小文字を区別します。設定値の再読み込みをワーカーへ任せる設計は破綻します。

## .envファイルとdotenvで開発環境の設定値をまとめる手順

ローカル開発では値をファイルへまとめると再現性が上がります。ただし .env はOSの機能ではありません。

### dotenvでの読み込みと.envをGitに入れない共有の手順

.env ファイルを読むのは、ライブラリかランタイムの機能です。Node.jsは `--env-file` オプションと `process.loadEnvFile()` を備え、PythonやRuby、PHPではdotenv系のライブラリが同じ役割を担いました。言語別の書き方は[dotenvと.envファイルの仕組みを解説した記事](https://www.issoh.co.jp/tech/details/3573/)で扱っています。The Twelve-Factor Appの「設定をコードから分離し、環境に持たせる」原則（[設定 / The Twelve-Factor App](https://12factor.net/ja/config)）に沿うなら、全員が同じ値を使えるものだけをファイルへ残します。

実際の形は、.env を `.gitignore` へ入れ、キー名だけを書いた `.env.example` を共有するものです。プロジェクトのディレクトリへ入ったときだけ .env の値をシェルへ流し込みたい場合は、[direnvで.envrcを使ってディレクトリ単位に環境変数を切り替える方法](https://www.issoh.co.jp/tech/details/17741/)が使えます。

```
# .gitignore
.env
.env.*.local

# .env.example
APP_DB_HOST=localhost
APP_DB_PASSWORD=          # 値は各自のパスワードマネージャから
APP_LOG_LEVEL=debug
```

誤ってコミットした場合は、履歴から消す作業より先に**その値を失効させる**のが正しい順序です。履歴の書き換えではフォークやキャッシュまで追えません。

## コンテナとCIでの受け渡し｜Composeの優先順位とActionsの使い分け

同じ変数名が複数の場所に書かれると、どれが勝つかで挙動が変わります。ここは推測せず、公式の優先順位表に当たります。

### Docker Composeで同名の値が競合したときの優先順位

Docker公式ドキュメントは、Compose環境での優先順位を高い順に次のように示しています（[Environment variables precedence in Docker Compose / Docker Docs](https://docs.docker.com/compose/how-tos/environment-variables/envvars-precedence/)）。

| 順位 | 設定場所                     | 使いどころ     |
| -- | ------------------------ | --------- |
| 1  | docker compose run -e    | 一時的な上書き   |
| 2  | シェルや.envからの補間            | 環境ごとの差分   |
| 3  | compose.yamlのenvironment | 固定値の明示    |
| 4  | compose.yamlのenv\_file   | まとまった既定値  |
| 5  | DockerfileのENV           | イメージ内の既定値 |

注意点がひとつあります。Compose側で `environment`・`env_file`・`run --env` のいずれかが設定されている場合、Dockerfile内の `ARG` や `ENV` は評価されません。イメージへ焼いた既定値が効かないときは、この条件を先に疑います。`ENV` 命令の書き方は[Dockerfileの主要命令と書き方の解説](https://www.issoh.co.jp/tech/details/3315/)で整理しました。

### GitHub Actionsのenv・vars・secretsの使い分けと上限

GitHub Actionsでは、機密でない構成値を `vars`、機密を `secrets`、ワークフロー内で参照する環境変数を `env` で扱います。公式リファレンスによれば、個々の変数は48KBまで、保存できる数は組織1,000件・リポジトリ500件・環境100件で、1実行あたりの組織とリポジトリの変数合計は256KBに制限されます（[Variables reference / GitHub Docs](https://docs.github.com/en/actions/reference/workflows-and-actions/variables)）。同名なら下位のレベル（環境 → リポジトリ → 組織）が優先されます。

```
jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      APP_ENV: staging
      APP_REGION: 変数参照（vars.APP_REGION）
    steps:
      - run: ./deploy.sh
        env:
          APP_TOKEN: 機密参照（secrets.DEPLOY_TOKEN）
```

置く階層で露出範囲が変わるため、トークンの類はステップ単位へ絞ります。受け渡しの詳細は[GitHub Actionsのenv・vars・secretsの使い分け](https://www.issoh.co.jp/tech/details/16921/)で扱っています。

### KubernetesのConfigMapとSecretから環境変数を渡す方法

Kubernetesでは、コンテナの `env` に個別指定するか、`envFrom` でConfigMapのキーをまとめて環境変数として展開します（[ConfigMap / Kubernetes ドキュメント](https://kubernetes.io/ja/docs/concepts/configuration/configmap/)）。

```
envFrom:
  - configMapRef:
      name: app-config
env:
  - name: APP_DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: app-secret
        key: db-password
```

ConfigMapは機密を保持する仕組みではありません。パスワードはSecretへ置きますが、Secretも既定ではetcdにBase64エンコードで格納されるだけなので、保存時暗号化とRBACでの参照制限を別途かけます。環境変数として渡した値は、ConfigMapを更新してもPodを作り直すまで変わりません。

## 機密情報を環境変数に置く判断基準｜4KB上限とシークレット管理

「環境変数に秘密を置くな」と「12factorは環境変数を推奨している」は、どちらも実務では雑すぎます。条件を切って判断します。

### 環境変数に置いてよい値と外部の秘密管理へ逃がすべき値の線引き

判断軸はひとつです。**その値を失効・更新するのに、デプロイし直す必要があるか**。必要なら環境変数から出します。この軸で切ると次のように分かれます。

- 置いてよい：接続先ホスト名、リージョン、ログレベル、機能フラグ、タイムアウト値
- 置いてよい：CIジョブ内の短命なトークン（secretsのマスクが効き、ジョブ終了で消える）
- 逃がす：本番DBのパスワード、長期有効のAPIキー、秘密鍵、決済系の資格情報

逃がす理由は、環境変数が「読める場所が多い」ことにあります。子プロセスへ自動的に継承され、クラッシュダンプに載り、フレームワークによっては起動ログへ環境一式が出るためです。AWSであれば[Parameter StoreとSecrets Managerの違いと使い分け](https://www.issoh.co.jp/tech/details/3412/)で整理した参照方式へ切り替え、環境変数には「どこから取るか」のパス名だけを置きます。

### Lambdaの4KB上限に当たったときの分割と参照方式の選択

AWS Lambdaは、すべての環境変数の合計サイズが4KBを超えないことを要件としています。`_HANDLER`、`AWS_REGION`、実行ロールから渡される `AWS_ACCESS_KEY_ID` などの予約済み変数も存在します（[Lambda 環境変数の操作 / AWS ドキュメント](https://docs.aws.amazon.com/ja%5Fjp/lambda/latest/dg/configuration-envvars.html)）。値は保管時に暗号化され、別のKMSキー指定も選べます。

4KBに当たったときの打ち手は、設定をJSONへまとめてS3やParameter Storeへ置き、起動時に取得して実行環境のメモリへキャッシュする形です。取得の往復は初回だけで済み、上限も事実上外れます。どこから参照方式へ倒すかは起動頻度で変わるため、[AWS・Google Cloud・Azureのインフラ構築支援](https://www.issoh.co.jp/service/system/aws/)で構成ごと相談する手も取れます。

## 設定しても反映されない場合の切り分け｜継承・sudo・cronの落とし穴

実際に手が止まる場面の潰し方をまとめます。原因は毎回ほぼ同じ場所です。

### 設定した値が子プロセスへ継承されないときに確認する3つの起点

第一に、export したか。`set` には出るが `printenv` に出ないなら、シェル変数のままです。第二に、対象プロセスを再起動したか。環境は起動時にコピーされるため、稼働中のプロセスへは届きません。第三に、設定したユーザーと実行ユーザーが同じか。デプロイユーザーのシェル設定は、サービス実行ユーザーには無関係です。

推測で潰すより、動いているプロセスが受け取った値を直接見るほうが早く終わります。Linuxなら `tr '\0' '\n' < /proc/<PID>/environ`、Windowsなら `[Environment]::GetEnvironmentVariable('APP_ENV','Machine')` でスコープを指定して読みます。

### sudo・cron・systemdで環境変数が消える仕様と回避の書き方

ユーザーのシェルでは動くのに、別の起動経路だと消える。これは仕様で、回避策も決まっています。

1. sudo：既定の env\_reset が効き、PATHも安全な既定値へ置き換わります。`sudo -E` か、sudoers側での変数指定で引き継ぎます
2. cron：初期化ファイルを読まず最小限の環境で実行されます。crontab内で変数を明示し、コマンドは絶対パスで書きます
3. systemd：同じくシェルを経由しません。ユニットの `Environment=` か `EnvironmentFile=` で渡します

コンテナも同じ系統の問題を抱えます。`docker exec` で入って確認した環境と `ENTRYPOINT` が受け取った環境は一致しないことがあるため、確認はアプリケーションを起動しているプロセスのPIDに対して行ってください。

## よくある質問

環境変数の扱いで実際に検索されている質問を5つ、仕様の根拠とあわせて答えます。

### 環境変数とシェル変数はどう違いますか？

シェル変数はそのシェルの内部だけで有効な変数で、環境変数は起動する子プロセスへ引き継がれる変数です。Bashでは `VAR=value` の段階ではシェル変数で、`export VAR` を実行して初めて環境に入ります。確認方法も分かれ、`set` は両方を、`printenv` は環境変数だけを表示します。プログラムから読めない場合、この境目を越えていないケースがほとんどです。

### 環境変数に設定できる値の長さに上限はありますか？

POSIXの仕様として固定の上限値は定められておらず、実際の上限は実行環境ごとに決まります。AWS Lambdaはすべての環境変数の合計で4KB、GitHub Actionsは個々の変数が48KBまでです。Linuxではコマンドライン引数と環境の合計サイズに制限があり、長大な値は起動時のエラーになります。数KBを超える設定はファイルや外部ストアへ逃がしてください。

### 環境変数の名前は大文字と小文字のどちらで書くべきですか？

全大文字とアンダースコアで統一するのが無難です。POSIXは標準ユーティリティが使う名前を大文字・数字・アンダースコアのみと規定し、小文字を含む名前空間をアプリケーション側へ予約しました。ただしWindowsは大文字小文字を区別せず、LinuxとmacOSは区別するため、小文字名を混ぜると環境間で挙動が割れます。`APP_DB_HOST` のようにプレフィックスで名前空間を切れば、他ツールの変数との衝突も避けられます。

### .envファイルは本番環境でも使ってよいですか？

本番では使わず、実行基盤側の仕組みで渡す形を推奨します。ファイルとして配置すると、誤ってイメージへ焼き込まれたりバックアップ経路に乗ったりするためです。コンテナならKubernetesのSecret、サーバーレスなら実行環境の設定とシークレットストアの参照を使います。読み込み経路を分けておけば、開発用の値が本番へ紛れ込む事故も防げます。

### 環境変数を変更したのにアプリに反映されないのはなぜですか？

環境はプロセス起動時にコピーされる仕様のため、稼働中のプロセスには新しい値が届きません。まずアプリケーションのプロセスを再起動してください。それでも変わらない場合は、設定を書いた場所と実行ユーザー・起動経路の一致を確認します。Pythonのように起動時のスナップショットを保持する言語では、外部から書き換えてもプロセス内のマッピングは変わりません（3.14以降は `os.reload_environ()` で取り直せます）。

## 関連記事

- [dotenvとは？.envで環境変数を管理する仕組みと言語別の使い方](https://www.issoh.co.jp/tech/details/3573/)：.envの読み込みを言語別に深掘りしています
- [GitHub Actionsの環境変数｜env・vars・secretsの使い分けと受け渡し](https://www.issoh.co.jp/tech/details/16921/)：CI上での受け渡しとマスク機構の各論です
- [パラメータストアとは？AWS Parameter Storeの料金・使い方・Secrets Managerとの違いを解説](https://www.issoh.co.jp/tech/details/3412/)：環境変数から逃がした値の置き場所を比較しています
- [Dockerfileとは｜書き方・主要命令・ベストプラクティスを解説【2026年版】](https://www.issoh.co.jp/tech/details/3315/)：ENV命令の書き方とイメージ内の既定値を扱っています
- [systemdとは何か？Linuxにおける役割と概要解説](https://www.issoh.co.jp/tech/details/8160/)：デーモンへ設定値を渡す前提知識です

---

出典: [環境変数とは？Linux・Windowsの設定方法とDocker・CIでの受け渡し](<https://www.issoh.co.jp/tech/details/17616/>)（株式会社一創）
