💬

devcontainerでdocker-composeを使う時にdocker-compose.ymlへの変数の受け渡し方

2022/10/24に公開

経緯

VSCodeのdevcontainer用にdocker-compose.ymlを書いていて、 同じ文字列 を使うことが多々あるので変数化できないかを調べたので結果を残します。

結論

devcontainerdocker-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で受け渡すことになります。

.envenv_file(environment)は別物

僕自身混同していましたが.envファイルとdocker-compose.yml内のenv_fileは別物です。

.env

主な用途はdocker-composedocker-compose.ymlからコンテナをビルドするタイミングで読み込まれるdefault環境変数を書くファイルです。
docker-compose.yml内に書かれた環境変数のキーに該当するキーが.envにある場合、.envの値が埋め込まれます。

たとえば

.env
USER_NAME=vscode
CONTAINER_NAME=zenn_container
HOME_DIR=/home/${USER_NAME}

と書かれた.envがある場合、以下のdocker-composeが正常に動作します。

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-composedocker-compose.ymlからコンテナをビルド完了後に、 コンテナに渡す 環境変数です。
そのため、env_fileenvironmentも同様にdocker-compose.yml内では使用できません。
正確にはただ空値状態なので、エラーにもならないけど求めてる状態にならないケースが出てきます。

devcontainerを起動する前にdocker-compose configを実行すると値が入っていない状態なのが確認できます。

env_fileenvironmentの違いはenvironmentdocker-compose.ymlに直接環境変数を書く、env_fileは環境変数を外出したファイルを作成して読み込む形式になっただけです。
docker-compose configを実行するとenvironmentに全部書いてenv_fileで環境変数が書かれたファイルを読み込んでもどちらも同じ結果が返ってきます。

(おまけ)Dockerfileなら--env-file指定できる

Dockerfile単体で立ち上げる場合は、devcontainer.jsonの設定で.env以外の設定ファイルを指定することが出来ます。
``devcontainer.jsonrunArgs`という設定があり、以下のように書くことが可能です。

devcontainer.json
{
  ...,
  "runArgs": [
    "--env-file", "<devcontainer.jsonから見た設定ファイルのパス>"
  ]
}

runArgsと書いてある通り、docker runコマンドに対する引数指定なのでdocker compose upコマンドに対しては引数指定できません。
こちらのIssuedocker-compose用の upArgs という設定ほしいよねってやりとりはあったみたいですが、そのまま流れてCloseされてますね・・・

まとめ

他にも

  • Extension fieldsでどうにかできないか(文字列連結ができなくて断念)
  • devcontainer.jsonの設定でどうにかならないか(upArgsほしい・・・)
  • postCreateCommandとかにShellScript叩かせて(postCreateCommand実行タイミングは既にコンテナ出来上がってる・・・)

とまぁ、色々試してみたのですが devcontainerdocker-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