Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連以外

docker-compose.ymlの中で値を使い回す方法

小ネタで恐縮です。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の機能である程度実現できることがわかりました。「アンカー/エイリアス」機能を用います。

「アンカー/エイリアス」機能自体は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自体の機能ではないので、そのつもりで使うことにします。

関連記事

クジラに乗ったRuby: Evil Martians流Docker+Ruby/Rails開発環境構築(翻訳)

docker-composeを便利にするツール「dip」を使ってみた


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。