これは、なにをしたくて書いたもの?
Docker Composeの構成ファイル内で(環境)変数を参照できるのはなんとなく知っていましたが、ちゃんと試したことがなかったので
自分でも確認しておきたいなということで。
環境
今回の環境は、こちら。
$ docker version Client: Docker Engine - Community Version: 23.0.1 API version: 1.42 Go version: go1.19.5 Git commit: a5ee5b1 Built: Thu Feb 9 19:47:01 2023 OS/Arch: linux/amd64 Context: default Server: Docker Engine - Community Engine: Version: 23.0.1 API version: 1.42 (minimum version 1.12) Go version: go1.19.5 Git commit: bc3805a Built: Thu Feb 9 19:47:01 2023 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.6.18 GitCommit: 2456e983eb9e37e47538f59ea18f2043c9a73640 runc: Version: 1.1.4 GitCommit: v1.1.4-0-g5fd4c4d docker-init: Version: 0.19.0 GitCommit: de40ad0 $ docker compose version Docker Compose version v2.16.0
Docker Composeの構成ファイルで変数を参照する
こちらのドキュメントで、簡単に触れられていますが
Ways to set environment variables in Compose | Docker Documentation
Docker Composeの構成ファイルのリファレンスの、Interpolationを参照するのがよいでしょうね。
Compose file specification / Interpolation
bashと似た${...}
という構文で参照するようです。変数、変数と書いていますが、実体としては環境変数ですね。
ちょっと見てみましょう。
$VARIABLE
と${VARIABLE}
の両方の書き方をサポート- シェル構文を使ったもの
${VARIABLE:-default}
… 変数VARIABLE
が設定されていないまたは空の場合は、デフォルト値としてdefault
を使用する${VARIABLE-default}
… 変数VARIABLE
が設定されていない場合にのみ、デフォルトとしてdefault
を使用する${VARIABLE:?err}
… 変数VARIABLE
が設定されていないまたは空の場合は、エラーメッセージとしてerr
を出力して終了する${VARIABLE?err}
… 変数VARIABLE
が設定されていない場合は、エラーメッセージとしてerr
を出力して終了する
ネストも可能なようです。
${VARIABLE:-${FOO}}
${VARIABLE?$FOO}
${VARIABLE:-${FOO:-default}}
${VARIABLE/foo/bar}
といった拡張はサポートしていないそうです。
$
自体を文字として使いたい場合は、$$
とするようです。
You can use a $$ (double-dollar sign) when your configuration needs a literal dollar sign.
また、変数が定義されておらず、デフォルト値もない場合は空の文字列を設定し、ユーザーに警告するようです。
If the Compose implementation can’t resolve a substituted variable and no default value is defined, it MUST warn the user and substitute the variable with an empty string.
というわけで、ちょっと試してみましょう。
お題
MinIOのDockerイメージを使う時に、タグの指定とコンソールポートを変数で指定するようにしてみましょう。
雛形
まずは、以下からスタートしましょう。
compose.yaml
services: minio: image: minio/minio:RELEASE.2023-02-17T17-52-43Z ports: - 9000:9000 - 9001:9001 command: server /data --console-address ":9001"
起動。
$ docker compose up
この時のバージョンやコンソールポートの情報。
xxxxx-minio-1 | MinIO Object Storage Server xxxxx-minio-1 | Copyright: 2015-2023 MinIO, Inc. xxxxx-minio-1 | License: GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html> xxxxx-minio-1 | Version: RELEASE.2023-02-17T17-52-43Z (go1.19.6 linux/amd64) xxxxx-minio-1 | xxxxx-minio-1 | Status: 1 Online, 0 Offline. xxxxx-minio-1 | API: http://172.19.0.2:9000 http://127.0.0.1:9000 xxxxx-minio-1 | Console: http://172.19.0.2:9001 http://127.0.0.1:9001
変数を参照する
では、変数を参照するようにしてみましょう。
以下のように変更。
compose.yaml
services: minio: image: minio/minio:${MINIO_TAG} ports: - 9000:9000 - ${MINIO_CONSOLE_PORT}:${MINIO_CONSOLE_PORT} command: server /data --console-address ":${MINIO_CONSOLE_PORT}"
タグをMINIO_TAG
で、コンソールポートをMINIO_CONSOLE_PORT
で指定するようにしています。
このまま変数は指定せずに起動すると
$ docker compose up
起動はするものの、ドキュメント通り変数が解決できないので、空の文字列として扱うことが出力されます。
WARN[0000] The "MINIO_TAG" variable is not set. Defaulting to a blank string. WARN[0000] The "MINIO_CONSOLE_PORT" variable is not set. Defaulting to a blank string. WARN[0000] The "MINIO_CONSOLE_PORT" variable is not set. Defaulting to a blank string. WARN[0000] The "MINIO_CONSOLE_PORT" variable is not set. Defaulting to a blank string.
今回の場合は、ports
も変数化したので解決できずに起動に失敗します。
* error decoding 'Ports': No port specified: :<empty>
というわけで、変数を与えて起動してみます。
※export
してもよいです
$ MINIO_TAG=RELEASE.2023-02-10T18-48-39Z MINIO_CONSOLE_PORT=9003 docker compose up
使用するタグはひとつ古いバージョンにして、ポートは9003にしてみました。
xxxxx-minio-1 | MinIO Object Storage Server xxxxx-minio-1 | Copyright: 2015-2023 MinIO, Inc. xxxxx-minio-1 | License: GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html> xxxxx-minio-1 | Version: RELEASE.2023-02-10T18-48-39Z (go1.19.4 linux/amd64) xxxxx-minio-1 | xxxxx-minio-1 | Status: 1 Online, 0 Offline. xxxxx-minio-1 | API: http://172.19.0.2:9000 http://127.0.0.1:9000 xxxxx-minio-1 | Console: http://172.19.0.2:9003 http://127.0.0.1:9003
反映されているようです。
ローカルにバインドされているポートも変わっていますね。
$ MINIO_TAG=RELEASE.2023-02-10T18-48-39Z MINIO_CONSOLE_PORT=9003 docker compose ps NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS xxxxx-minio-1 minio/minio:RELEASE.2023-02-10T18-48-39Z "/usr/bin/docker-ent…" minio 2 minutes ago Up 2 minutes 0.0.0.0:9000->9000/tcp, :::9000->9000/tcp, 0.0.0.0:9003->9003/tcp, :::9003->9003/tcp
この時、変数展開した結果としてどのように解釈されるかは、docker compose convert
で見れるようです。
$ MINIO_TAG=RELEASE.2023-02-10T18-48-39Z MINIO_CONSOLE_PORT=9003 docker compose convert name: xxxxx services: minio: command: - server - /data - --console-address - :9003 image: minio/minio:RELEASE.2023-02-10T18-48-39Z networks: default: null ports: - mode: ingress target: 9000 published: "9000" protocol: tcp - mode: ingress target: 9003 published: "9003" protocol: tcp networks: default: name: xxxxx_default_default
変数を指定していない場合にエラーにする
次は、変数を指定していない場合にエラーにしてみましょう。
compose.yaml
services: minio: image: minio/minio:${MINIO_TAG?missing tag} ports: - 9000:9000 - ${MINIO_CONSOLE_PORT?missing console port}:${MINIO_CONSOLE_PORT?missing console port} command: server /data --console-address ":${MINIO_CONSOLE_PORT?missing console port}"
特になにも指定せずに起動すると
$ docker compose up
MINIO_TAG
がないとエラーになりました。
invalid interpolation format for services.minio.image. You may need to escape any $ with another $. required variable MINIO_TAG is missing a value: missing tag
MINIO_TAG
だけ指定すると、次はMINIO_CONSOLE_PORT
がないと言われます。
$ MINIO_TAG=RELEASE.2023-02-10T18-48-39Z docker compose up invalid interpolation format for services.minio.ports.[]. You may need to escape any $ with another $. required variable MINIO_CONSOLE_PORT is missing a value: missing console port
デフォルト値を指定する
最後に、デフォルト値を指定してみます。
compose.yaml
services: minio: image: minio/minio:${MINIO_TAG:-RELEASE.2023-02-17T17-52-43Z} ports: - 9000:9000 - ${MINIO_CONSOLE_PORT:-9001}:${MINIO_CONSOLE_PORT:-9001} command: server /data --console-address ":${MINIO_CONSOLE_PORT:-9001}"
特になにも指定せずに起動すると
$ docker compose up
デフォルト値として指定した値が使われます。
xxxxx-minio-1 | MinIO Object Storage Server xxxxx-minio-1 | Copyright: 2015-2023 MinIO, Inc. xxxxx-minio-1 | License: GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html> xxxxx-minio-1 | Version: RELEASE.2023-02-17T17-52-43Z (go1.19.6 linux/amd64) xxxxx-minio-1 | xxxxx-minio-1 | Status: 1 Online, 0 Offline. xxxxx-minio-1 | API: http://172.19.0.2:9000 http://127.0.0.1:9000 xxxxx-minio-1 | Console: http://172.19.0.2:9001 http://127.0.0.1:9001
変数を指定すると
$ MINIO_TAG=RELEASE.2023-02-10T18-48-39Z MINIO_CONSOLE_PORT=9003 docker compose up
その値が使われます。
xxxxx-minio-1 | MinIO Object Storage Server xxxxx-minio-1 | Copyright: 2015-2023 MinIO, Inc. xxxxx-minio-1 | License: GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html> xxxxx-minio-1 | Version: RELEASE.2023-02-10T18-48-39Z (go1.19.4 linux/amd64) xxxxx-minio-1 | xxxxx-minio-1 | Status: 1 Online, 0 Offline. xxxxx-minio-1 | API: http://172.19.0.2:9000 http://127.0.0.1:9000 xxxxx-minio-1 | Console: http://172.19.0.2:9003 http://127.0.0.1:9003
docker compose convert
の結果。
変数を指定しない場合。
$ docker compose convert name: xxxxx_default services: minio: command: - server - /data - --console-address - :9001 image: minio/minio:RELEASE.2023-02-17T17-52-43Z networks: default: null ports: - mode: ingress target: 9000 published: "9000" protocol: tcp - mode: ingress target: 9001 published: "9001" protocol: tcp networks: default: name: xxxxx_default
変数を指定した場合。
$ MINIO_TAG=RELEASE.2023-02-10T18-48-39Z MINIO_CONSOLE_PORT=9003 docker compose convert name: xxxxx services: minio: command: - server - /data - --console-address - :9003 image: minio/minio:RELEASE.2023-02-10T18-48-39Z networks: default: null ports: - mode: ingress target: 9000 published: "9000" protocol: tcp - mode: ingress target: 9003 published: "9003" protocol: tcp networks: default: name: xxxxx_default
こんなところでしょうか。
もう少し例を
先日、こんなエントリーを書きました。
Docker Composeで、コンテナの起動時に初期処理をしたい - CLOVER🍀
ここで指定していたクレデンシャルを、変数で設定するようにしてみましょう。
こんな感じで。
compose.yaml
services: minio: image: minio/minio:RELEASE.2023-02-17T17-52-43Z ports: - 9000:9000 - 9001:9001 command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: ${MY_MINIO_ROOT_USER:-defaultminioadmin} MINIO_ROOT_PASSWORD: ${MY_MINIO_ROOT_PASSWORD:-defaultminioadmin} minio-setup: image: minio/mc:RELEASE.2023-02-16T19-20-11Z restart: "no" depends_on: - minio entrypoint: [] command: >- bash -c 'sleep 3 \ && mc alias set myminio http://minio:9000 ${MY_MINIO_ROOT_USER:-defaultminioadmin} ${MY_MINIO_ROOT_PASSWORD:-defaultminioadmin} \ && mc mb myminio/my-bucket \ && echo "minio setup complete"'
なにも指定しないとdefaultminioadmin
という値をクレデンシャルとして使い、設定する場合はMY_MINIO_ROOT_USER
と
MY_MINIO_ROOT_PASSWORD
という変数を使うことにします。
environment: MINIO_ROOT_USER: ${MY_MINIO_ROOT_USER:-defaultminioadmin} MINIO_ROOT_PASSWORD: ${MY_MINIO_ROOT_PASSWORD:-defaultminioadmin}
起動時にバケットも作成するためのコンテナも定義していますが、こちらはcommand
内で参照するようにしています。
entrypoint: [] command: >- bash -c 'sleep 3 \ && mc alias set myminio http://minio:9000 ${MY_MINIO_ROOT_USER:-defaultminioadmin} ${MY_MINIO_ROOT_PASSWORD:-defaultminioadmin} \ && mc mb myminio/my-bucket \ && echo "minio setup complete"'
まずは変数に設定せずに起動。
$ docker compose up
確認。
$ export AWS_ACCESS_KEY_ID=defaultminioadmin $ export AWS_SECRET_ACCESS_KEY=defaultminioadmin $ export AWS_DEFAULT_REGION=us-east-1 $ aws s3 ls --endpoint-url http://localhost:9000 2023-02-19 21:26:42 my-bucket
OKですね。
なお、MinIOの本来のデフォルトのクレデンシャルはminioadmin
なので、この値を指定するとクレデンシャルでエラーになります。
$ export AWS_ACCESS_KEY_ID=minioadmin $ export AWS_SECRET_ACCESS_KEY=minioadmin $ export AWS_DEFAULT_REGION=us-east-1 $ aws s3 ls --endpoint-url http://localhost:9000 An error occurred (InvalidAccessKeyId) when calling the ListBuckets operation: The Access Key Id you provided does not exist in our records.
docker compose convert
してみると、command
の中を含めて展開されているのがわかります。
$ docker compose convert name: xxxxx services: minio: command: - server - /data - --console-address - :9001 environment: MINIO_ROOT_PASSWORD: defaultminioadmin MINIO_ROOT_USER: defaultminioadmin image: minio/minio:RELEASE.2023-02-17T17-52-43Z networks: default: null ports: - mode: ingress target: 9000 published: "9000" protocol: tcp - mode: ingress target: 9001 published: "9001" protocol: tcp minio-setup: command: - bash - -c - |- sleep 3 \ && mc alias set myminio http://minio:9000 defaultminioadmin defaultminioadmin \ && mc mb myminio/my-bucket \ && echo "minio setup complete" depends_on: minio: condition: service_started entrypoint: [] image: minio/mc:RELEASE.2023-02-16T19-20-11Z networks: default: null restart: "no" networks: default: name: xxxxx_default
次は、変数を指定して起動してみます。
$ MY_MINIO_ROOT_USER=myminioadmin MY_MINIO_ROOT_PASSWORD=myminioadmin docker compose up
確認。
$ export AWS_ACCESS_KEY_ID=myminioadmin $ export AWS_SECRET_ACCESS_KEY=myminioadmin $ export AWS_DEFAULT_REGION=us-east-1 $ aws s3 ls --endpoint-url http://localhost:9000 2023-02-19 21:31:02 my-bucket
こちらもOKですね。
docker compose convert
の結果。
$ MY_MINIO_ROOT_USER=myminioadmin MY_MINIO_ROOT_PASSWORD=myminioadmin docker compose convert name: xxxxx services: minio: command: - server - /data - --console-address - :9001 environment: MINIO_ROOT_PASSWORD: myminioadmin MINIO_ROOT_USER: myminioadmin image: minio/minio:RELEASE.2023-02-17T17-52-43Z networks: default: null ports: - mode: ingress target: 9000 published: "9000" protocol: tcp - mode: ingress target: 9001 published: "9001" protocol: tcp minio-setup: command: - bash - -c - |- sleep 3 \ && mc alias set myminio http://minio:9000 myminioadmin myminioadmin \ && mc mb myminio/my-bucket \ && echo "minio setup complete" depends_on: minio: condition: service_started entrypoint: [] image: minio/mc:RELEASE.2023-02-16T19-20-11Z networks: default: null restart: "no" networks: default: name: xxxxx_default
こんなところでしょうか。
まとめ
Docker Composeの構成ファイル内で、環境変数を参照してみました。
構文やデフォルト値、値が設定されていない時の振る舞いなど、この機会に見直せて良かったかなと思います。
覚えておくと便利そうなので、使えそうなところでは使っていきましょう。