
Я пытаюсь контейнеризировать мой 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 «в исходном виде» (не в Docker), и я хочу использовать их сокеты для своего контейнера nginx (отсюда и строка volumes: - "/run/php:/run/php"
).
Разрешения сокетов равны srw-rw---- www-data:www-data
. Поэтому я добавил пользователя контейнера в группу 33 (которая является www-data на моей хост-системе -> group_add: ["33"]
). Когда я проверяю идентификаторы групп в контейнере, идентификатор 33
действительно добавляется к текущему вошедшему в систему пользователю:
/ # 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
- 33
такой же, как идентификатор на хост-машине для группы www-data
.
Внутри контейнера вы можете добавить пользователя nginx в группу xfs:
addgroup nginx xfs
Проблема должна быть устранена сейчас.
Я не уверен, как добавить это непосредственно в ваш файл Compose (как указать, какого пользователя добавить в группу?), но вы можете сделать это в своем 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 «в исходном виде» (не в Docker), и я хочу использовать их сокеты для своего контейнера nginx (отсюда и строка volumes: -
"/run/php:/run/php"
).
Это невозможно и неразумно.
Docker создает собственное сетевое пространство имен, поэтому вы получаете собственный стек брандмауэра, стек IP и сетевой стек Unix.
Даже если вы исправите проблему с разрешениями, предположим, что вы входите в контейнер вручную с помощью docker exec
файла chmod
сокета 666, и для краткости предположим, что на пути нет никаких пространств имен пользователей.
То, что вы просите сделать, эквивалентно следующему:
- Запуск
php-fpm
экземпляраsystem1
с сокетом Unix/var/run/php-fpm.sock
- Экспорт
/var/run
пути по NFS наsystem1
. - Монтаж
system1:/var/run
наsystem2
. Полностью отдельная система. - Попытка
connect()
подключиться к сокету Unixsystem2
и ожиданиеsystem1
ответаphp-fpm
.
То, как вы на самом деле должны это сделать (на самом деле должныхотетьдля этого (что является отдельным вопросом) нужно прослушивать экземпляр с использованием IP -- например, php-fpm
привязывая его к . Затем использовать in для подключения к .host_system:12345
nginx
container
host_system:12345
Это все просто неправильно. Не слушайте меня. Если вы создаете правильно названный сокет unix, открытый в любом из пространств имен, и путь является общим для обоих пространств имен, подключение к этому сокету unix подключается к другому пространству имен!
https://lore.kernel.org/all/[email protected]/Т/
Этот патч как раз решает эту проблему. Очевидно, когда я это тестировал, это было очень давно! :)
Единственный случай, когда это не так, — это случай создания анонимного сокета Unix, однако это довольно специфичная для Linux и нечасто используемая функция сокетов Unix.