小ネタで恐縮です。docker-composeは便利なのですが、docker-compose.ymlの中でローカル変数的に値を手軽に使い回す方法を知りたくなりました。
version: "3.4"
services:
app: &app
build:
context: .
dockerfile: ./.dockerdev/Dockerfile
args:
RUBY_VERSION: "2.7.0-slim-buster"
PG_MAJOR: "12"
NODE_MAJOR: "11"
YARN_VERSION: "1.19.1"
BUNDLER_VERSION: "2.0.2"
image: enno_docker:1.0.0
tmpfs:
- /tmp
# (略)
postgres:
image: postgres:12
volumes:
- .psqlrc:/root/.psqlrc:ro
- postgres:/var/lib/postgresql/data
- ./log:/root/log:cached
environment:
- PSQL_HISTFILE=/root/log/.psql_history
ports:
- 5432
env_file: .env
上のargs:
でPostgreSQLのバージョンをPG_MAJOR: "12"
と指定しますが、これはDocker側の環境変数にexportされてDockerfile側で参照する前提です(この場合はpsqlのビルドに使われます)。
このバージョン番号を、その下にあるPostgreSQLのDocker Hubイメージのバージョン指定image: postgres:12
にも使おうと思ってimage: postgres:{$PG_MAJOR}
などと書いてもエラーになります。
WARNING: The PG_MAJOR variable is not set. Defaulting to a blank string.
Creating network "enno_docker_default" with the default driver
ERROR: no such image: postgres:{}: invalid reference format
解決方法
またしてもStack Overflowですが、yamlの機能である程度実現できることがわかりました。「アンカー/エイリアス」機能を用います。
- Stack Overflow: Define local variable in docker-compose.yml? - Stack Overflow
「アンカー/エイリアス」機能自体はdocker-compose.ymlでも普通に使われていますが、ここでのポイントは以下のように「x-
で始まるキー」を書くことで、これでDocker Composeで無視されるようになります。そこに&アンカー名
を書くと、値を*アンカー名
でエイリアスとして参照できます。以下ではx-var
にしていますが、わかりやすい名前でよいと思います。
version: "3.4"
x-var: &APP_IMAGE_TAG
"my_app:1.0.0"
x-var: &RUBY_VERSION
"2.7.0-slim-buster"
x-var: &PG_MAJOR
12
x-var: &POSTGRES
"postgres:12"
x-var: &NODE_MAJOR
12
x-var: &YARN_VERSION
1.21.1
x-var: &BUNDLER_VERSION
2.1.2
services:
app: &app
build:
context: .
dockerfile: ./.dockerdev/Dockerfile
args:
RUBY_VERSION: *RUBY_VERSION
PG_MAJOR: *PG_MAJOR
NODE_MAJOR: *NODE_MAJOR
YARN_VERSION: *YARN_VERSION
BUNDLER_VERSION: *BUNDLER_VERSION
image: *APP_IMAGE_TAG
tmpfs:
- /tmp
# (略)
postgres:
image: *POSTGRES
volumes:
- .psqlrc:/root/.psqlrc:ro
- postgres:/var/lib/postgresql/data
- ./log:/root/log:cached
environment:
- PSQL_HISTFILE=/root/log/.psql_history
ports:
- 5432
env_file: .env
参考: アンカーとエイリアス -- プログラマーのための YAML 入門 (初級編)
YAML では、データに「&name」で印をつけ、「*name」で参照することができます (C 言語におけるアドレスやポインタと同じ表記です)。前者をアンカー (Anchor)、後者をエイリアス (Alias) といいます。
なお上の例でもわかるように、シェルの環境変数みたいに値を結合したり一部を置き換えたりすることはできませんでした。本当はimage: postgres:{$PG_MAJOR}
のように書きたかったのですがダメでした😢。
わかってしまえばどうということはありませんでしたが、それでも変動する可能性のある値をdocker-compose.ymlの冒頭にまとめられたので、バージョン更新のときに見落としにくくなったと思います(つか前は見落としました)。docker-compose自体の機能ではないので、そのつもりで使うことにします。
おたより発掘
"x-" で無視されるようになるの知らなかった / “docker-compose.ymlの中で値を使い回す方法|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社” https://t.co/pSOdyhHtjT
— sue445 (@sue445) August 27, 2020