LoginSignup
6
5

More than 5 years have passed since last update.

Dockerfile の ARG を使って xdebug をインストールしたり,しなかったり した方法のメモ

Last updated at Posted at 2018-08-15

結論

https://qiita.com/t_n/items/203cd3593427a35f7ed7 のように、 shellif 〜 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 に以下のファイルが配置される。

/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 を上書きする

docker-compose.yml
# ..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.inirm -rf /usr/local/etc/php/conf.d/xdebug.ini で削除する

例えば、 xdebug.ini は以下のような感じにデフォルト値設定しておくとか。

/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



  1. docker-compose.yml を gitignore に入れて、 docker-compose.yml.template とかをリポジトリに入れて各人でローカルの docker-compose.yml を編集してもらう方法とか、 .env を使う方法(その場合は ARG でのコントロールじゃなくなるかも。)とか、色々あるけどとりあえず割愛。 

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5