docker で nginx と php-fpm 環境を構築してみる

docker で nginx と php-fpm 環境を構築し、Dockerfile からコンテナの起動までを実施してみる。

## 手順の流れ

1. docker イメージ作成のディレクトリ作成
1. nginx と php-fpm の設定ファイルなどの準備
1. Dockerfile の作成
1. docker のネットワーク設定
1. nginx と php-fpm のコンテナ作成と起動
1. nginx への接続確認
1. nginx と php-fpm に取り込まれたファイルの確認
1. コンテナの停止と削除

### docker イメージ作成のディレクトリ作成

まずは docker イメージ作成に必要なディレクトリの用意をする。
ディレクトリ名は、任意の名称で良い。今回は、nginx と php-fpm 間を TCP で通信するので、ディレクトリ名を php-tcp と適当につけた。

```zsh
$ mkdir -p ~/works/docker-sample/php-tcp
$ cd ~/works/docker-sample/php-tcp
```

### nginx と php-fpm の設定ファイルなどの準備

docker イメージを作成する際に、nginx と php-fpm を動作・連携させるのに必要な設定ファイルを準備する。

#### php-fpm の設定ファイルなどの準備

設定ファイルは php-fpm のイメージに含まれている php.ini-production を利用する。
この設定ファイルを編集するのではなく、追加の設定を外部ファイルとして書き出し、docker イメージ作成時に取り込んで、php-fpm が読み込むようにする。

```zsh
$ mkdir -p php/settings
$ echo "[PHP]\ndate.timezone = \"Asia/Tokyo\"" > settings/php.ini
$ cat settings/php.ini
[PHP]
date.timezone = "Asia/Tokyo"
```

そして、動作確認用のファイルも用意しておく。

```zsh
$ mkdir -p php/src/
$ touch php/src/index.php
$ vim php/src/index.php
$ echo '<?php phpinfo(); ?>' > php/src/index.php
$ cat php/src/index.php
<?php phpinfo(); ?>
```

#### nginx の設定ファイルの準備

nginx の設定ファイルに、php-fpm との連携に必要な設定を外部ファイルに記述して、nginx に読み込ませる。
nginx のドキュメントルートには、今回なにもファイルを置いていない。

```zsh
$ mkdir -p nginx/settings/
$ touch nginx/settings/default.conf
$ vim nginx/settings/default.conf
$ cat nginx/settings/default.conf
server {
    listen 80;
    root /usr/share/nginx/html;

    location / {
        index          index.php index.html index.htm;
        # php-sample:9000 の php-sample は php-fpm のコンテナ名を指定している
        fastcgi_pass   php-sample:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}
```

### Dockerfile の作成

nginx と php-fpm の Dockerfile を用意する。

#### php-fpm の Dockerfile を用意する

```zsh
$ touch php/Dockerfile
$ vim php/Dockerfile
$ cat php/Dockerfile
FROM php:8.1.4-fpm-alpine

RUN cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini
COPY php/settings/php.ini /usr/local/etc/php/conf.d/php.ini
COPY src /usr/share/nginx/html
```

COPY コマンドで参照される相対パスのルートは Dockerfile が置いていあるディレクトリになる。

#### nginx の Dockerfile を用意する

```zsh
$ mkdir nginx
$ touch nginx/Dockerfile
$ vim nginx/Dockerfile
$ cat nginx/Dockerfile
FROM nginx:1.21.6-alpine

COPY settings/default.conf /etc/nginx/conf.d/default.conf
```

#### 現在のファイルの配置状況

```zsh
$ pwd
$HOME/works/docker-sample/php-tcp
$ tree
.
├── nginx
│   ├── Dockerfile
│   └── settings
│       └── default.conf
└── php
    ├── Dockerfile
    ├── settings
    │   └── php.ini
    └── src
        └── index.php

5 directories, 5 files
```

### docker のネットワーク設定

nginx と php-fpm のコンテナ間の通信と外部からの通信ができるように、ネットワークの設定をする。

```zsh
$ docker network create --driver bridge sample_nw
```

この設定は docker-compose でコンテナの作成と起動をすると不要になる。
(docker-compose コマンドがネットワークを自動生成してくれる)

### nginx と php-fpm のコンテナ作成と起動

まずは docker イメージを作成する。

```zsh
$ docker build --no-cache -t php/sample:20220327 php/
$ docker build --no-cache -t nginx/sample:20220327 nginx/
$ docker image list
REPOSITORY                    TAG        IMAGE ID       CREATED         SIZE
nginx/sample                  20220327   6ee198feefa2   4 seconds ago   23.4MB
php/sample                    20220327   8ab121bef960   3 minutes ago   73.4MB
```

そして、先ほど作成したネットワーク `sample_nw` にnginx と php-fpm の docker イメージをバインドして、起動する。


```zsh
$ docker run --detach --net=sample_nw --name php-sample php/sample:20220327
6bfa5e297b13777617b8fb70a2e7451139b434851be3ebd077dfbdc32435ffc5
$ docker run --detach --net=sample_nw -p 80:80 --name nginx-sample nginx/sample:20220327
5e5327b192cd3adbc7d3b050086a466d03b73a0d433912300e044869785c5aae
```

`docker run --detach --net=sample_nw -p 80:80 --name nginx-sample nginx/sample:20220327` の `-p 80:80` が意味するところは、ローカルホスト 80 ポートの接続は、コンテナの 80 ポート (nginx) へ転送させるための設定になる。

起動を確認する。

```zsh
$ docker ps
CONTAINER ID   IMAGE                   COMMAND                  CREATED         STATUS         PORTS                NAMES
5e5327b192cd   nginx/sample:20220327   "/docker-entrypoint.…"   6 seconds ago   Up 5 seconds   0.0.0.0:80->80/tcp   nginx-sample
6bfa5e297b13   php/sample:20220327     "docker-php-entrypoi…"   3 minutes ago   Up 3 minutes   9000/tcp             php-sample
```

### nginx への接続確認

コマンドと WEB ブラウザから、動作確認をしてみる。

nginx 経由で php-fpm のレスポンスを取得できている。

```zsh
$ curl -I -s localhost:80
HTTP/1.1 200 OK
Server: nginx/1.21.6
Date: Sun, 27 Mar 2022 04:30:08 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/8.1.4
```

WEB ブラウザから [ローカルホスト](http://localhost/) にアクセスをして、`phpinfo();` の実行結果が表示されることを確認する。

![phpinfo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248967/4d9f9a61-c7fe-2446-f270-b7d585bbf87a.png)

### nginx と php-fpm に取り込まれたファイルの確認

まずは、両コンテナの ID を確認する。

```zsh
$ docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED       STATUS       PORTS                NAMES
b7eb6af2f944   php-tcp_nginx-sample   "/docker-entrypoint.…"   3 hours ago   Up 3 hours   0.0.0.0:80->80/tcp   nginx-sample
def5d6b848a6   php-tcp_php-sample     "docker-php-entrypoi…"   3 hours ago   Up 3 hours   9000/tcp             php-sample
```

そして、php-fpm のコンテナにログインをしてみる。

```zsh
$ docker exec -i -t def5d6b848a6 /bin/sh
# ls -l /usr/local/etc/php/
total 220
drwxr-xr-x    1 root     root          4096 Mar 27 04:12 conf.d
-rw-r--r--    1 root     root         72908 Mar 27 04:12 php.ini
-rw-r--r--    1 root     root         72762 Mar 23 19:57 php.ini-development
-rw-r--r--    1 root     root         72908 Mar 23 19:57 php.ini-production
# head /usr/local/etc/php/php.ini-production
[PHP]

;;;;;;;;;;;;;;;;;;;
; About php.ini   ;
;;;;;;;;;;;;;;;;;;;
; PHP's initialization file, generally called php.ini, is responsible for
; configuring many of the aspects of PHP's behavior.

; PHP attempts to find and load this configuration from a number of locations.
; The following is a summary of its search order:
#
# head /usr/local/etc/php/php.ini
[PHP]

;;;;;;;;;;;;;;;;;;;
; About php.ini   ;
;;;;;;;;;;;;;;;;;;;
; PHP's initialization file, generally called php.ini, is responsible for
; configuring many of the aspects of PHP's behavior.

; PHP attempts to find and load this configuration from a number of locations.
; The following is a summary of its search order:
# head /usr/local/etc/php/conf.d/php.ini
[PHP]
date.timezone = "Asia/Tokyo"
# exit
$
```

nginx のコンテナにログインをする。

```zsh
$ docker exec -i -t b7eb6af2f944 /bin/sh
# ls -l /etc/nginx/
total 36
drwxr-xr-x    1 root     root          4096 Mar 27 04:15 conf.d
-rw-r--r--    1 root     root          1077 Jan 25 15:26 fastcgi.conf
-rw-r--r--    1 root     root          1007 Jan 25 15:26 fastcgi_params
-rw-r--r--    1 root     root          5349 Jan 25 15:26 mime.types
lrwxrwxrwx    1 root     root            22 Mar 23 17:15 modules -> /usr/lib/nginx/modules
-rw-r--r--    1 root     root           648 Jan 25 15:26 nginx.conf
-rw-r--r--    1 root     root           636 Jan 25 15:26 scgi_params
-rw-r--r--    1 root     root           664 Jan 25 15:26 uwsgi_params
# head /etc/nginx/nginx.conf

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
# ls -l /etc/nginx/conf.d/
total 4
-rw-r--r--    1 root     root           324 Mar 27 04:51 default.conf
# head /etc/nginx/conf.d/default.conf
server {
    listen 80;
    root /usr/share/nginx/html;

    location / {
        index          index.php index.html index.htm;
        fastcgi_pass   php-sample:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include        fastcgi_params;
# exit
$
```

Dockerfile でイメージに取り込むように記述したファイルが、ちゃんと取り込まれていることが確認できた。

### コンテナの停止と削除

```zsh
$ docker stop nginx-sample
nginx-sample
$ docker stop  php-sample
php-sample
$ docker rm php-sample
php-sample
$ docker rm nginx-sample
nginx-sample
```

続きは [Dockerfile から docker-compose.yaml を作る](https://qiita.com/centipede/items/2b6f1c0c7de9225c026a) 。