結論
https://qiita.com/t_n/items/203cd3593427a35f7ed7 のように、 shell
の if 〜 then 〜 fi
を使う。
ただし、記事にある通りで、
これはするべきではないです
と思います。が、今の所、この方法しか思いつかなかった。。というメモ。
具体例:
# ..snip..
COPY ./docker/workspace/usr/local/etc/php/conf.d/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini
RUN if [ "${PHP_XDEBUG_INSTALL}" = "true" ]; then pecl install xdebug ;fi
RUN if [ ! "${PHP_XDEBUG_INSTALL}" = "true" ]; then rm -rf /usr/local/etc/php/conf.d/xdebug.ini ;fi
# ..snip..
実現したかったこと
- Dockerfile を使って、 PHP の動くコンテナを作成する
- ある条件(ARG で与えるパラメーター)に従って必要ならば xdebug をインストール
- 具体的には、
PHP_XDEBUG_INSTALL
が"true"
なら xdebug をインストール -
"false"
なら xdebug をインストールせず、かつ、xdebug.so
の読み込みもしない
- 具体的には、
- Dockerfile 単独でビルドするときはパラメーターを与えないことで
PHP_XDEBUG_INSTALL
の値を自動的に"false"
とする - docker-compose でビルドするときは
PHP_XDEBUG_INSTALL
の値をdocker-compose.yml
に記載して"true"
となるようにする - かつ、
xdebug
の各種パラメーターを ARG で与えるようにしたい
なんで、こんな事を実現したかったか
- 作成した Docker Image を Production でも使えるようにしたかった
- かつ、 Production では xdebug は入れたくなかった
- でも、開発環境では、可能な限り Production と親しい状態に保ちたかった(xdebug は入れておきたかった)
- でも、 docker for mac 使ってる人もいるかもだし、個人的には docker-machine 使いたいしで、特に
xdebug.remote_host
の値とか各開発者の環境に依存するので、可能なら外部でコントロールしたい1 - echo 使って xdebug.ini 出力しても良いけど、 Dockerfile 見にくいの嫌やし…
- なにより、あまり何も考えずにコマンド叩けば済むようにしたかった
どうやって実現したか
前提:
- ベースイメージは
php:7.2-fpm-alpine3.7
を使ってます
シンプルに php:7.2-fpm-alpine3.7
で xdebug をインストールして有効化する方法
# ..snip..
RUN pecl install xdebug
RUN docker-php-ext-enable xdebug
# ..snip..
pecl
でインストールして docker-php-ext-enable
で有効にする。
これで、 /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
に以下のファイルが配置される。
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20170718/xdebug.so
docker-php-ext-enable xdebug
を実行すると /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
が用意される。(便利やねー)
Dockerfile
で ARG を使う かつ デフォルト値を持たせる
# ..snip..
ARG PHP_XDEBUG_INSTALL="false"
# ..snip..
ARG
で宣言してるので docker build
時に --build-arg <KEY>=<VAL>
みたいに指定できるようになる。
ARG PHP_XDEBUG_INSTALL="false"
としてデフォルト値である "false"
を渡してるので、宣言しない場合は自動的に "false"
となる。
PHP_XDEBUG_INSTALL
を "true"
としたければ、 --build-arg PHP_XDEBUG_INSTALL=true
としたら大丈夫。(の、はず。。)
docker-compose.yml
で ARG を上書きする
# ..snip..
workspace:
build:
context: ./
dockerfile: docker/workspace/Dockerfile
args:
PHP_XDEBUG_INSTALL: "true"
# ..snip..
上記のように、 args
で指定する。
この例であれば、 PHP_XDEBUG_INSTALL
は "true"
となる。
なお、 ARG は http://docs.docker.jp/engine/reference/builder.html#arg にある通り、ビルド時のみ有効な値となる。
あまり考えずにコマンドを叩けばOKになった!
これで、何も考えずに docker build
したら PHP_XDEBUG_INSTALL
は "false"
, docker-compose build
したら PHP_XDEBUG_INSTALL
は "true"
という状況が実現できた。
ARG の値を用いて条件分岐する
Dockerfile には if 文が無い。
ので、冒頭の記事のように RUN 命令と shell
を組み合わせて実現する。
PHP_XDEBUG_INSTALL
が "true"
の時だけ xdebug
をインストールして有効化したいならば、以下のように書けば事が足りる。
# ..snip..
RUN if [ "${PHP_XDEBUG_INSTALL}" = "true" ]; then \
pecl install xdebug \
&& docker-php-ext-enable xdebug \
;fi
# ..snip..
ただし、これではデフォルトの /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
が出来上がるだけで、
でも、 docker for mac 使ってる人もいるかもだし、個人的には docker-machine 使いたいしで、特に
xdebug.remote_host
の値とか各開発者の環境に依存するので、外部でコントロールしたい
これが実現できない。
echo で実現してみる
# ..snip..
ARG PHP_XDEBUG_REMOTE_HOST="192.168.99.1"
# ..snip..
RUN if [ "${PHP_XDEBUG_INSTALL}" = "true" ]; then \
pecl install xdebug \
&& docker-php-ext-enable xdebug \
&& echo "xdebug.remote_host=${PHP_XDEBUG_REMOTE_HOST}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
;fi
# ..snip..
一応、これで実現できる。
でも、 xdebug の他のパラメーターもここに書くの?なんか嫌じゃない?(増えてきたら)見にくいし…
というわけで、どうするか
- 事前に
xdebug.ini
を COPY で/usr/local/etc/php/conf.d/xdebug.ini
へ転送する- そのため、
docker-php-ext-enable xdebug
は行わない
- そのため、
-
xdebug.ini
は、変数を使って初期化できるように書いておく -
PHP_XDEBUG_INSTALL
が"true"
以外なら- COPY した
/usr/local/etc/php/conf.d/xdebug.ini
をrm -rf /usr/local/etc/php/conf.d/xdebug.ini
で削除する
- COPY した
例えば、 xdebug.ini は以下のような感じにデフォルト値設定しておくとか。
[xdebug]
zend_extension=xdebug.so
xdebug.default_enable=${PHP_XDEBUG_DEFAULT_ENABLE}
xdebug.remote_enable=${PHP_XDEBUG_REMOTE_ENABLE}
xdebug.remote_port=${PHP_XDEBUG_REMOTE_PORT}
xdebug.remote_host=${PHP_XDEBUG_REMOTE_HOST}
xdebug.remote_autostart=${PHP_XDEBUG_REMOTE_AUTO_START}
xdebug.remote_connect_back=${PHP_XDEBUG_REMOTE_CONNECT_BACK}
xdebug.idekey=${PHP_XDEBUG_IDEKEY}
; profiler
xdebug.profiler_enable = ${PHP_XDEBUG_PROFILER_ENABLE}
xdebug.profiler_output_dir = ${PHP_XDEBUG_PROFILER_OUTPUT_DIR}
で、 Dockerfile はと言うと以下のような感じで用意する。
# ..snip..
ARG PHP_XDEBUG_DEFAULT_ENABLE="Off"
ARG PHP_XDEBUG_REMOTE_ENABLE="On"
ARG PHP_XDEBUG_REMOTE_PORT="9001"
ARG PHP_XDEBUG_REMOTE_HOST="127.0.0.99"
ARG PHP_XDEBUG_REMOTE_AUTO_START="Off"
ARG PHP_XDEBUG_REMOTE_CONNECT_BACK="Off"
ARG PHP_XDEBUG_IDEKEY="PHPSTORM"
ARG PHP_XDEBUG_PROFILER_ENABLE="Off"
ARG PHP_XDEBUG_PROFILER_OUTPUT_DIR="/tmp"
ENV PHP_XDEBUG_DEFAULT_ENABLE ${PHP_XDEBUG_DEFAULT_ENABLE}
ENV PHP_XDEBUG_REMOTE_ENABLE ${PHP_XDEBUG_REMOTE_ENABLE}
ENV PHP_XDEBUG_REMOTE_PORT ${PHP_XDEBUG_REMOTE_PORT}
ENV PHP_XDEBUG_REMOTE_HOST ${PHP_XDEBUG_REMOTE_HOST}
ENV PHP_XDEBUG_REMOTE_AUTO_START ${PHP_XDEBUG_REMOTE_AUTO_START}
ENV PHP_XDEBUG_REMOTE_CONNECT_BACK ${PHP_XDEBUG_REMOTE_CONNECT_BACK}
ENV PHP_XDEBUG_IDEKEY ${PHP_XDEBUG_IDEKEY}
ENV PHP_XDEBUG_PROFILER_ENABLE ${PHP_XDEBUG_PROFILER_ENABLE}
ENV PHP_XDEBUG_PROFILER_OUTPUT_DIR ${PHP_XDEBUG_PROFILER_OUTPUT_DIR}
# ..snip..
## PHP_XDEBUG_INSTALL の値に関わらずとりあえず事前に COPY
COPY ./docker/workspace/usr/local/etc/php/conf.d/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini
## PHP_XDEBUG_INSTALL が true なら pecl install xdebug するけど、 docker-php-ext-enable xdebug は行わない
RUN if [ "${PHP_XDEBUG_INSTALL}" = "true" ]; then pecl install xdebug ;fi
## PHP_XDEBUG_INSTALL が true ではないなら、 COPY した /usr/local/etc/php/conf.d/xdebug.ini を rm する
RUN if [ ! "${PHP_XDEBUG_INSTALL}" = "true" ]; then rm -rf /usr/local/etc/php/conf.d/xdebug.ini ;fi
# ..snip..
当然ながら、 RUN if 〜 then 〜 fi
の中で COPY 命令は使えない(RUN 命令なので)ので、事前に COPY して、不要ならば削除する方針とした。
さいごに
作業した記憶から書き起こしてるのと、実際に自分の書いたコードとは一部違うので、誤植とか書き間違いがあったらごめんなさい。
他に、もっと効率的に書けるよ!とか、こんなの Docker way とは違うよ!みたいな事、あるかと思います!教えてくださいm(_ _)m
-
docker-compose.yml
を gitignore に入れて、docker-compose.yml.template
とかをリポジトリに入れて各人でローカルのdocker-compose.yml
を編集してもらう方法とか、.env
を使う方法(その場合はARG
でのコントロールじゃなくなるかも。)とか、色々あるけどとりあえず割愛。 ↩