我尝试将当前在服务器上运行的 nginx 容器化。为此,我创建了以下 docker compose 文件:
version: "3.8"
services:
nginx:
image: nginx:stable-alpine
container_name: nginx
restart: unless-stopped
group_add: ["33"]
volumes:
- "/etc/nginx-docker:/etc/nginx/conf.d:ro"
- "/run/php:/run/php"
- "/var/www:/var/www:ro"
ports:
- "8111:80"
- "8443:443"
一切工作正常,但问题是,我的主机系统上仍然有 php-fpm“本地”运行(未 dockerized),并且我想将它们的套接字用于我的 nginx 容器(因此有此行volumes: - "/run/php:/run/php"
)。
套接字的权限是srw-rw---- www-data:www-data
。因此,我将容器用户添加到组 33(即我的主机系统上的 www-data -> group_add: ["33"]
)。当我在容器中检查组 ID 时,该 ID33
确实已添加到当前登录的用户:
/ # id -G
0 1 2 3 4 6 10 11 20 26 27 33
/ # id -u
0
/ # whoami
root
尽管如此,当我调用由 PHP 驱动的网站时,我在 nginx 日志中收到以下错误消息:
2024/01/21 08:58:53 [crit] 21#21: *1 connect() to unix:/run/php/php8.2-fpm.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.192.68, server: _, request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:", host: "op---s:8111"
有什么提示或解决方案可以使其工作吗?
答案1
我做了一些挖掘:)
如果你进入运行 nginx 镜像的容器,你会看到有几个 nginx 进程正在运行:
docker exec -it 43b5b971c433 /bin/sh
/ # ps -ef |grep nginx
1 root 0:00 nginx: master process nginx -g daemon off;
21 nginx 0:00 nginx: worker process
22 nginx 0:00 nginx: worker process
23 nginx 0:00 nginx: worker process
24 nginx 0:00 nginx: worker process
42 root 0:00 grep nginx
有些以 身份运行root
,有些以nginx
用户身份运行。
您已将用户添加root
到www-data
docker-compose 文件中的组中,但即使不这样做,root 用户也应该拥有访问 php unix 套接字所需的所有权限。
您可以使用以下test
命令测试权限。输出退出代码以查看命令是否成功。如您所见,root 用户可以读取套接字文件,但不能执行它:
/run/php # whoami
root
/run/php # test -r php8.1-fpm.sock; echo $?
0
/run/php # test -x php8.1-fpm.sock; echo $?
1
因此permission denied
错误可能来自nginx worker
以用户身份运行的进程nginx
。
让我们首先检查 docker 容器内文件的权限...
ls -al
输出结果如下:
srw-rw---- 1 xfs xfs 0 Jan 25 08:58 php8.1-fpm.sock
表示套接字文件归“xfs”所有。快速查看/etc/group
容器内的文件会发现xfs
组的 ID33
与主机上组的 ID 相同www-data
。
在容器内部,可以将 nginx 用户添加到 xfs 组:
addgroup nginx xfs
现在该问题应该已经解决了。
我不确定如何将其直接添加到您的撰写文件中(您如何指定要添加到组中的用户?) - 但如果您可以创建一个新的图像,您可以在您的 Dockerfile 中执行此操作。
但重新启动容器后,权限似乎仍然存在。
答案2
确定 PHP-FPM 在主机上运行的用户和组。您通常可以在 PHP-FPM 配置文件中找到此信息(通常位于 /etc/php/7.x/fpm/pool.d/www.conf)
然后更新你的docker-compose并添加这个
user: "your_php_user:your_php_group"
答案3
一切工作正常,但问题是,我的主机系统上仍然有 php-fpm“本地”运行(未 dockerized),并且我想将它们的套接字用于我的 nginx 容器(因此有行 volumes: -
"/run/php:/run/php"
)。
这是不可能的,也是没有意义的。
Docker 生成了自己的网络命名空间,因此您可以获得自己的防火墙堆栈、IP 堆栈和 Unix 网络堆栈。
即使您解决了权限问题,假设您使用套接字文件 666 手动登录到容器,docker exec
并且chmod
为了简洁起见,我们假设其中没有用户命名空间。
您要求执行的操作相当于:
- 使用 Unix 套接字运行
php-fpm
实例system1
/var/run/php-fpm.sock
/var/run
通过 NFS导出路径system1
。- 安装
system1:/var/run
在 上system2
。一个完全独立的系统。 - 尝试
connect()
对所述 Unix 套接字套接字进行连接system2
并期望system1
用 进行响应php-fpm
。
你实际上应该这样做(实际上应该想要做到这一点(这是另一回事),需要php-fpm
使用 IP 监听实例 -- 将其绑定到host_system:12345
例如。然后使用nginx
incontainer
连接到host_system:12345
。
这完全是错误的。别听我的。如果你创建一个命名良好的 unix 套接字,在任一命名空间中公开,并且路径在两个命名空间之间共享,则连接到该 unix 套接字将连接到另一个命名空间!
https://lore.kernel.org/all/[电子邮件保护]/T/
此补丁专门解决了这个问题。显然,当我测试它时已经是很久很久以前的事情了!:)
唯一一次出现这种情况的情况是在匿名 Unix 套接字创建案例中,然而这是一个 Linux 特有的并且不常用的 Unix 套接字功能。