Apache + php-fpm を別々の Docker コンテナで動かしたい（Unixドメインソケット コンテナ間通信）

# 背景
Apache + php-fpm の環境を別々の Docker コンテナで構築しようと思ったのですが、
同一コンテナで構築している方々が多かったため、記事にしてみました。

別々のコンテナで構築するメリットは、Apache、php-fpm どちらかのバージョンアップをする際に片方のコンテナのみの停止、DockerFile編集、起動で良いことです。

最低限の設定しかしませんので、Webサーバにこの手順を使用する際にはセキュリティやログの出力先等、詳細な設定をしてください。

以前、記事にした環境構築を参考にしております。

https://qiita.com/hamburg-love/items/ae819a7abf921af77376

# 環境
ホストOS：Amazon Linux release 2 (Karoo)
コンテナOS：CentOS Linux release 7.9.2009 (Core)
Docker version 20.10.4
docker-compose version 1.29.2
Apache/2.4.6
PHP 5.4.16 (fpm-fcgi)

# 手順
## ディレクトリ・ファイル配置
ディレクトリとファイルの配置場所の構成は以下のようにしました。

```
ApachePHPFPM
|
|- Apache
|  |- Dockerfile
|  |- httpd-original.conf
|
|- PHPFPM
|  |- Dockerfile
|  |- www-original.conf
|
|- docker-compose.yml
```

## Apache コンテナ
### DockerFile
DockerFile は以下のように記述しております。

```
# ベースイメージの指定
FROM centos:centos7

# yum update
RUN yum update -y

# Apache のインストール
RUN yum install -y httpd

# Apache の設定ファイルを配置
COPY httpd-original.conf /etc/httpd/conf/httpd.conf

# Apache の起動
ENTRYPOINT ["/usr/sbin/httpd", "-DFOREGROUND"]
```

### Apache の設定ファイル
Apache の設定ファイルは `httpd-original.conf` というファイル名にしてます。
ドキュメントルートの設定に、php-fpm に処理を渡す記述を書いただけです。
以下のように記述しています。


```
ServerRoot "/etc/httpd"

Listen 80

Include conf.modules.d/*.conf

User apache
Group apache

ServerName localhost:80
ServerAdmin root@localhost

<Directory />
    AllowOverride none
    Require all denied
</Directory>

DocumentRoot "/var/www/html"

<Directory "/var/www">
    AllowOverride None
    Require all granted
</Directory>

<Directory "/var/www/html">
    <FilesMatch \.(html|php)$>
       SetHandler "proxy:unix:/var/run/php-fpm/php-fpm.sock|fcgi://php-fpm"
    </FilesMatch>

    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

<IfModule dir_module>
    DirectoryIndex index.html index.php
</IfModule>

<Files ".ht*">
    Require all denied
</Files>

ErrorLog "logs/error_log"
LogLevel warn

<IfModule log_config_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

    <IfModule logio_module>
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>

    CustomLog "logs/access_log" combined
</IfModule>

<IfModule alias_module>
    ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
</IfModule>

<Directory "/var/www/cgi-bin">
    AllowOverride None
    Options None
    Require all granted
</Directory>

<IfModule mime_module>
    TypesConfig /etc/mime.types
    AddType application/x-compress .Z
    AddType application/x-gzip .gz .tgz
    AddType text/html .shtml
    AddOutputFilter INCLUDES .shtml
</IfModule>

AddDefaultCharset UTF-8

<IfModule mime_magic_module>
    MIMEMagicFile conf/magic
</IfModule>

EnableSendfile on
IncludeOptional conf.d/*.conf
```

## PHPFPM コンテナ
### DockerFile

```
# ベースイメージの指定
FROM centos:centos7

# yum update
RUN yum update -y

# php-fpm のインストール
RUN yum install -y php-fpm

# php-fpm の設定ファイルを配置
COPY www-original.conf /etc/php-fpm.d/www.conf

# Apache の起動
ENTRYPOINT ["php-fpm"]
```

### PHPFPM の設定ファイル
PHPFPM の設定ファイルは `www-original.conf` というファイル名にしてます。
`listen` にソケットファイルの場所を記述しています。
他は以下のように記述しています。

```
[www]
listen = /var/run/php-fpm/php-fpm.sock

listen.owner = apache
listen.group = apache
listen.mode = 0660

user = nobody
group = nobody

pm = static
pm.max_children = 2

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
```

## docker-compose ファイル
Apache と PHPFPM はUNIXドメインソケットで通信しています。
なので、`socket` というボリュームを作成し、このボリュームを Apache , PHPFPM コンテナのソケットファイルを配置するディレクトリでマウントしております。

また、ホストの `/opt/app` に Apache コンテナのドキュメントルートをマウントして、ホスト側で公開するファイルを配置できるようにしてます。

PHPFPM コンテナ側でも`/opt/app`にドキュメントルートをマウントして、処理するファイルが見えるようにします。

```
version: "3.9"
services:
  apache:
    build:
      context: ./Apache
      dockerfile: Dockerfile
    ports:
      - "80:80"
    volumes:
      - "socket:/var/run/php-fpm/"
      - "/opt/app:/var/www/html"
  php-fpm:
    build:
      context: ./PHPFPM
      dockerfile: Dockerfile
    volumes:
      - "socket:/var/run/php-fpm/"
volumes:
  socket:
```

## 公開するファイルの配置
今回は phpinfo を表示して動作確認します。
`/opt/app` 配下にファイルを配置します。

```:index.php
<?php echo phpinfo(); ?>
```

## docker-compose によるコンテナ作成
`ApachePHPFPM` ディレクトリ内で以下コマンドを実行するだけです。

```
sudo docker-compose up -d --build
```

## 動作確認
URLにアクセスして phpinfo が表示されるか確認します。
表示されればOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184532/e25bb382-4b3c-b12e-e6cf-2d8207713b6f.png)

## はまったところ
最初はソケット通信だとソケットファイルを使って、Apache コンテナからPHPFPM コンテナに `index.php` の内容を送ってくれるものだと思っており、PHPFPM 側から index.php のファイルが見えないように設定しておりました。
それだと`File not found.` になってしまうのでご注意ください。

## 最後に
一度、`DockerFile` や `docker-compose.yml` を書いてしまえば、1つのコマンドで同じ環境を複数作れるのはとても魅力的に感じました。

作業効率を良くするために docker の勉強は続けていきたいと思います。
最後まで読んでいただきありがとうございました。