devcontainerでdocker-composeを使う時にdocker-compose.ymlへの変数の受け渡し方
経緯
VSCodeのdevcontainer用にdocker-compose.ymlを書いていて、 同じ文字列 を使うことが多々あるので変数化できないかを調べたので結果を残します。
結論
devcontainerでdocker-composeを使う場合はおとなしく、.envを使うのことで目的は達成できます。
単体のDockerfileならdevcontainerでもdevcontainer.jsonの設定で.env以外のファイルを読み込ませることは可能でした。
この当たりも最後の方に書きます。
調査詳細
.envによる環境変数の受けわたし
結論に書いた通りで、devcontainer用のdocker-compose.ymlに環境変数を渡すのは.env になります。
docker compose upを直接実行する際には--env-fileで別のファイル名で指定することも可能です。
ですが、devcontainer立ち上げ時のdocker compose upコマンドはVSCodeが行うため、--env-fileを指定できません。
そのためコマンドに引数を渡さなくても自動で読み込まれる.envで受け渡すことになります。
.envとenv_file(environment)は別物
僕自身混同していましたが.envファイルとdocker-compose.yml内のenv_fileは別物です。
.env
主な用途はdocker-composeがdocker-compose.ymlからコンテナをビルドするタイミングで読み込まれるdefault環境変数を書くファイルです。
docker-compose.yml内に書かれた環境変数のキーに該当するキーが.envにある場合、.envの値が埋め込まれます。
たとえば
USER_NAME=vscode
CONTAINER_NAME=zenn_container
HOME_DIR=/home/${USER_NAME}
と書かれた.envがある場合、以下のdocker-composeが正常に動作します。
version: "3.4"
services:
zenn_cli_on_nodejs:
container_name: $CONTAINER_NAME
# ホスト名を明示的に指定する
hostname: localhost
build:
context: .
dockerfile: ./ubuntu/Dockerfile
args:
USER_ID: 1000
USER_NAME: $USER_NAME
GROUP_ID: 1000
GROUP_NAME: $USER_NAME
WORK_DIR: develop
environment:
- TZ=JST-9
ports:
- 8000:8000
volumes:
# ソースコードとdevcontainerを一緒に管理する場合は明示的にマウント先を指定
- ..:$HOME_DIR/develop:cached
- ~/.ssh:$HOME_DIR/.ssh
- .extensions:$HOME_DIR/.vscode-server/extensions
command: sleep infinity
$ docker-compose config
services:
zenn_cli_on_nodejs:
build:
args:
GROUP_ID: '1000'
GROUP_NAME: vscode
USER_ID: '1000'
USER_NAME: vscode
WORK_DIR: develop
context: /home/*****/develop/zenn-content/.devcontainer
dockerfile: ./ubuntu/Dockerfile
command: sleep infinity
container_name: zenn_container
environment:
TZ: JST-9
hostname: localhost
ports:
- published: 8000
target: 8000
volumes:
- /home/*****/develop/zenn-content:/home/vscode/develop:cached
- /home/*****/.ssh:/home/vscode/.ssh:rw
- /home/*****/develop/zenn-content/.devcontainer/.extensions:/home/vscode/.vscode-server/extensions:rw
version: '3.4'
補足ですが、docker compose upのオプション--env-fileでファイル指定した場合も同じですタイミングで読み込まれます。
docker-compose.yml内のenv_fileやenvironment
こちらはdocker-composeがdocker-compose.ymlからコンテナをビルド完了後に、 コンテナに渡す 環境変数です。
そのため、env_fileやenvironmentも同様にdocker-compose.yml内では使用できません。
正確にはただ空値状態なので、エラーにもならないけど求めてる状態にならないケースが出てきます。
devcontainerを起動する前にdocker-compose configを実行すると値が入っていない状態なのが確認できます。
env_fileとenvironmentの違いはenvironmentはdocker-compose.ymlに直接環境変数を書く、env_fileは環境変数を外出したファイルを作成して読み込む形式になっただけです。
docker-compose configを実行するとenvironmentに全部書いてenv_fileで環境変数が書かれたファイルを読み込んでもどちらも同じ結果が返ってきます。
(おまけ)Dockerfileなら--env-file指定できる
Dockerfile単体で立ち上げる場合は、devcontainer.jsonの設定で.env以外の設定ファイルを指定することが出来ます。
``devcontainer.jsonにrunArgs`という設定があり、以下のように書くことが可能です。
{
...,
"runArgs": [
"--env-file", "<devcontainer.jsonから見た設定ファイルのパス>"
]
}
runArgsと書いてある通り、docker runコマンドに対する引数指定なのでdocker compose upコマンドに対しては引数指定できません。
こちらのIssueでdocker-compose用の upArgs という設定ほしいよねってやりとりはあったみたいですが、そのまま流れてCloseされてますね・・・
まとめ
他にも
-
Extension fieldsでどうにかできないか(文字列連結ができなくて断念) -
devcontainer.jsonの設定でどうにかならないか(upArgsほしい・・・) -
postCreateCommandとかにShellScript叩かせて(postCreateCommand実行タイミングは既にコンテナ出来上がってる・・・)
とまぁ、色々試してみたのですが devcontainerでdocker-composeを使う場合は.env の決め打ちでいいんじゃないかなって気がしてます。
もしコンテナに対してenvファイル使いたい場合はそちらの名前をdevcontainer.envなどの名前に変えるほうが自然かもしれません。
とりあえずは今回はここまでにしました。
参考資料
Qiita - docker-compose.ymlの中で環境変数を展開する
Compose ファイル (docker-compose.yml) 内で環境変数を参照する
docker docs - Environment variables in Compose - The “.env” file
docker docs 日本語版 - Compose における環境変数 - .envファイル
docker docs - Environment variables in Compose - Using the “--env-file” option
docker docs 日本語版 - Compose における環境変数 - --env-fileオプションの利用
docker docs - Compose specification - environment
Discussion