在 Docker 中,使用 nginx + php-fpm 配置并通过 UNIX 套接字进行通信

前几天,我建立了一个使用nginx + php-fpm的环境,通过TCP进行协作。现在我要改成使用UNIX Socket来实现nginx和php-fpm之间的协作。

手順的步骤

    要使php-fpm在UNIX套接字上监听,需要准备一个与php-fpm在UNIX套接字上协作的docker,运行容器并确认配置的反映。

要在UNIX套接字上让php-fpm监听

大致上需要进行以下设定。

    1. 将已注册在php-fpm镜像中的用户添加到nginx镜像中

 

    1. 添加一个配置文件,将连接php-fpm的方式从TCP更改为UNIX Socket

 

    添加一个配置文件,用于设置nginx连接php-fpm的方式

将注册在 php-fpm 镜像中的用户添加到 nginx 镜像中。

将注册在php-fpm镜像中的用户添加到nginx镜像中的原因是需添加操作php-fpm的UNIX套接字的权限。如果不添加此权限,nginx将无法将请求传递给php-fpm。

启动php-fpm容器,并查看已注册在php-fpm镜像中的用户。

$ docker run --detach --net=sample_nw --name php-sample php/sample:20220327
8ffaac4a194dbfee7cd214f4a84fb613b3dbc929dca0f46305d4550f9129acda
$ docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED          STATUS          PORTS      NAMES
8ffaac4a194d   php/sample:20220327   "docker-php-entrypoi…"   31 seconds ago   Up 29 seconds   9000/tcp   php-sample
$ docker exec -i -t 8ffaac4a194d /bin/sh

# cat /etc/passwd | grep nginx
# cat /etc/passwd | grep www-data
www-data:x:82:82:Linux User,,,:/home/www-data:/sbin/nologin
/var/www/html # id www-data
uid=82(www-data) gid=82(www-data) groups=82(www-data),82(www-data)

作为与WEB服务器相关的用户,uid=82(www-data)gid=82(www-data)groups=82(www-data),82(www-data)已注册,因此需要将该用户注册到nginx的映像中。

确认注册在nginx镜像中的用户。

启动nginx的容器,并验证注册用户。

www_data 组已经注册,但是 www-data 用户尚未注册。在 php 镜像中,已经注册了 www-data 的组和用户,因此需要在 nginx 镜像中注册 www-data 用户。

$ docker ps
CONTAINER ID   IMAGE                     COMMAND                  CREATED          STATUS          PORTS                NAMES
95a89d5cac6d   php-socket_nginx-sample   "/docker-entrypoint.…"   18 seconds ago   Up 17 seconds   0.0.0.0:80->80/tcp   php-socket_nginx-sample_1
d82e7e343c79   php-socket_php-sample     "docker-php-entrypoi…"   19 seconds ago   Up 17 seconds   9000/tcp             php-socket_php-sample_1
$ docker exec -i -t bde24e5cbe3d /bin/sh
# cat www-data /etc/group
www-data:x:82:www-data
# cat nginx /etc/group
nginx:x:101:nginx
# grep www-data /etc/passwd
# grep nginx /etc/passwd
nginx:x:101:101:nginx:/var/cache/nginx:/sbin/nologin
# id nginx
uid=101(nginx) gid=101(nginx) groups=101(nginx),101(nginx)
# 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;
# exit

通过上述可以确认,虽然“www-data”和“nginx”组已经注册,但只有“nginx”用户被注册。

另外,为了给在/etc/nginx/nginx.conf注册的nginx进程分配操作php-fpm UNIX套接字的权限,需要修改/etc/nginx/nginx.conf的设置来授权nginx用户。

增加一个配置文件,将与php-fpm的连接从TCP更改为UNIX Socket。

php-fpm等待请求的配置文件位于以下目录下。

$ docker run --detach --net=sample_nw --name php-sample php/sample:20220327
8ffaac4a194dbfee7cd214f4a84fb613b3dbc929dca0f46305d4550f9129acda
$ docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED          STATUS          PORTS      NAMES
8ffaac4a194d   php/sample:20220327   "docker-php-entrypoi…"   31 seconds ago   Up 29 seconds   9000/tcp   php-sample
$ docker exec -i -t 8ffaac4a194d /bin/sh
# ls -l /usr/local/etc/php-fpm.d/
total 56
-rw-r--r--    1 root     root           357 Mar 23 19:57 docker.conf
-rw-r--r--    1 root     root         20876 Mar 23 19:57 www.conf
-rw-r--r--    1 root     root         20876 Mar 23 19:56 www.conf.default
-rw-r--r--    1 root     root            45 Mar 23 19:57 zz-docker.conf
# cat /usr/local/etc/php-fpm.d/zz-docker.conf
[global]
daemonize = no

[www]
listen = 9000

/usr/local/etc/php-fpm.d/zz-docker.conf是非常棘手的配置文件。即使在Dockerfile的COPY或docker-compose.yaml中使用文件来替换设置以监听UNIX套接字,更改仍无法生效。

当我进行调查时,发现原因在于公式的 php-fpm Dockerfile 中的描述覆盖了用户的更改。

    参照: php/Dockerfile at a41dc76cb007ac64177d6999f7be91aae149ee9e · docker-library/php · GitHub
	} | tee php-fpm.d/docker.conf; \
	{ \
		echo '[global]'; \
		echo 'daemonize = no'; \
		echo; \
		echo '[www]'; \
		echo 'listen = 9000'; \
	} | tee php-fpm.d/zz-docker.conf

请在本地语言中进行该短语的释义。

    • Documentation regarding configuration. #241

 

    • PHPの公式DockerイメージでUNIXソケット通信しようとして罠にハマる

 

    docker-composeでunixソケットを使った、Nginx、php-fpmコンテナを作る

要将php-fpm监听UNIX套接字,应该怎么做?

    • php-fpm の設定は、後から読み込まれる設定で上書きされる

 

    • 設定ファイルは、ファイル名の昇順で読み込まれる

 

    この仕様を利用して、/usr/local/etc/php-fpm.d/zz-docker.conf よりも後に設定ファイルを読み込ませて、TCP で listen する設定を、UNIX ソケットで listen する設定で上書きする

需要这件事情。 zhè .)

有几个网页详细说明了这种回避策,但没有提到上述的原因。因此,无法理解为什么将文件名更改为socket.conf后配置更改不会反映,确定原因花费了相当长的时间。

准备一个将php-fpm与UNIX套接字配合使用的docker。

Docker 最近使用以前创建的设置。

直接复制之前创建的 Docker 配置。

假设已创建的Docker配置位于以下目录$HOME/works/docker-sample/php-tcp。请进行复制。

$ pwd
$HOME/works/docker-sample
$ ls -l
total 0
drwxr-xr-x  5 centipede  centipede  160  3 27 13:36 php-tcp
$ cp -r php-tcp
$ ls -l
total 0
drwxr-xr-x  7 centipede  centipede  224  3 28 15:19 php-socket
drwxr-xr-x  5 centipede  centipede  160  3 27 13:36 php-tcp

编辑 docker-compose.yaml 文件

使nginx容器能够访问php-fpm生成的UNIX套接字。

$ cp -p docker-compose.yaml docker-compose.yaml.orig
$ vim docker-compose.yaml
$ cat docker-compose.yaml
version: '3'

# nginx と php-fpm のコンテナ間で共有されるボリューム名を設定
volumes:
  php-fpm-sock:

services:
  php-sample:
    restart: always
    build:
      context: .
      dockerfile: ./php/Dockerfile
    volumes:
      # 共有されるボリュームを次のディレクトリにマウントさせる
      - php-fpm-sock:/var/run/php-fpm

  nginx-sample:
    restart: always
    ports:
      - 80:80
    build:
      context: .
      dockerfile: ./nginx/Dockerfile
    volumes:
      # 共有されるボリュームを次のディレクトリにマウントさせる
      - php-fpm-sock:/var/run/php-fpm
      # ngixn のプロセスを実行するユーザーを変更するために、設定ファイルを置き換える
      - ./nginx/settings/nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - php-sample

变更如下:

$ diff -uw docker-compose.yaml.orig docker-compose.yaml
--- docker-compose.yaml.orig	2022-03-27 13:51:28.000000000 +0900
+++ docker-compose.yaml	2022-03-28 15:20:51.000000000 +0900
@@ -1,11 +1,16 @@
 version: '3'

+volumes:
+  php-fpm-sock:
+
 services:
   php-sample:
     restart: always
     build:
       context: .
       dockerfile: ./php/Dockerfile
+    volumes:
+      - php-fpm-sock:/var/run/php-fpm

   nginx-sample:
     restart: always
@@ -14,3 +19,8 @@
     build:
       context: .
       dockerfile: ./nginx/Dockerfile
+    volumes:
+      - php-fpm-sock:/var/run/php-fpm
+      - ./nginx/settings/nginx.conf:/etc/nginx/nginx.conf
+    depends_on:
+      - php-sample

修改nginx的Dockerfile。

为了操作php-fpm的UNIX套接字,需要在nginx镜像中添加用户。

在此情况下,需要将www-data用户的用户ID与php镜像中注册的用户ID匹配。由于该ID为82,因此需要在nginx镜像中创建一个具有用户ID 82的www-data用户。

$ cp nginx/Dockerfile nginx/Dockerfile.tcp
$ vim nginx/Dockerfile
$ cat nginx/Dockerfile
FROM nginx:1.21.6-alpine

# add nginx group and nginx user
RUN adduser -S www-data -G www-data -u 82 \
    && echo "www-data ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \
    && echo 'www-data:www-data' | chpasswd

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

变更点如下。

$ diff -uw nginx/Dockerfile.bak nginx/Dockerfile
--- nginx/Dockerfile.tcp	2022-03-27 17:50:49.000000000 +0900
+++ nginx/Dockerfile	2022-03-28 15:22:08.000000000 +0900
@@ -1,3 +1,8 @@
 FROM nginx:1.21.6-alpine

-COPY settings/default.conf /etc/nginx/conf.d/default.conf
+# add nginx group and nginx user
+RUN adduser -S www-data -G www-data -u 82 \
+    && echo "www-data ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \
+    && echo 'www-data:www-data' | chpasswd
+
+COPY nginx/settings/default.conf /etc/nginx/conf.d/default.conf
\ No newline at end of file

更改以使得 nginx 和 php-fpm 通过 UNIX Socket 进行协作。

为了将执行 nginx 的用户从 nginx 更改为 www-data,需要准备一个修改过的 nginc.conf 文件。

$ touch nginx/settings/nginx.conf
$ vim nginx/settings/nginx.conf
$ cat nginx/settings/nginx.conf
# change nginx user to www-data
user  www-data;
worker_processes  auto;

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


events {
    worker_connections  1024;
}


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

    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;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

修改default.conf的配置,以便与php-fpm的UNIX套接字进行通信。php-fpm的UNIX套接字将在/var/run/php-fpm/php-fpm.sock生成。

$ cp nginx/settings/default.conf nginx/settings/default.conf.orig
$ 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;
        fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

变更的内容如下。

$ diff -uw nginx/settings/default.conf.orig nginx/settings/default.conf
--- nginx/settings/default.conf.orig	2022-03-27 18:00:38.000000000 +0900
+++ nginx/settings/default.conf	2022-03-27 18:31:28.000000000 +0900
@@ -4,7 +4,7 @@

     location / {
         index          index.php index.html index.htm;
-        fastcgi_pass   php-sample:9000;
+        fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock;
         fastcgi_index  index.php;
         fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
         include        fastcgi_params;

修改 php-fpm 的 Dockerfile。

将读取文件 /usr/local/etc/php-fpm.d/zz-docker.conf 后,将 php-fpm 监听 TCP 9000 端口的配置覆盖为监听 UNIX Socket 的配置。为此,请将文件名 /usr/local/etc/php-fpm.d/zz-www.conf 导入到 php-fpm 的映像中。

$ cp php/Dockerfile php/Dockerfile.tcp
$ 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
# import the conf file ordred by file name to overwrite listening TCP port setting to unix socket
COPY php/settings/php-fpm.d/zz-www.conf /usr/local/etc/php-fpm.d/zz-www.conf

COPY php/src /usr/share/nginx/html

以下是变更点:

$ diff -uw php/Dockerfile.tcp php/Dockerfile
--- php/Dockerfile.tcp	2022-03-27 17:51:59.000000000 +0900
+++ php/Dockerfile	2022-03-28 15:36:56.000000000 +0900
@@ -1,5 +1,9 @@
 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
+# import the conf file to overwrite listening TCP port setting to unix socket
+COPY php/settings/php-fpm.d/zz-www.conf /usr/local/etc/php-fpm.d/zz-www.conf
+
 COPY php/src /usr/share/nginx/html

启动容器并确认配置的反映

为了确认,检查当前目录。

$ pwd
$HOME/works/docker-sample/php-socket
$ ls -l
$ ls -l
total 16
-rw-r--r--  1 centipede  centipede  471  3 28 15:20 docker-compose.yaml
-rw-r--r--  1 centipede  centipede  248  3 27 13:51 docker-compose.yaml.orig
drwxr-xr-x  6 centipede  centipede  192  4  3 18:50 nginx
drwxr-xr-x  7 centipede  centipede  224  3 28 15:20 php
drwxr-xr-x  2 centipede  centipede   64  3 28 13:29 src
$ tree
$ tree
.
├── docker-compose.yaml
├── docker-compose.yaml.orig
├── nginx
│   ├── Dockerfile
│   ├── Dockerfile.tcp
│   └── settings
│       ├── default.conf
│       ├── default.conf.orig
│       └── nginx.conf
└── php
    ├── Dockerfile
    ├── Dockerfile.tcp
    ├── settings
    │   ├── php-fpm.d
    │   │   └── zz-www.conf
    │   └── php.ini
    └── src
        └── index.php

6 directories, 12 files

启动容器。

$ docker-compose up -d
$ docker ps
CONTAINER ID   IMAGE                     COMMAND                  CREATED      STATUS      PORTS                NAMES
95a89d5cac6d   php-socket_nginx-sample   "/docker-entrypoint.…"   6 days ago   Up 6 days   0.0.0.0:80->80/tcp   php-socket_nginx-sample_1
d82e7e343c79   php-socket_php-sample     "docker-php-entrypoi…"   6 days ago   Up 6 days   9000/tcp             php-socket_php-sample_1

登录到 PHP 容器中,确认其状态。

$ docker exec -i -t d82e7e343c79 /bin/sh
/var/www/html # ls -l /usr/local/etc/php-fpm.d/
docker.conf       www.conf          www.conf.default  zz-docker.conf    zz-www.conf
/var/www/html # ls -l /usr/local/etc/php-fpm.d/zz-www.conf
-rw-r--r--    1 root     root           173 Mar 28 06:20 /usr/local/etc/php-fpm.d/zz-www.conf
/var/www/html # cat /usr/local/etc/php-fpm.d/zz-www.conf
[global]
daemonize = no

[www]

user = www-data
group = www-data

listen = /var/run/php-fpm/php-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode  = 0660
/var/www/html # ls -l /var/run/php-fpm/
total 0
srw-rw----    1 www-data www-data         0 Mar 28 06:23 php-fpm.sock
/var/www/html # netstat -natp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.11:44299        0.0.0.0:*               LISTEN      -
/var/www/html # exit

取り込まれたphp-fpm的配置文件并且生成了预期的UNIX套接字。通过执行netstat -natp命令,确认php-fpm没有监听端口。

接下来,要检查nginx的状态。

$ docker exec -i -t 95a89d5cac6d /bin/sh
/ # ls -l /var/run/php-fpm/
total 0
srw-rw----    1 www-data www-data         0 Mar 28 06:23 php-fpm.sock
/ # netstat -natp | grep nginx
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1/nginx: master pro
/ # exit

我确认了从Nginx容器中能看到PHP-FPM的UNIX套接字。

从主机上用curl尝试进行连接。

$ curl -I http://localhost/
HTTP/1.1 200 OK
Server: nginx/1.21.6
Date: Sun, 03 Apr 2022 09:58:42 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/8.1.4

在连接到 http://localhost/ 后,确认能够显示执行 phpinfo() 的结果。

广告
将在 10 秒后关闭
bannerAds