前提
ドキュメントによると、 .env
で変数を指定した場合でも環境変数のほうが優先されると書いてある。
Values in the shell take precedence over those specified in the
.env
file.
Environment variables in Compose | Docker Documentation
実行時に環境変数を指定すると、常に .env ファイル中で定義した変数を上書きします。
環境ファイル — Docker-docs-ja 17.06.Beta ドキュメント
背景(不思議な挙動)
環境変数 http_proxy
が設定されている状態で .env
に http_proxy
を別の値で記述すると .env
の値が優先された1。
ドキュメントの記述と一致していないように感じたので調査した。
検証
環境
Windows 10 Home + docker-machine
$ docker.exe --version
Docker version 18.03.0-ce, build 0520e24302
$ docker-compose.exe --version
docker-compose version 1.20.1, build 5d8c71b2
$ docker-machine.exe --version
docker-machine.exe version 0.14.0, build 89b8332
$ docker-machine.exe ssh default docker --version
Docker version 18.09.1, build 4c52b90
docker-compose.yml
version: '3'
services:
test:
image: alpine:3.9
command: env
environment:
- AAA
- BBB
- CCC
- DDD
- EEE
- fff
- ggg
- hhh
- iii
- jjj
.env
AAA=.env_var
BBB=.env_var
CCC=.env_var
DDD=.env_var
EEE=.env_var
fff=.env_var
ggg=.env_var
hhh=.env_var
iii=.env_var
jjj=.env_var
環境変数
以下の4つを環境変数として設定
- DDD
- EEE
- iii
- jjj
$ env | sort | grep env_var
DDD=user_env_var
EEE=system_env_var
iii=user_env_var
jjj=system_env_var
※ Windows環境のため、ユーザー環境変数とシステム変数を大文字小文字それぞれ設定
test.sh
以下の変数を sh
内で定義2
- シェル変数
AAA
fff
- 環境変数 (
export
2)BBB
ggg
# !/bin/sh -x
cat .env
echo -e "\n\n"
printenv AAA
printenv BBB
printenv CCC
printenv DDD
printenv EEE
printenv fff
printenv ggg
printenv hhh
printenv iii
printenv jjj
echo -e "\n\n"
AAA=sh_var
export BBB=exported_sh_var
fff=sh_var
export ggg=exported_sh_var
echo -e "\n\n"
printenv AAA
printenv BBB
printenv CCC
printenv DDD
printenv EEE
printenv fff
printenv ggg
printenv hhh
printenv iii
printenv jjj
echo -e "\n\n"
docker-compose config
docker-compose up
実行結果
Git Bash で実行した。
$ ./test.sh
+ cat .env
AAA=.env_var
BBB=.env_var
CCC=.env_var
DDD=.env_var
EEE=.env_var
fff=.env_var
ggg=.env_var
hhh=.env_var
iii=.env_var
jjj=.env_var
+ echo -e '\n\n'
+ printenv AAA
+ printenv BBB
+ printenv CCC
+ printenv DDD
user_env_var
+ printenv EEE
system_env_var
+ printenv fff
+ printenv ggg
+ printenv hhh
+ printenv iii
user_env_var
+ printenv jjj
system_env_var
+ echo -e '\n\n'
+ AAA=sh_var
+ export BBB=exported_sh_var
+ BBB=exported_sh_var
+ fff=sh_var
+ export ggg=exported_sh_var
+ ggg=exported_sh_var
+ echo -e '\n\n'
+ printenv AAA
+ printenv BBB
exported_sh_var
+ printenv CCC
+ printenv DDD
user_env_var
+ printenv EEE
system_env_var
+ printenv fff
+ printenv ggg
exported_sh_var
+ printenv hhh
+ printenv iii
user_env_var
+ printenv jjj
system_env_var
+ echo -e '\n\n'
+ docker-compose config
services:
test:
command: env
environment:
AAA: .env_var
BBB: exported_sh_var
CCC: .env_var
DDD: user_env_var
EEE: system_env_var
fff: .env_var
ggg: .env_var
hhh: .env_var
iii: .env_var
jjj: .env_var
image: alpine:3.9
version: '3.0'
+ docker-compose up
Starting 1_test_1 ... done
Attaching to 1_test_1
test_1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
test_1 | HOSTNAME=02a7c6031232
test_1 | AAA=.env_var
test_1 | BBB=exported_sh_var
test_1 | CCC=.env_var
test_1 | DDD=user_env_var
test_1 | EEE=system_env_var
test_1 | fff=.env_var
test_1 | ggg=.env_var
test_1 | hhh=.env_var
test_1 | iii=.env_var
test_1 | jjj=.env_var
test_1 | HOME=/root
1_test_1 exited with code 0
fff
~ jjj
が全て .env
が優先され、 .env
で定義した .env_var
になっている。
fff: .env_var
ggg: .env_var
hhh: .env_var
iii: .env_var
jjj: .env_var
ちなみに、Linux環境では、 AAA
~ EEE
と同じように環境変数が優先される。
fff: .env_var
ggg: exported_sh_var
hhh: .env_var
iii: user_env_var
jjj: system_env_var
おまけ
変数名に小文字・数字・記号が入る場合
- 大文字・小文字(
Xx
):.env
優先(Linux環境では環境変数優先) - 大文字・数字(
Y123
): 環境変数優先 - 大文字・記号(
Z_Z
): 環境変数優先
docker-compose.yml
version: '3'
services:
test:
image: alpine:3.9
command: env
environment:
- Xx
- Y123
- Z_Z
.env
Xx=.env_var
Y123=.env_var
Z_Z=.env_var
test.sh
# !/bin/sh -x
cat .env
echo -e "\n\n"
export Xx=exported_sh_var
export Y123=exported_sh_var
export Z_Z=exported_sh_var
echo -e "\n\n"
printenv Xx
printenv Y123
printenv Z_Z
echo -e "\n\n"
docker-compose config
docker-compose up
実行結果
$ ./test.sh
+ cat .env
Xx=.env_var
Y123=.env_var
Z_Z=.env_var
+ echo -e '\n\n'
+ export Xx=exported_sh_var
+ Xx=exported_sh_var
+ export Y123=exported_sh_var
+ Y123=exported_sh_var
+ export Z_Z=exported_sh_var
+ Z_Z=exported_sh_var
+ echo -e '\n\n'
+ printenv Xx
exported_sh_var
+ printenv Y123
exported_sh_var
+ printenv Z_Z
exported_sh_var
+ echo -e '\n\n'
+ docker-compose config
services:
test:
command: env
environment:
Xx: .env_var
Y123: exported_sh_var
Z_Z: exported_sh_var
image: alpine:3.9
version: '3.0'
Linux環境での実行結果(抜粋)
Xx: exported_sh_var
Y123: exported_sh_var
Z_Z: exported_sh_var
大文字環境変数でも強制的に上書きする
source ./.env
を実行する
※ これだけLinux環境でも同じ挙動となった
docker-compose.yml
version: '3'
services:
test:
image: alpine:3.9
command: env
environment:
- AAA
- BBB
- CCC
.env
AAA=.env_var
BBB=.env_var
test.sh
# !/bin/sh -x
export BBB=exported_sh_var
export CCC=exported_sh_var
echo -e "\n\n"
printenv AAA
printenv BBB
printenv CCC
echo -e "\n\n"
source ./.env
echo -e "\n\n"
printenv AAA
printenv BBB
printenv CCC
echo -e "\n\n"
docker-compose config
docker-compose up
実行結果
$ ./test.sh
+ export BBB=exported_sh_var
+ BBB=exported_sh_var
+ export CCC=exported_sh_var
+ CCC=exported_sh_var
+ echo -e '\n\n'
+ printenv AAA
+ printenv BBB
exported_sh_var
+ printenv CCC
exported_sh_var
+ echo -e '\n\n'
+ source ./.env
++ AAA=.env_var
++ BBB=.env_var
+ echo -e '\n\n'
+ printenv AAA
+ printenv BBB
.env_var
+ printenv CCC
exported_sh_var
+ echo -e '\n\n'
+ docker-compose config
services:
test:
command: env
environment:
AAA: .env_var
BBB: .env_var
CCC: exported_sh_var
image: alpine:3.9
version: '3.0'
コンテナ内に渡す環境変数だけ指定したいなら env_file
env_file: my.env
のように docker-compose.yml
に書くことで、 environment
のように環境変数をコンテナに直接渡せる。
※ .env
の定義は docker-compose.yml
内でも使えるため、完全な代替ではない
優先順位
-
environment
(環境変数) -
environment
(.env
) env_file
docker-compose.yml
version: '3'
services:
test:
image: alpine:3.9
env_file: my.env
command: env
environment:
- BBB
- CCC
.env
AAA=.env_var
BBB=.env_var
CCC=.env_var
my.env
AAA=my.env_var
BBB=my.env_var
CCC=my.env_var
test.sh
# !/bin/sh -x
cat .env
echo -e "\n\n"
cat my.env
echo -e "\n\n"
printenv AAA
printenv BBB
printenv CCC
echo -e "\n\n"
export CCC=exported_sh_var
echo -e "\n\n"
printenv AAA
printenv BBB
printenv CCC
echo -e "\n\n"
docker-compose config
実行結果
$ ./test.sh
+ cat .env
AAA=.env_var
BBB=.env_var
CCC=.env_var
+ echo -e '\n\n'
+ cat my.env
AAA=my.env_var
BBB=my.env_var
CCC=my.env_var
+ echo -e '\n\n'
+ printenv AAA
+ printenv BBB
+ printenv CCC
+ echo -e '\n\n'
+ export CCC=exported_sh_var
+ CCC=exported_sh_var
+ echo -e '\n\n'
+ printenv AAA
+ printenv BBB
+ printenv CCC
exported_sh_var
+ echo -e '\n\n'
+ docker-compose config
services:
test:
command: env
environment:
AAA: my.env_var
BBB: .env_var
CCC: exported_sh_var
image: alpine:3.9
version: '3.0'
結論
Windows環境の場合、
- 変数に
- 小文字が含まれる場合は
.env
のほうが優先される - 小文字が含まれない場合(大文字・数字・記号のみの場合)は 環境変数 のほうが優先される
- 小文字が含まれる場合は
- 小文字が含まれない変数も
.env
を優先させたい場合はsource ./.env
を実行することで環境変数の優先をキャンセルできる- ※ env_file を使ったほうが自然&楽
Linux環境の場合、
- 変数名中の小文字の有無によらず 環境変数 のほうが優先される
-
.env
を優先させたい場合はsource ./.env
を実行することで環境変数の優先をキャンセルできる- ※ env_file を使ったほうが自然&楽