docker-compose.yamlのentrypoint/commandフィールドで環境変数を使いたい
はじめに
docker-compose.yaml
内で環境変数を記述する際には、その展開時期に注意しましょう。entrypoint
や command
フィールドに環境変数を記述する場合には、environment
フィールドでの環境変数定義を参照できないため、別途工夫が必要です。
また、docker-compose up
実行時に、環境変数が「置換」される挙動については、使い方次第では不便な場合もあるため、注意が必要です。
問題点について、具体的なコードをあげて説明した後、対処法を紹介します。
検証環境
$ uname -moi
arm64 unknown Darwin
$ docker-compose --version
Docker Compose version v2.15.1
docker-compose.yaml
に環境変数 $VAR
を記述した時の挙動
docker-compose.yaml
には $VAR
あるいは ${VAR}
の形式で環境変数を記述できます。
環境変数の展開の挙動を確認しておきます。
以下のような docker-compose.yaml
ファイルを用意します。
version: "3"
services:
app:
image: bash
environment:
"Z": genzouw
entrypoint: echo "$X",'$Y',"$Z"
YAML ファイルを配置しているディレクトリで、以下のコマンドを実行することで Docker Compose 内に記述されているイメージを使ってコンテナが立ち上がります。
$ docker-compose up
ここで、環境変数 X
、 Y
を渡して起動してみます。Z
は docker-compose.yaml
内の environment
フィールドで定義したものを参照してみます。
$ X=hello Y=world docker-compose up
WARN[0000] The "Z" variable is not set. Defaulting to a blank string.
[+] Running 1/0
⠿ Container work-app-1 Created 0.0s
Attaching to work-app-1
work-app-1 | hello,world,
コマンド実行直後のメッセージに Z
変数についてのメッセージが表示されています。echo "$X",'$Y',"$Z"
の処理を実行した結果、Z
だけが出力されていないことからもわかりますが、環境変数は docker-compose up
実行タイミングで YAML ファイル内の各フィールド値の $AVR
の記述が「置換」されているようです。environment
フィールドの値は、 YAML ファイルの「置換」のタイミングでは利用できません。
今回の YAML は起動直後に以下の内容と同じに扱われているということです。
version: "3"
services:
app:
image: bash
environment:
"Z": genzouw
entrypoint: echo "hello",'world',""
environment
フィールドに設定した環境変数を entrypoint
/command
で参照する方法
それでは environment
フィールドで設定した環境変数を entrypoint
や command
で参照するにはどうしたら良いでしょう?
環境変数を YAML ファイル解釈のタイミングではなく、 entrypoint
実行タイミングで展開させればよいことになります。
以下のように記述することでこれを実現できます。
version: "3"
services:
app:
image: bash
environment:
"Z": genzouw
entrypoint: sh -c 'echo $X,$Y,$$Z'
$ X=hello Y=world docker-compose up
[+] Running 1/0
⠿ Container work-app-1 Recreated 0.0s
⠋ app The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested 0.0s
Attaching to work-app-1
work-app-1 | hello,world,genzouw
無事、実行結果として hello.world,genzouw
が出力されました。
$$Z
についてですが、 docker-compose.yaml
内で $$VAR
のように $
を二重に記述すると、環境変数の展開は行われず、 $VAR
という文字列リテラルとして扱われます。
シェルの \$VAR
のように解釈されたと思っていただければよいでしょう。
その後、 entrypoint
に記述されたコマンドが実行されます。
$X
と $Y
は YAML ファイル読み込み直後にすでに環境変数が展開されているので、 以下のコマンドが実行されたのと同義です。
sh -c 'echo hello,world,$Z'
結果として sh
実行時に $Z
が無事展開されます。
entrypoint
/ command
でプログラム、スクリプトを呼び出し、中で環境変数を参照する場合の注意
以下のような内容の main.sh
を用意し、 entrypoint
や command
の中で main.sh
を呼び出す場合には、今度は docker-compose
コマンド実行時に指定した環境変数を利用できません。
#!/usr/bin/env bash
echo "$X"
echo "$Y"
echo "$Z"
docker-compose.yaml
は以下のとおりです。
version: "3"
services:
app:
image: bash
environment:
"Z": genzouw
volumes:
- ./main.sh:/main.sh
entrypoint: /main.sh
実行結果は以下のようになり、 $Z
しか出力されません。
$ X=hello Y=world docker-compose up
work-app-1 |
work-app-1 |
work-app-1 | genzouw
この場合の対処は 2 つです。
1 つは docker-compose.yaml
の environment
フィールドに、コマンド実行時に設定された環境変数を引き継ぐ方法。
version: "3"
services:
app:
image: bash
environment:
"X": $X
"Y": $Y
"Z": genzouw
volumes:
- ./main.sh:/main.sh
entrypoint: /main.sh
実行します。
$ X=hello Y=world docker-compose up
[+] Running 1/0
⠿ Container work-app-1 Recreated 0.1s
⠋ app The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested 0.0s
Attaching to work-app-1
work-app-1 | hello
work-app-1 | world
work-app-1 | genzouw
もう1つは docker-compose up
ではなく docker-compose run
を使い、 -e
オプションで環境変数を指定する方法。
version: "3"
services:
app:
image: bash
environment:
"Z": genzouw
volumes:
- ./main.sh:/main.sh
entrypoint: /main.sh
実行します。
$ docker-compose run -e X=hello -e Y=world app
hello
world
genzouw
ひとこと
docker-compose up
実行時に $VAR
が置換される挙動は、個人的には少し気持ちが悪いです。
ディスカッション
コメント一覧
まだ、コメントがありません