Назад | Перейти на главную страницу

502: сброс соединения одноранговым узлом при использовании systemd-socket-proxyd для активации fpm по требованию

Настройка: диспетчер vhost контейнеров nginx, который использует systemd для автоматического создания контейнеров php-fpm, когда их соответствующие vhosts активированы.

Конфигурация: общий том для сокетов в / 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 откроет сокет unix, где его ожидает найти systemd:

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

Часть импорта здесь - это сопоставление томов, которое гарантирует, что область файловой системы доступна для записи обоими сокетами, которые мы собираемся использовать.

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=

Последний шаг. При наличии файла index.php в месте, доступном как для контейнеров nginx, так и для fpm, следующее должно вывести текст «Hello, world» из php:

# 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 и еще меньше о запуске контейнеров fpm таким образом. На данный момент я совершенно не понимаю, куда идти дальше.

Чтобы увидеть полную схему проекта, вы можете скачать его здесь и, возможно, сможете воспроизвести проблему с помощью vagrant. Однако в настоящее время служебные модули systemd не копируются на хост автоматически:

https://github.com/djcf/wordpress-fpm-docker