设置:一个 nginx 容器 vhost 管理器,当各自的 vhost 被激活时,它使用 systemd 自动生成 php-fpm 容器。
配置:/var/run 中用于套接字的共享卷。systemd-socket-proxyd 用于监听 nginx 的写入套接字,然后启动 fpm 容器,等待 fpm 容器创建监听套接字,然后将 nginx 的写入套接字代理到 fpm 的监听套接字。
nginx:/etc/nginx/conf.d/default:
try_files $uri =404;
root /usr/share/nginx/html;
fastcgi_pass unix:/var/run/docker-apps/vhost.fpm-waker.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
这告诉 nginx 将 php 请求传递给 /var/run/docker-apps/vhost.fpm-waker.sock。首先我们必须确保 nginx 和 fpm 具有相同的权限:
nginx:/etc/nginx/nginx.conf:
user www-data;
接下来我们确保 fpm 将打开 systemd 期望找到的 unix 套接字:
fpm:/etc/php5/fpm/pool.d/www.conf:
listen = /var/run/docker-apps/vhost.fpm.sock
listen.owner = www-data
listen.group = www-data
现在配置已准备好,我们将启动(但不运行)我们的 fpm 容器:
docker create \
--name vhost \
--ipc="container:nginx" \
-v /var/run/docker-apps:/var/run/docker-apps \
fpm
这里的重要部分是卷映射,它确保 FS 的一个区域可被我们将要使用的两个套接字写入。
host:/vagrant/docker/docker-compose.yml:
nginx:
image: nginx
container_name: switchboard.noflag.org.uk
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker-apps:/var/run/docker-apps
最后,我们主机上的 systemd 服务单元描述符:
[Unit]
Description=vhost fpm container
[Service]
ExecStart=/usr/bin/docker start -a vhost
ExecStartPost=/bin/sleep 2
ExecStop=/usr/bin/docker stop vhost
此服务描述符允许 systemd 控制容器的启动和停止。我们来测试一下:
# systemctl start vhost.service
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cacb32d1468c fpm "/usr/sbin/php5-fpm -" 26 hours ago Up 26 minutes 9005/tcp vhost
是的,该服务描述符工作正常。
现在我们告诉 systemd 何时以及如何为 nginx 创建要写入的监听套接字代理:
# more vhost.fpm-waker.socket
[Socket]
ListenStream=/var/run/docker-apps/vhost.fpm-waker.sock
SocketUser=www-data
SocketGroup=www-data
[Install]
WantedBy=sockets.target
此描述符描述了 systemd 将打开的用于 nginx 写入的套接字。当套接字激活时,vhost.fpm-waker.service 也会激活。
# more vhost.fpm-waker.service
[Unit]
Requires=vhost.fpm.service
After=vhost.fpm.service
[Install]
Also=vhost.fpm-waker.socket
[Service]
ExecStart=/lib/systemd/systemd-socket-proxyd /var/run/docker-apps/vhost.fpm.sock
vhost.fpm-waker.service 自动启动 vhost.service,正如我们所见,它成功启动了 fpm 容器。对套接字的请求由 /lib/systemd/systemd-socket-proxyd 代理,直到 fpm 使监听套接字 /var/run/docker-apps/vhost.fpm.sock 可用。
如果我们完全跳过 systemd-socket-proxyd 会发生什么?
# more vhost.fpm-waker.service
ExecStart=docker start -a vhost
# systemctl start vhost.fpm-waker.service
# docker logs vhost
[24-Nov-2016 13:07:06] ERROR: An another FPM instance seems to already listen on /var/run/docker-apps/vhost.fpm-waker.sock
[24-Nov-2016 13:07:06] ERROR: FPM initialization failed
因此我们可以确认 systemd-socket-proxyd 对于此过程是必需的,因为 fpm 不愿意传递预先存在的监听套接字。
当我们把所有碎片拼凑在一起时会发生什么?
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f92b7ce5e7b nginx "nginx -g 'daemon off" 28 hours ago Up About an hour 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx
# systemctl enable vhost.fpm-waker.socket
Created symlink from /etc/systemd/system/sockets.target.wants/vhost.fpm-waker.socket to /etc/systemd/system/vhost.fpm-waker.socket.
# ls -la /var/run/docker-apps
. ..
# systemctl start vhost.fpm-waker.socket
# ls -la /var/run/docker-apps
srw-rw---- 1 www-data www-data 0 Nov 24 21:31 vhost.fpm-waker.sock=
很好。Systemd 已成功创建 nginx 将要连接的套接字。让我们验证 nginx 是否可以与套接字通信:
# docker exec -it nginx ls -la /var/run/docker-apps
srw-rw---- 1 www-data www-data 0 Nov 24 21:31 vhost.fpm.sock=
最后一步。给定一个位于 nginx 和 fpm 容器都可用的位置的 index.php 文件,以下命令应从 php 生成文本“Hello, world”:
# curl http://localhost:80/index.php
<p>Sorry, the page you are looking for is currently unavailable.<br/> Please try again later.</p>
<p>If you are the system administrator of this resource then you should check the <a href="http://nginx.org/r/error_log">error log</a> for details.</p>
然而,事实并非如此。fpm 容器没有日志条目,但它是正在运行,正如预期的那样:
# docker logs vhost
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cacb32d1468c fpm "/usr/sbin/php5-fpm -" 26 hours ago Up 6 minutes 9005/tcp vhost
2f92b7ce5e7b nginx "nginx -g 'daemon off" 28 hours ago Up About an hour 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx
而且,nginx 的写入套接字(由 systemd 创建)和 fpm 的监听套接字(由 fpm 创建)均存在且正确:
# ls -la /var/run/docker-apps/
total 0
drwxr-xr-x 2 root root 60 Nov 24 21:31 ./
drwxr-xr-x 18 root root 660 Nov 24 20:06 ../
srw-rw---- 1 www-data www-data 0 Nov 24 21:31 vhost.fpm.sock=
srw-rw---- 1 www-data www-data 0 Nov 24 21:31 vhost.fpm-waker.sock=
唯一的线索是在 nginx 日志中:
docker logs nginx
172.21.0.1 - - [24/Nov/2016:20:51:04 +0000] "GET /index.php HTTP/1.1" 502 537 "-" "curl/7.38.0" "-"
2016/11/24 20:56:53 [error] 5#5: *15 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 172.21.0.1, server: localhost, request: "GET /index.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/docker-apps/vhost.fpm-waker.sock:", host: "localhost"
不幸的是,关于使用 unix 套接字通过 systemd-socket-proxyd 启动 docker 容器的信息很少,关于以这种方式启动 fpm 容器的信息就更少了。目前,我完全不知道接下来该怎么做。
要查看完整的项目大纲,您可以在此处下载,并可能能够使用 vagrant 重现该问题。但是,此时 systemd 服务单元不会自动复制到主机中: