あるSEのつぶやき・改

IT・システム開発に関することをつぶやいています。

Docker+CentOS8+nginxにPHP(php-fpm)をインストールする


はじめに

前の記事では、Docker に CentOS 8 と nginx をインストールする方法をご紹介しました。

www.aruse.net

この記事では、さらに PHP(php-fpm) のコンテナを構築して、Web(nginx) + App(PHP) という構成の環境を構築します。

フォルダ構成

Docker の設定ファイルなどのフォルダ構成は、以下の通りです。今回は、最初から Dockerfile と docker-compose.yml を使用します。

root
├── docker-compose.yml
├── php
│   ├── Dockerfile
│   └── www.conf
├── share
│   └── src
│       └── index.php
└── web
    ├── Dockerfile
    └── nginx.conf

nginx の設定

nginx では、以下の Dockerfile を使用します。

Dockerfile

FROM centos:8
RUN dnf -y update
RUN dnf install -y nginx
COPY nginx.conf /etc/nginx/nginx.conf
ENTRYPOINT /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf

nginx のインストールは、dnf を使用していますが yum と文法は変わらないので違和感はないです。

COPYコマンドでは、ローカル(ホスト側)にあるnginx.confをコンテナにコピーしています。

ENTRYPOINTコマンドでは、コンテナが終了してしまわないよう nginx をフォアグラウンドで実行しています。Docker では、バックグラウンドプロセスしか実行していないと、Docker がコンテナを終了してしまうのでこのような記述になっています。

なお、nginx をフォアグラウンドで実行する方法として、以下の記述がネットで多かったですがうまく動作しませんでした。

CMD ["/usr/sbin/nginx", "-g", "daemon off;"]

nginx の設定は以下のようになります。デフォルトと異なるのは、php-fpm の設定を追加していることです。

nginx.conf

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
         listen       80 default_server;
         listen       [::]:80 default_server;
         server_name  _;
         root         /usr/share/nginx/html;

         # Load configuration files for the default server block.
         include /etc/nginx/default.d/*.conf;

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

         error_page 404 /404.html;
             location = /40x.html {
         }

         error_page 500 502 503 504 /50x.html;
            location = /50x.html {
         }

         location ~ \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass php:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }
    }
}

php-fpm の設定の以下のphpは、Docker の設定によるコンテナ名を指しています。

            fastcgi_pass php:9000;

PHP(php-fpm) の設定

Docker では、1コンテナ1プロセスという制約があるようなので、PHP(php-fpm) 用にコンテナを構築します。

Dockerfile は以下のようになります。

Dockerfile

FROM centos:8
RUN dnf -y update
RUN dnf install -y php php-fpm
RUN mkdir -p /run/php-fpm
COPY www.conf /etc/php-fpm.d/www.conf

/run/php-fpmディレクトリを作成しているのは、php-fpm 実行時にこのディレクトリがないとエラーになってしまうためです。また、COPYコマンドでローカルからコンテナに php-fpm の設定ファイルをコピーしています。

php-fpm の設定ファイルは以下のようになります。デフォルトと異なるのは、user と group を nginx にしていることと、listen をプロセスファイルではなくポート番号にしていること、listen.acl_users をコメントアウトしていることです。

www.conf

[www]
user = nginx
group = nginx
listen = 9000
;listen.acl_users = apache,nginx
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path]    = /var/lib/php/session
php_value[soap.wsdl_cache_dir]  = /var/lib/php/wsdlcache

Docker Compose の設定

Docker Compose の設定で(docker-compose.yml)、コンテナの設定を行います。

docker-compose.yml

version: '3'
services:
  web:
    build:
      context: ./web/.
    ports:
      - "8080:80"
    links:
      - php
    volumes:
      - ./share/src:/usr/share/nginx/html
  php:
    build:
      context: ./php/.
    command: php-fpm -F
    volumes:
      - ./share/src:/usr/share/nginx/html

serviceswebphpがありますが、それぞれ1つのコンテナになります。

buildは相対パスにある Dockerfile を使用してコンテナイメージのビルドを行います。

linksはコンテナ間の依存関係を記述します。weblinks-phpと設定されることで、phpのコンテナをwebのコンテナから参照できるようになります。

volumesは、ホスト側とコンテナで共有するディレクトリを設定します。./share/srcには PHP のファイルを保存するので、webphpで共通の設定になっています。

phpcommand: php-fpm -Fは、php-fpm をフォアグラウンドで実行するためのコマンドです。いろいろ調べたのですが、Dockefile に記述する方法はダメで、docker-compose.ymlに記述する必要があるようです。

また下記コマンドを実行して、index.php を作成しておきます。

$ cd share/src
$ echo "<?php phpinfo(); ?>" > index.php

コンテナの起動

下記コマンドを実行して、web と php の2つのコンテナをまとめて起動します。

$ docker-compose up -d

起動ができているか確認します。

$ docker-compose ps
      Name                     Command              State          Ports        
--------------------------------------------------------------------------------
wordpress_php_1     php-fpm -F                      Up                          
wordpress_web_1     /bin/sh -c /usr/sbin/nginx      Up      0.0.0.0:8080->80/tcp

問題なく起動していますね。

State に Exit と表示されている場合はコンテナが起動していないので、原因を調べて対応する必要があります。

では、ブラウザでhttp://localhost:8080/index.phpを開いて、phpinfo() が出力されているか確認します。

f:id:fnyablog:20191006114524p:plain:w480

問題なく表示されていますね。

これで、web と php のコンテナの通信が行われていて、php-fpm も問題なく動作していることが分かります。

コンテナの終了

作業が終了したら、下記コマンドでコンテナを終了して削除します。

$ docker-compose down
Stopping wordpress_web_1   ... done
Stopping wordpress_php_1   ... done
Removing wordpress_web_1   ... done
Removing wordpress_php_1   ... done
Removing network wordpress_default

おわりに

Docker で CentOS に nginx をインストールして PHP(php-fpm) と連携するというのはマイナーなようで、ネットで調べてもあまり情報がありませんでした。トラブルシューティングの情報はほぼない状態でしたね。リリースされてから1ヶ月経っていない CentOS 8 なのでさらに情報がなかったです。

みなさん、nginx の公式のコンテナイメージを使用されているのでしょうね。だけど、OS が固定されることもあると思うのですが、その場合はどうしているのでしょう?苦労してはいるけれど、情報が共有されてないだけ?

この記事がお役にたてば幸いです。