読者です 読者をやめる 読者になる 読者になる

しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

App Service on Linux のカスタム Docker イメージ機能を使って nginx + php-fpm な環境を作る

Azure Web Apps PHP

最近は Windows Containers じゃない Docker Container を弄っていたので、勢いで App Service on Linux 向けに nginx + php-fpm という鉄板な構成でカスタムランタイムを作成しました。

既に shibayan/nginx-php-fpm というイメージ名で Docker Hub に上げてあるので、それを使うとコンテンツをディレクトリにコピーするだけの Dockerfile を作れば動きます。

FROM shibayan/nginx-php-fpm

COPY index.php /var/www/html/index.php

index.php にはお馴染みの phpinfo だけ書いておきました。

この Dockerfile をビルドして Docker Hub にプッシュし、App Service で設定すれば終わりです。

f:id:shiba-yan:20161224203205p:plain

実際に作成したイメージをデプロイしました。Server API が FPM になっているのが確認できました。

f:id:shiba-yan:20161224203605p:plain

これだけだと一瞬で終わってしまったので、App Service on Linux について最近調べていたことを簡単にまとめておこうかと思いました。後は作成したイメージについてもう少し説明を書きます。

アーキテクチャについて

そういえば App Service on Linux が Docker Container に対応した話は書いてなかった気がします。アーキテクチャについては公式情報がゼロですが、以下の記事がまとまっていると思います。

Nazim 氏がコメントを書き込んでいるので、大体当たりのようです。軽く基本的な情報をまとめます。

  • ホスト OS は Ubuntu 16.04
  • ビルトインイメージは Debian 8 ベース (debian:jessie)
  • www と scm は別のコンテナで動作している
    • ランタイムに .NET Core を指定しても Kudu で dotnet コマンドが叩けない理由がこれ
  • /home は www と scm 共通でマウントされている

OS が Ubuntu と Debian のどちらかという話がありましたが、両方というのが正解。他にも今は Docker のイメージを変更すると 503 になったりしますが、今後アップデートで対応されるとかなんとか。

docker コマンドを Kudu から見えるようにすると、コンテナ間のアイソレーションで問題になりそうなので、カスタムデプロイスクリプトで docker build というのは非常に難しそうです。

カスタムイメージを作る

アーキテクチャの話はこれぐらいにして、実際に nginx と php-fpm を使う Docker イメージを作成してみます。調べると良く出てくるのが nginx と php-fpm を別コンテナにする方法ですが、App Service on Linux では Docker Compose は使えないので 1 つのコンテナで両方動かすことにします。

ベースとなるイメージは公式の php-fpm を使いました。確か Debian ベースです。

FROM php:7.0.6-fpm

# Install nginx
RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 \
    && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list \
    && apt-get update \
    && apt-get install -y nginx --no-install-recommends

# Install PHP extensions
RUN apt-get update \
    && apt-get install -y libpng12-dev \
         libjpeg-dev \
         libpq-dev \
         libmcrypt-dev \
         libldap2-dev \
         libldb-dev \
         libicu-dev \
         libgmp-dev \
    && ln -s /usr/lib/x86_64-linux-gnu/libldap.so /usr/lib/libldap.so \
    && ln -s /usr/lib/x86_64-linux-gnu/liblber.so /usr/lib/liblber.so \
    && ln -s /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h \
    && rm -rf /var/lib/apt/lists/* \
    && docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr \
    && docker-php-ext-install gd \
         mysqli \
         opcache \
         pdo \
         pdo_mysql \
         pdo_pgsql \
         pgsql \
         ldap \
         intl \
         mcrypt \
         gmp \
         zip \
         bcmath \
         mbstring \
         pcntl

# Install Supervisor
RUN apt-get update \
    && apt-get install -y supervisor \
    && mkdir -p /var/log/supervisor

# Add configuration
COPY default.conf /etc/nginx/conf.d/default.conf
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

EXPOSE 80

CMD ["/usr/bin/supervisord"]

ダラダラと長いですが、やっていることは nginx / php extensions / supervisor のインストールと設定ファイルのコピーだけです。PHP Extension のインストールは公式の Dockerfile を参考にしました。

nginx の設定ファイルは非常にシンプルです。やっていることは FastCGI の設定と REMOTE_ADDR を正しくするための設定ぐらいです。ちゃんと 80 番ポートをリッスンするようにしておきます。

server {
    listen 80;
    server_name _;
    root /var/www/html;
    index index.php index.html index.htm;
    charset utf-8;

    set_real_ip_from 10.0.0.0/8;
    set_real_ip_from 172.17.0.0/16;
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        fastcgi_pass  127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include       fastcgi_params;
    }
}

公式の php-fpm イメージをベースに作っているので、9000 番ポートに FastCGI のリクエストを流し込みます。この辺りは特に代わり映えのしない、ありがちな設定です。

最後に Supervisor の設定ファイルです。nginx と php-fpm を立ち上げているだけです。

[supervisord]
nodaemon=true

[program:php-fpm]
command=php-fpm
priority=10

[program:nginx]
command=nginx -g "daemon off;"
priority=5

とりあえず優先順位をつけて php-fpm が先に起動するようにしました。これで docker build すると nginx と php-fpm のベースイメージが完成するので、あとはコンテンツを追加したイメージを作ります。

本来なら App Service のビルトインイメージと同じように /home/site/wwwroot のファイルを使う方法もありますが、今はちょっとしたバグがあるので紹介は止めておきました。直ったら書きます。