Docker

周回遅れのDocker 2: Docker による PHP サーバ

More than 1 year has passed since last update.

https://registry.hub.docker.com/_/php/

Docker 公式の PHP イメージを使って Web サーバに相当するコンテナを作ってみる。今回のコンテナ例では立ち上げると phpinfo() を出力する PHP Web サーバを提供することとする。

また -v (--volume) オプションを使って、ローカルディスクの領域を Web サーバのドキュメントルートとしてマウントした際の挙動もあわせて確認する。

なお以下の例で実行している docker コマンドは、docker-machine で作られたホストに対して行っており、事前に docker-machine env による環境変数が設定済みの状態。


Apache + PHP


コンテナイメージの準備

まず PHP の phpinfo() を出力するファイルを用意。


public/info.php

<?php

phpinfo();

続けて image ビルドのための Dockerfile を用意。ここでは、 Apache モジュールが同梱された PHP コンテナイメージをベースとして使う。

あわせて、先ほどの PHP ファイルをコンテナイメージに同梱するよう COPY を使ってローカルファイルをコンテナに含めるようにする。コピー先は、ベースとなるコンテナが提供している仕様に基づくディレクトリとする。すなわち今回利用しているベースコンテナの php:apache の Apache がドキュメントルートとして利用しているディレクトリで、ここでは /var/www/html となっている。


Dockerfile

FROM php:apache

COPY ./public/info.php /var/www/html/

docker build コマンドを使って、新たな自前 Docker イメージを作成する。

Dockerfile で定義した利用コンテナイメージのダウンロードが行われ、それを基にして新規イメージが作られる。

$ docker build -t sandbox-phpinfo-apache .

docker images コマンドを実行すると、先ほど作った新規イメージが利用可能な状態であることがわかる。

$ docker images

REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
sandbox-phpinfo-apache latest 5cfc1b74c92a 42 seconds ago 481 MB
php 5.6-apache 385019d6807e 12 days ago 481 MB

docker run コマンドでこの自前 Docker イメージからコンテナを実行する。

-p オプションはポートフォワード設定で、Docker ホストへのアクセスに対してコンテナへ流す設定を行っている。

$ docker run --name phpinfo -p 80:80 -d sandbox-phpinfo-apache

fe055eccf5d24cc1fa5cec7940a6e619480dc6b091e0b83a8f0217007a795de6


動作確認

起動した Apache + PHP コンテナイメージに対してアクセスしてみる。

まずは Docker ホストの IP アドレスを docker-machine ip コマンドでチェック。

$ docker-machine ip dev

192.168.99.100

得られたアドレスを使って Docker ホストへブラウザでルートアクセスすると、phpinfo() が表示される。

スクリーンショット 2015-06-29 23.52.58.png


ローカルディレクトリをマウントして Web サーバを動かす

続けて、ローカルの public ディレクトリを先ほどのコンテナの Apache ドキュメントルートとしてマウントして動かしてみる。

ローカルには先ほどの phpinfo() 出力プログラムとは違う内容のものを用意。


public/index.php

<?php

echo "Hello, world: ", time();

先ほどのコンテナを一旦止めて、-v オプションで public ディレクトリをドキュメントルートへマウントする。

$ docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fe055eccf5d2 sandbox-phpinfo-apache "apache2-foreground" 7 minutes ago Up 7 minutes 0.0.0.0:80->80/tcp phpinfo

$ docker stop phpinfo
phpinfo

$ docker run --name phpinfo2 -v /path/to/sandbox-docker-phpinfo-apache/public:/var/www/html -p 80:80 -d sandbox-phpinfo-apache
40b99a767cbc2fbddb90d22fdc9e70296401cbce625c6133c355b455bbb2f0c7

再びブラウザでルートアクセスすると、今度は phpinfo() ではなく、public/index.php に書かれた Hello, world プログラムの結果が表示される。また、/info.php にアクセスすると phpinfo() が表示される。以上より、マウントした public ディレクトリがコンテナ内 Apache のドキュメントルートになって稼働していることがわかる。


Nginx + PHP-FPM

続いてもう1つ PHP サーバを動かすスタイルとしてよく見られる Nginx と PHP-FPM を組み合わせたサーバを Docker で作ってみる。ここでは、Nginx コンテナと PHP-FPM コンテナの2つを用意して、Nginx コンテナからの Proxy アクセスで PHP アプリケーションが利用できるようにする。


PHP-FPM コンテナ

php-fpm の Docker イメージをベースにしてコンテナを作成。あわせて phpinfo() を表示する PHP ファイルを先ほどの Apache のときと同じようにコピーする。


phpfpm/Dockerfile

FROM php:fpm

COPY index.php /var/www/html/


phpfpm/index.php

<?php

phpinfo();

イメージの作成とコンテナ起動。ここでは phpfpm という名称で起動した。

php:fpm の Docker コンテナな PHP-FPM を tcp:9000 で待ち受けするとのことだが、Nginx からの Proxy アクセスのみを考慮しているので、Docker 起動時のポートマッピングオプションは必要なしになる。

$ docker build -t sandbox-phpinfo-phpfpm ./phpfpm

$ docker run --name phpfpm -d sandbox-phpinfo-phpfpm


Nginx コンテナ

Nginx イメージ を使う。

PHP-FPM への Proxy アクセスのためのサーバ設定ファイルを用意して、コンテナをビルドする際に設定ファイルディレクトリへファイルを埋め込む。

FROM nginx

ADD server.conf /etc/nginx/conf.d/server.conf

Proxy 設定ファイルは以下のとおり。

ここでポイントなのが、Proxy 先となる PHP-FPM のホストを 127.0.0.1 などの IP, hostname ではなく、Docker のコンテナ間接続のための機構である link オプションによるエイリアス名を指定することになる。ここでは php という名称にした。 ("fastcgi_pass php:9000;" の箇所)


nginx/server.conf

server {

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

access_log off;
error_log off;

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

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


イメージの作成とコンテナ起動。

前述したコンテナ間接続のため、link オプションで <コンテナ名>:<エイリアス名> を指定する。phpfpm コンテナに対して Nginx 設定ファイル内で php というエイリアス名を使っているので、 --link phpfpm:php となる。

$ docker build -t sandbox-phpinfo-nginx ./nginx

$ docker run --name nginx -p 80:80 --link phpfpm:php -d sandbox-phpinfo-nginx


動作確認

Apache + PHP の時と同様、Docker ホストへブラウザでルートアクセスすると、PHP-FPM による phpinfo() が表示される。

スクリーンショット 2015-06-30 22.50.40.png


サンプルソース

今回利用したサンプルソース。