なにもわからない

気分で技術系の雑記を書きます

docker-compose の ${VAR:-default} 記法と .env で開発&本番環境を設計する

docker-compose.yml で、シェルでよくある ${VAR:-default} 記法が使えるのがあまり知られていないようだったので書きます。 www.debuntu.org

サンプルプロジェクトはこちらです github.com


PHP が動く Dockerfile と

# Dockerfile
FROM docker.io/php:7.2.29-cli

それを使う docker-compose.yml を用意します。今回はサービスは1つです。

# docker-compose.yml
version: "3.7"
services:
  php:
    build:
      context: .
    working_dir: /app
    volumes:
      - .:/app

動かすプログラム src/main.php環境変数 $MESSAGE を出力するだけです。

<?php

echo $_ENV["MESSAGE"] . PHP_EOL;

Dockerfile で ENV MESSAGE "hello" として

FROM docker.io/php:7.2.29-cli

ENV MESSAGE "hello"

これを実行すると、ENV した hello が出力されます。

$ docker-compose run --rm php php src/main.php
hello

これは環境変数なので当然シェルも同様です

$ docker-compose run --rm php sh -c 'echo $MESSAGE'
hello

docker-compose.yml で environment に表題の MESSAGE: ${MESSAGE:-holla} とすると

--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -3,6 +3,8 @@ services:
   php:
     build:
       context: .
+    environment:
+      MESSAGE: ${MESSAGE:-holla}
     working_dir: /app
     volumes:
       - .:/app

デフォルト値の holla が出力されます

$ docker-compose run --rm php php src/main.php
holla

-e を指定するとこちらが優先されます

$ docker-compose run --help | grep -- "-e KEY=VAL"
    run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] [-l KEY=VALUE...]
    -e KEY=VAL            Set an environment variable (can be used multiple times)
$ docker-compose run --rm -e MESSAGE=ciao php php src/main.php
ciao

.env を docker-compose が勝手に読むので、状態を .env に保持しておけます

$ echo "MESSAGE=haisai" > .env

$ docker-compose run --rm php php src/main.php
haisai

さて、ここで開発用にgitやvimを入れたくなった気持ちになってみます。

--- a/Dockerfile
+++ b/Dockerfile
@@ -1,3 +1,10 @@
 FROM docker.io/php:7.2.29-cli

+RUN apt-get update && \
+    apt-get install -y \
+      vim \
+      git \
+      && \
+    apt-get clean
+
 ENV MESSAGE "hello"

本番稼働時は要らないですよね

$ docker-compose build
Building php
Step 1/4 : FROM docker.io/php:7.2.29-cli
 ---> e7d2518687da
Step 2/4 : ENV MESSAGE "hello"
 ---> Using cache
 ---> 51c63dafa792

Step 3/4 : FROM production-pseudo AS development
 ---> 51c63dafa792
Step 4/4 : RUN apt-get update &&     apt-get install -y       vim       git       &&     apt-get clean
 ---> Using cache
 ---> 964a4048e6ab

そんなときは target build stages の出番です。 production-pseudo はまだ本番稼働していない疑似本番環境を表す語として使っています。

FROM docker.io/php:7.2.29-cli AS production-pseudo

RUN # ここに本番で要るものだけインストールする

# --

FROM production-pseudo AS development

RUN apt-get update && \
    apt-get install -y \
      vim \
      git \
      && \
    apt-get clean

これで TARGET=production-pseudo 時はvimやgitをインストールしなくなりました

$ docker-compose build
Building php
Step 1/2 : FROM docker.io/php:7.2.29-cli AS production-pseudo
 ---> e7d2518687da
Step 2/2 : ENV MESSAGE "hello"
 ---> Using cache
 ---> 51c63dafa792

Successfully built 51c63dafa792
Successfully tagged docker-compose-variable_php:latest

TARGET=development 時はインストールされます

$ echo "TARGET=development" > .env

$ docker-compose build
Building php
Step 1/4 : FROM docker.io/php:7.2.29-cli AS production-pseudo
 ---> e7d2518687da
Step 2/4 : ENV MESSAGE "hello"
 ---> Using cache
 ---> 51c63dafa792

Step 3/4 : FROM production-pseudo AS development
 ---> 51c63dafa792
Step 4/4 : RUN apt-get update &&     apt-get install -y       vim       git       &&     apt-get clean
 ---> Running in 36bcf0f189fe

$ docker-compose run --rm php which git
/usr/bin/git

これに VSCode の Remote Containers 拡張用を合わせて使うと相性が良いです。 FROM development AS debug として XDebug をインストールする、といった使い方もできます(それなりに重いので)。

が、話が長くなるのでこれについてはまた次回書きます。


ちなみに今回、 .env を作ったりする docker.mk はこの様になりました

.PHONY: install install-dev development clean

TARGET := production-pseudo

install: \
   .env \
   build

install-dev: \
   development \
   install

development:
  $(eval TARGET := development)

.env:
  touch $@
  echo "TARGET=$(TARGET)" >> $@

build:
  docker-compose build

clean:
  rm -rf .env