Docker Composeファイル内でDRYを実践
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 up
や docker-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かと思います。ぜひ活用してみてください。