これは、なにをしたくて書いたもの?
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の構成ファイル内で、環境変数を参照してみました。
構文やデフォルト値、値が設定されていない時の振る舞いなど、この機会に見直せて良かったかなと思います。
覚えておくと便利そうなので、使えそうなところでは使っていきましょう。