Docker Composeファイル内でDRYを実践

media thumbnail

GizTechPro事業部の伊藤太樹です。
普段は参画先の現場にて、AWSクラウドを使用したインフラストラクチャの設計・構築や運用保守を担当しています。

昔からターミナル操作や仮想環境、サーバーの構築といったあたりの作業や技術が好みで触れ続けていたら
いつの間にかバックエンドエンジニアから、AWSインフラエンジニアに転生していたという経歴を持っています。

今の現場でも開発チームが使用する開発環境の構築や
LocalStackを使用したローカルでのAWS構成の検証等、様々なところでDockerに触れる機会があります。

今回は、Docker Composeを使用する場合のコンテナ設定定義ファイル docker-compose.yml (compose.yml) にて
セクションを変数化して使いまわしてDRYに記述する方法について紹介していきます。

前提・対象とする読者

DockerやDocker Composeを普段から使用される方、あるいは使用する機会が少なくても興味があるという方をターゲットとして記事を執筆しています。

DRYの原則

Don’t Repeat Yourself の頭文字を取ってDRY (ドライ)の原則といいます。
実装において繰り返しを避けましょうという意味ですが、ただただ繰り返しを避けてコードを共通化をすれば良いというのは安直で、扱う情報の重複を避けるというのが重要です。

サンプル設定ファイル

今回は下記のような compose.yml を用意しました。

version: "3.8"

services:
  nginx:
    image: nginx:latest
    environment:
      TZ: Asia/Tokyo
  php:
    image: php:8.2
    environment:
      TZ: Asia/Tokyo

  db:
    image: mysql:8.0
    environment:
      TZ: Asia/Tokyo
  • クライアントからのリクエストを受け付けるWebサーバとしての Nginxコンテナ
  • Nginxコンテナで受け付けたリクエストを転送して、PHPを実行するアプリケーションサーバとしての PHPコンテナ
  • PHPコンテナ上のアプリケーションから使用するDBサーバとしての MySQLコンテナ

の3つのコンテナを定義しています。

3つのコンテナでは
タイムゾーンを日本時間に設定するための環境変数 Asia/Tokyo が共通する設定となっています。

Asia/Tokyo のタイムゾーン設定をコンテナの数だけ繰り返し記述しており
全体のタイムゾーンを UTC に変更したくなった場合に、一つ一つ変更する必要が生じる作りとなってしまっているあたり保守性に欠けてしまいますね。

x-var

Docker Composeの設定ファイルでは、x- というプレフィックスを付けて定義したセクションは
他のセクションの中で使えるように変数化されるという仕様があります。

先程のサンプル compose.yml を下記のように書き換えてみます。

version: "3.8"

x-var: &TIME_ZONE
  Asia/Tokyo

services:
  nginx:
    image: nginx:latest
    environment:
      TZ: *TIME_ZONE

  php:
    image: php:8.2
    environment:
      TZ: *TIME_ZONE

  db:
    image: mysql:8.0
    environment:
      TZ: *TIME_ZONE

x-var の箇所は、docker-compose updocker-compose downといったDocker Composeの設定定義ファイルを参照するコマンドを実行しても起動するコンテナとしては認識されません。

&TIME_ZONE という記述のように & を先頭に付けることで、& 後ろの TIME_ZONE という名前で変数を宣言することができます。
宣言した変数は、 *TIME_ZONE という記述のように * を先頭に付けることで、compose.yml 内の任意の場所で使用することができます。

コンテナ定義の数分、Asia/Tokyo のタイムゾーン環境変数を記述するよりも
全体の保守性としては向上したと言えますね。(タイムゾーンを分けたい場合はこの通りではありませんが)

x-セクション

もう一歩踏み込んで共通化してみましょう。

先程のようにたった一つ重複設定があったくらいでは、記述量も少ないので保守性が高くなったといっても
恩恵はそこまで大きく感じられないと思います。

ですが、もっと共通の設定が増えればどうでしょうか?

下記のように一つひとつ environment セクションに環境変数を記述していくというのは面倒と感じていただけると思います。

version: "3.8"

x-var: &TIME_ZONE
  Asia/Tokyo
x-var: &LANG
  ja_JP.UTF-8
x-var: &LC_ALL
  ja_JP.UTF-8

services:
  nginx:
    image: nginx:latest
    environment:
      TZ: *TIME_ZONE
      LANG: *LANG
      LC_ALL: *LC_ALL

  php:
    image: php:8.2
    environment:
      TZ: *TIME_ZONE
      LANG: *LANG
      LC_ALL: *LC_ALL

  db:
    image: mysql:8.0
    environment:
      TZ: *TIME_ZONE
      LANG: *LANG
      LC_ALL: *LC_ALL

そこでもっと大規模に共通化する方法が、セクション自体の共通化です。

version: "3.8"

x-environments: &environments
  environment:
    TZ: Asia/Tokyo
    LANG: ja_JP.UTF-8
    LC_ALL: ja_JP.UTF-8

services:
  nginx:
    image: nginx:latest
    <<: *environments

  php:
    image: php:8.2
    <<: *environments

  db:
    image: mysql:8.0
    <<: *environments

x-で始まるセクションの定義内に、各コンテナサービスで定義していた environment プロパティ自体を含めてしまい
&environments という記述によって、environments の名前を付けて変数化します。

あとは、変数化したenvironmentセクションを注入したい箇所に
<<: *environments と記述することで変数の値が展開されます。

全体としてかなりすっきりして
コンテナ間で共通で使用する環境変数の管理がしやすくなることは一目でお分かりいただけると思います。

まとめ

Docker Composeコンテナ設定定義ファイル内では、 x- を上手く使うことで設定の共通化ができます。
そこそこ大規模なDocker Composeコンテナ設定定義ファイルを記述するようなケースがあれば、役に立つTipsかと思います。ぜひ活用してみてください。

少しでも開発にお困りの方は
相談しやすいスペシャリストにお問い合わせください

お問い合わせ
  1. breadcrumb-logo
  2. メディア
  3. Docker Composeファイル内でDRYを実践