php fpm docker config
Как nginx указать на php-fpm на другом докере?
Сделано два простых докера:
2019/01/23 07:57:21 [error] 9#9: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.24.0.1, server: localhost, request: «GET / HTTP/1.1», upstream: «fastcgi://127.0.0.1:9000», host: «localhost:6080»
Ошибка, насколько понимаю в том, что nginx не видит php-fmp, который находится в другом докере. Как правильно настроить это?
Вместо
fastcgi_pass 127.0.0.1:9000;
Указать
fastcgi_pass php:9000;
Ваша ошибка указывает на то, что nginx не может найти по адресу 127.0.0.1 php-fpm.
А происходит это потому, что адрес 127.0.0.1 это адрес внутри контейнера nginx, а php-fpm лежит за его пределами внутри другого контейнера.
Благодаря тому, что docker-compose по умолчанию создает сеть между контейнерами указанными в файле, то достучаться до сервиса можно по его имени из docker-compose.yml. В вашем случае это php
В браузере получаю ошибку «File not found.»
2019/01/24 07:07:25 [error] 8#8: *5 FastCGI sent in stderr: «Primary script unknown» while reading response header from upstream, client: 172.24.0.1, server: localhost, request: «GET / HTTP/1.1», upstream: «fastcgi://172.24.0.2:9000», host: «localhost:6080
Все, разобрался, рабочий конфиг оказался таким:
\.php$ <
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/site.loc$fastcgi_script_name;
include fastcgi_params;
>
И пробовал путь:
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
В браузере получаю ошибку «File not found.»
2019/01/24 07:07:25 [error] 8#8: *5 FastCGI sent in stderr: «Primary script unknown» while reading response header from upstream, client: 172.24.0.1, server: localhost, request: «GET / HTTP/1.1», upstream: «fastcgi://172.24.0.2:9000», host: «localhost:6080
Все, разобрался, рабочий конфиг оказался таким:
\.php$ <
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/site.loc$fastcgi_script_name;
include fastcgi_params;
>
How to correctly link php-fpm and Nginx Docker containers?
I am trying to link 2 separate containers:
The problem is that php scripts do not work. Perhaps the php-fpm configuration is incorrect. Here is the source code, which is in my repository. Here is the file docker-compose.yml :
and Dockerfile which I used to build a custom image based on the nginx one:
Lastly, here is my custom Nginx virtual host config:
Could anybody help me configure these containers correctly to execute php scripts?
P.S. I run containers via docker-composer like this:
from the project root directory.
7 Answers 7
I know it is kind an old post, but I’ve had the same problem and couldn’t understand why your code didn’t work. After a LOT of tests I’ve found out why.
It seems like fpm receives the full path from nginx and tries to find the files in the fpm container, so it must be the exactly the same as server.root in the nginx config, even if it doesn’t exist in the nginx container.
docker-compose.yml
/etc/nginx/conf.d/default.conf
Dockerfile
Don’t hardcode ip of containers in nginx config, docker link adds the hostname of the linked machine to the hosts file of the container and you should be able to ping by hostname.
EDIT: Docker 1.9 Networking no longer requires you to link containers, when multiple containers are connected to the same network, their hosts file will be updated so they can reach each other by hostname.
Every time a docker container spins up from an image (even stop/start-ing an existing container) the containers get new ip’s assigned by the docker host. These ip’s are not in the same subnet as your actual machines.
see docker linking docs (this is what compose uses in the background)
An entry with the alias’ name will be created in /etc/hosts inside containers for this service, e.g:
expose
and if you set up your project to get the ports + other credentials through environment variables, links automatically set a bunch of system variables:
Full URL, e.g. DB_PORT=tcp://172.17.0.5:5432
Full URL, e.g. DB_PORT_5432_TCP=tcp://172.17.0.5:5432
Container’s IP address, e.g. DB_PORT_5432_TCP_ADDR=172.17.0.5
Exposed port number, e.g. DB_PORT_5432_TCP_PORT=5432
Protocol (tcp or udp), e.g. DB_PORT_5432_TCP_PROTO=tcp
Fully qualified container name, e.g. DB_1_NAME=/myapp_web_1/myapp_db_1
As pointed out before, the problem was that the files were not visible by the fpm container. However to share data among containers the recommended pattern is using data-only containers (as explained in this article).
Using compose (1.6.2 in my machine), the docker-compose.yml file would read:
Note that data publishes a volume that is linked to the nginx and fpm services. Then the Dockerfile for the data service, that contains your source code:
And the Dockerfile for nginx, that just replaces the default config:
For the sake of completion, here’s the config file required for the example to work:
New Answer
Docker Compose has been updated. They now have a version 2 file format.
Version 2 files are supported by Compose 1.6.0+ and require a Docker Engine of version 1.10.0+.
They now support the networking feature of Docker which when run sets up a default network called myapp_default
From their documentation your file would look something like the below:
As these containers are automatically added to the default myapp_default network they would be able to talk to each other. You would then have in the Nginx config:
Old Answer
I have kept the below here for those using older version of Docker/Docker compose and would like the information.
I kept stumbling upon this question on google when trying to find an answer to this question but it was not quite what I was looking for due to the Q/A emphasis on docker-compose (which at the time of writing only has experimental support for docker networking features). So here is my take on what I have learnt.
Docker has recently deprecated its link feature in favour of its networks feature
Therefore using the Docker Networks feature you can link containers by following these steps. For full explanations on options read up on the docs linked previously.
First create your network
Next run your PHP-FPM container ensuring you open up port 9000 and assign to your new network ( mynetwork ).
Next run your Nginx container again assign to the network you created.
Now comes the Nginx configuration. Which should look something similar to this:
You can add that Nginx config either during the build process of your Docker container or afterwards its up to you.
Докеризация nginx и php на сокетах с ротацией логов
Each container should have only one concern
Decoupling applications into multiple containers makes it much easier to scale horizontally and reuse containers. For instance, a web application stack might consist of three separate containers, each with its own unique image, to manage the web application, database, and an in-memory cache in a decoupled manner.
You may have heard that there should be “one process per container”. While this mantra has good intentions, it is not necessarily true that there should be only one operating system process per container. In addition to the fact that containers can now be spawned with an init process, some programs might spawn additional processes of their own accord. For instance, Celery can spawn multiple worker processes, or Apache might create a process per request. While “one process per container” is frequently a good rule of thumb, it is not a hard and fast rule. Use your best judgment to keep containers as clean and modular as possible.
If containers depend on each other, you can use Docker container networks to ensure that these containers can communicate.
В результате обсуждения выяснилось, что можно вместо отправки сигнала USR1 nginx добавить опцию copytruncate в конфигурацию logrotate. Значит в контейнере нет необходимости в запуске нескольких процессов. Однако все действия по настроке запуска ротации логов по cron нужно все равно будет выполнить только не внутри контейнера, а на хосте где работет контейнер. При запуске в одном контейнере и веб-сервер, и ротации логов, отдельная настройка ротации на хосте уже не требуется.
В приведенных выше ссылках даны решения. Впрочем с первого раза все не заработало и пришлось искать причины. Поэтому кроме ссыок я привожу результаты своих опытов. Для того, чтобы можно было познакомиться со способом защиты от DDoS-атак вместо сервера nginx будет запускаться openresty (сборка nginx от Taobao со скриптовым движком Lua). Этот сервер имеет другое по сравнению с nginx расположение каталогов с файлами. Но все остальное абсолютно идентично.
Для начала создадим файл docker-compose.yml в корневом каталоге проекта:
Мы предполагаем что сценарии создания контейнеров будут храниться в файлах docker/php/Dockerfile и docker/nginx/Dockerfile. Имя Dockerfile является именем по умолчанию, следовательно нет необходимости его явно задавать в конфигурации.
Создадим файл docker/php/Dockerfile:
Загружается образ php:7-fpm и создается пользователь с идентификатором заданным параметром UID (в docker-compose.yml UID: 3000) с именем app в группе app. Это нужно чтобы задать права на чтение сокета из контйнера, где будет запущен openresty.
Для того чтобы получить ротацию логов в nginx или openresty, необходимо чтобы контейнер не завершал работу при рестарте веб-сервера, а так же чтобы в этом же контейнере был запущен cron. То есть это не будет однопроцессный контейнер, но иначе ничего не получится. Запускать несколько процессов рекомендуется через supervisor.
Создадим файл docker/nginx/Dockerfile:
Так же необходмио создать несколько конфигурационных файлов.
Файл docker/php/zz-docker.conf (имя zz-docker.conf присутсвует в конфигурации образа php:7-fpm. Это нигде не описано и может меняться. К сожалению в настоящий момент подробных описаний образов нет, и приходися их исследовать после загрузки из репозитария):
Параметр listen = /sock/docker.sock будет тот же что и в конфигурации nginx.
Основной конфигурационный файл nginx придется переписать т.к. в openresty он не содержит необходимых параметров, а это расположение логов, иднтификатор процесса, пользователь (app), и каталог с конфигурациями виртуалных серверов (/conf.d).
Создадим виртуальный сервер с конфигурацией server.conf:
Теперь создадим файл logrotate.conf:
И задание для cron:
И наконец конфигурация supervisor:
Совершенно не имеет значения где все эти конфигурационные фйлы находятся, т.к. все пути задаются в операторах COPY из Dockerfile, и в значениях volumes из docker-compose.yml. Теперь нужно набраться терпения и записать все необходимые пути в docker-compose.yml.
Теперь можно добавить скрипты Lua (см. статью на Хабре).
Docker + php-fpm + PhpStorm + Xdebug
Не так давно тимлид нашей команды сказал: ребята я хочу, чтобы у всех была одинаковая среда разработки для наших боевых проектов + мы должны уметь дебажить всё — и web приложения, и api запросы, и консольные скрипты, чтобы экономить свои нервы и время. И поможет нам в этом docker.
Поэтому, давайте уточним условия задачи:
На боевых серверах используется стандартная связка nginx + php-fpm + mysql. И, в чем проблема?
Разворачиваем на локальной машине точно такое же окружение + Xdebug, настраиваем наши проекты в PhpStorm, работаем. Для дебага включаем «трубку» в PhpStorm, всё работает из коробки, всё замечательно.
Всё это действительно так — всё работает из коробки. Но, давайте попробуем заглянуть под капот нашего рабочего окружения.
Nginx + php-fpm общаются через сокет, xdebug слушает порт 9000, PhpStorm тоже, по умолчанию, слушает порт 9000 для дебага и всё вроде бы замечательно. А если у нас открыто несколько приложений в PhpStorm, и включена прослушка («трубка)» для нескольких приложений? Что сделает PhpStorm? Он начнет ругаться, что обнаружено новое подключение для Xdebug, вы хотите его игнорировать, или нет?
Т.е., при настройках по умолчанию в PhpStorm, в конкретный момент времени, я могу дебажить только одно приложение. У всех других открытых приложений дебаг должен быть выключен. Блин, но это же неудобно. Я хочу слушать для дебага все приложения, и если в каком-то из них стоит точка останова, то я хочу, чтобы PhpStorm остановился в этом приложении, на той строке, где мне нужно.
А что для этого нужно? А нужно, чтобы каждое приложение запускалось со своими настройками для Xdebug. Чтобы каждое приложение слушало свой порт, искало свой сервер, а не так, как у нас всё общее, всё в одной куче.
А для этого есть замечательный докер! Мы можем запустить каждое наше боевое приложение в отдельном контейнере, на основе одного общего образа, например, php:7.1-fpm. Благодаря технологии докера мы можем изолировать наши приложения, при минимальных накладных расходах.
Ок, давайте заведем наши боевые проекты под докер, запустим каждый проект в отдельном контейнере, настроим каждый проект в PhpStorm для дебага индивидуально, всё должно быть замечательно.
Костылим, вот пример образа php:7.1-fpm, который будет собираться.
Update
Как справедливо указало сообщество — совсем уж жестко костылить всё-таки не надо.
Например хаброюзер 1ntrovert в своем комментарии
Поправленный пример Dockerfile
При запуске контейнера из данного образа пользователь www-data получает uid=1000, gid=1000. Обычно такие права у первого созданного пользователя в операционной системе Линукс. И, именно с такими правами будут работать наши php-fpm контейнеры. Буду очень благодарен, если кто-то подскажет как можно работать без костылей с правами доступа в докер.
При запуске контейнера из данного образа пользователь www-data получает uid и gid, которые будут переданы извне.
Также в комментариях поднималась тема: зачем вообще менять права пользователю www-data, чем не устраивают стандартные права 33. Только одним: когда мы зайдем в контейнер, и создадим, например, файл миграции, то на машине хоста владельцем этого файла будем не мы. И каждый раз надо будет запускать что-то вроде
И вторая небольшая проблема: для корректной работы Xdebug необходимо прописать верный ip адрес для машины хоста. У каждого члена команды он разный. 127.0.0.1 не катит. И тут нам на помощь приходит сам докер. Например, мы можем явно сконфигурировать сеть — 192.168.220.0/28. И тогда наша машина всегда будет иметь адрес 192.168.220.1. Этот адрес мы будем использовать как для настройки PhpStorm, так и для настройки других приложений. Например, при работе с MySql.
Сам docker-compose.yml, после учета замечаний, выглядит так:
Мы видим, что в данном конфиге создаются два контейнера php71-first и php71-two, на основе одного образа php:7.1-fpm. У каждого контейнера свои настройки для Xdebug. Каждый отдельно взятый контейнер будет слушать, для дебага, свой порт и свой сервер.
Также, обращаю ваше внимание на директивы
Без этих переменных образ php-fpm не запустится. Вопрос: как их передать в docker-compose.yml? Ответ: так как удобнее вам. Можно при запуске:
Полный код для демо версии выложен на гитхабе.
Листинг демо проекта:
Пробежимся, кратко, по листингу проекта.
Каталог hosts — конфигурационные файлы для Nginx. В каждом конфиге прописан свой контейнер php-fpm. Пример:
Каталог images — инструкции для сборки образов php-fpm, каталог mysql — храним базы, каталог www — все наши web проекты, в нашем примере first.loc и two.loc.
Давайте подведем промежуточные итоги: используя возможности докера мы запустили все свои рабочие проекты в одном окружении. Все наши проекты видят друг друга, для каждого из проектов прописаны уникальные настройки для Xdebug.
Осталось корректно настроить PhpStorm для каждого из проектов. При настройке мы должны прописать порт для дебага и имя сервера в нескольких местах.
Создаем проект в PhpStorm
Настраивать будем разделы меню
— PHP (необходимо верно прописать CLI Interpreter),
— Debug (меняем порт на 9008, как в файле docker-compose.yml),
— DBGp proxy (IDE key, Host, Port),
update Спасибо хаброюзеру CrazyLazy за важное замечание. Пункт меню DBGp proxy настраивать не надо.
— Servers (необходимо верно указать имя сервера, как в файле docker-compose.yml, и use path mappings)
Все дальнейшие скрины буду прятать под спойлер.
Хитрого ничего нет — важно, при настройке выбрать нужный образ, и верно прописать имя сервера. По умолчанию имя сервера Docker, у нас оно своё.
Опять же всё прописываем из настроек docker-compose.yml для конкретного контейнера. На этом же шаге валидируем как работает наш дебаг.
Важно правильно прописать use path mappings, имя сервера опять же берем из настроек
Сервер выбираем наш, созданный на предыдущем шаге.
Ну, собственно и всё. Написано много букв, вроде бы всё непросто
На самом деле — главное понять очень простую вещь. Благодаря технологии докера мы можем запустить все наши рабочие приложения в едином пространстве, но с разными настройками для Xdebug. Каждое приложение работает в своем контейнере, и нам остаётся аккуратно прописать настройки для каждого приложения в PhpStorm.
И на выходе мы получаем чудесную картину.
2. Прописываем узлы first.loc и two.loc в файле /etc/hosts
4. Настраиваем оба проекта first.loc и two.loc в PhpStorm, так как описано выше, и запускаем оба проекта в PhpStorm. Т.е. у нас открыто два окна PhpStorm, с двумя проектами, каждый из них слушает входящие соединения (трубка включена).
5. В проекте two.loc ставим точку останова на второй, например, строке. В первом проекте first.loc запускаем http запрос из файла http.http
И о чудо! Нас перекидывает во второй проект, на нашу точку останова.
Для дебага консольных скриптов делаем всё ровно тоже самое. Включаем трубку для прослушки, ставим точку останова, заходим в нужный контейнер, запускаем нужный скрипт.
Где php71first — алиас на машине хоста:
cdf — алиас, который работает в контейнере. Выше я писал о том, что для общения с контейнерами предпочитаю использовать алиасы.
На этом всё, конструктивная критика, замечания приветствуются.
Разворачиваем связку Nginx+Php-Fpm+MySQL с magento2 на борту и раскладываем по контейнерам в Docker
Все чаще стучась в различные компании разработчиков в качестве DevOps инженера, я получаю приблизительно одни и те же тестовые задания. Они отличаются друг от друга версиями PHP или проектами которые надо запустить.
Но в целом они упираются в одну связку это Nginx\Appache, SQL (тут вариаций много, все зависит от предпочтений заказчика), PHP и желательно чтобы это было разложено по контейнерам.
Поэтому я решил рассказать на примере, как все это поднять без особых усилий.
Возможно кому-то это поможет понять, на простом примере, что к чему. Описывать что такое Docker я не буду, т.к. статей на эту тему вагон и маленькая тележка.
В данной статье, мы подготовим небольшую структуру:
Все зависит от системы в которой вы хотите работать, в отношении кроссплатформенности, docker приятно удивляет (один и тот же файл конфигурации позволяет собрать и запустить контейнеры на любой системе *nix, Win, iOS).
Для Linux (к примеру в CentOS)
Включаем и стартуем сервис:
Чтобы наша структура создавалась одной командой нам потребуется docker-compose.
Для начала поставим необходимые для него компоненты:
Дальше устанавливаем docker-compose и обновляем python:
(или # pip install docker-compose)
Для Win систем (многие считают это извращением)
Но если вы решили, настоятельно рекомендую вам это делать на версии которая поддерживает Hyper-V (например win10 Prof).
Включаем компонент Hyper-V в «Включении и отключении компонентов Windows» (Turn Windows features on or of).
Скачиваем установщик с оф.сайта докера и устанавливаем. Также, дополнительно вы можете поставить GUI (Kitematiс) для наглядного отображения.
Приступим к созданию окружения:
Для начала создадим под этот проект папку и заходим в нее:
Дальше строим структуру папок таким образом:
Создаем понятную среду для nginx:
MySQL — в этой папке будут храниться базы. Удобно бэкапить и переносить.
Nginx — тут будут храниться логи, файл конфигурации и наш проект.
PHP — сюда мы сложим Dockerfile с настройками и php.ini.
в корне (в нашем случе папка /mage) будет лежать файл docker-compose.yml.
Создадим конфигурационный файл для Nginx:
Можно использовать любой другой редактор. Если его нет — можно установить с помощью:
И добавляем в nginx.conf следующее:
Во втором блоке прописываем параметры fastcgi.
Третий блок нужен для решения проблемы отображения, в проекте показывалась пустая страница. Из документации вычитал что magento2 требует реврайтинга. (на других проектах таким проблем не возникало).
В папке www создаем каталог для нашего проекта:
Скачиваем с оф.сайта magento2
и извлекаем из архива в папку /mage/Nginx/www/magento2
C настройками для Nginx мы закончили.
Теперь займемся PHP:
Начнем с Dockerfile
Это нужно, чтобы мы могли использовать те модули, которые нужны именно под этот проект.
В этом файле мы рассказали что должно быть установленно в этом образе, а так же указали где будет располагаться корневая директория и куда скопировать настройки из php.ini
Теперь настроим php.ini:
Это взято из php.ini.sample который предлагают сами разработчики Magento2. Нечего сверхъестественного я в него не добавлял.
Все, на этом настройка PHP закончена.
Дальше создаем файл docker-compose который нам все соберет в одну удобную систему.
Тут мы распишем какие сервисы и с какими настройками должны запуститься:
И по экрану побегут строчки, а вы спокойно можете налить себе кружечку горячего кофе, пока машина будет работать за вас.
После установки, у вас в папке MySQL, создастся много файлов и папок, одна из которых будет magento2, а в папке Nginx/Logs появятся 2 лога.
Открыв браузер и набрав там localhost вы должны увидеть приглашение к установке Magento2.
Если все таки что-то не получилось, то возможно этот список решений, сможет вам помочь:
1) Версия docker-compose файла не подошла, тогда нужно поправить «version: ‘3.3’», посмотреть какая именно подойдет вам можно тут
2) Все нормально запустилось, но браузер открывает чистую страницу, без единой ошибки — поможет строчка в nginx.conf
3) Если после установки самой Magento2 (в браузере) у вас не прорисовываются фреймы и все выглядит как текстовый вариант сайта, вам нужно сделать следующее:
3.1 в SQL, советую зайти через phpmyadmin localhost:8090 логин root пароль mypassword, выбрать базу magento2 и ввести sql запрос
3.2 подключиться к контейнеру c PHP (php-fpm) и набрать
Он должен пересчитать и проверить все. И после этого все корректно должно отображаться.
4.1 в линуксе надо отключить политику защиты
Отключение до перезагрузки
или отключение навсегда
4.2 В windows нужно в настройках docker выбрать shared drivers и выбрать диск на котором у вас лежит проект. После перезапуска Docker проблема уйдет.