Разработка под Docker. Локальное окружение. Часть 2 — Nginx+PHP+MySql+phpMyAdmin
Для лучшего понимания нижеследующего материала сначала рекомендуется ознакомится с Предыдушим постом
Рассмотрим пример развертки локального окружения состоящего из связки Nginx+PHP+MySql+phpMyAdmin. Данная связка очень популярна и может удовлетворить ряд стандартных потребностей рядового разработчика.
Как и в прошлом посте акцент будет смещен в сторону утилиты docker-compose, чем докера в чистом виде.
Итак, поехали!
Начнем вот с такого docker-compose.yml, который лежит в отдельной папке proxy:
В представленном файле описана конфигурация для создания одного контейнера с именем proxy на базе образа image: jwilder/nginx-proxy и создание сети с одноименным именем. Директива networks указывает к каким сетям подключен контейнер, в данном примере, это наша сеть proxy.
При создание сети директиву driver: bridge можно было бы и не указывать. Драйвер типа «мост» является драйвером по умолчанию. Данный контейнер будет связываться по сети с прочими контейнерами.
Образ jwilder/nginx-proxy является базовым и взят и Docker Hub там же представлено довольно обширное и подробное описание по его использованию. Принцип работы nginx-proxy довольно простой, он через пробрасываемый сокет докера получает доступ к информации о запущенных контейнерах, анализирует наличие переменной окружения с именем VIRTUAL_HOST и перенаправляет запросы с указанного хоста на контейнер, у которого данная переменная окружения задана.
Данный вывод информирует нас о том, что в начале была создана сеть proxy_proxy, а затем был создан контейнер proxy_proxy_1. Имя сети получилось из названия папки, в которой размещался файл docker-compose.yml, у меня это proxy и одноименного имени сети.
Если ввести команду docker network ls, то мы увидим список сетей докера в нашей системе и одна из них должна быть proxy_proxy.
Имя контейнера строиться по аналогичному принципу имя папки плюс название сервиса и число, которое позволяет, чтобы контейнеры со схожими именами не дублировались. Через директиву container_name можно задать имя контейнера явно, но я считаю это довольно бесполезной функцией. Подробнее пойдет речь об этом в следующих постах.
Создаем второй docker-compose.yml следующего содержания:
Что тут у нас объявлено?
Перечислены четыре сервиса: nginx, php, mysql и phpmyadmin. И две сети. Одна сеть прокси с именем frontend, объявлена как внешняя сеть и новая внутренняя сеть backend. Драйвер для нее не указан, как и писал ранее, будет использоваться драйвер по умолчанию типа bridge.
nginx
Тут примерно должно быть все понятно. Используем базовый образ с докер хаб. Переменная окружения необходима для работы прокси и сообщает ему, по какому адресу должен быть доступен контейнер. Опция depends_on указывает, на зависимость данного контейнера от контейнера php. Это означает, что вперед будет запущен контейнер php, а после него будет выполнен запуск зависимого от него контейнера nginx. Далее пробрасываем конфигурацию для нашего nginx. Она будет чуть ниже и монтируем папку с html. Так же замечаем, что контейнер имеет доступ сразу к двум сетям. Он должен связываться и прокси из сети frontend и с php из сети backend. В принципе, можно было бы все контейнеры и в одну сеть frontend попихать, но я придерживаюсь, что подобное разделение более верное.
default.nginx — это конфиг для nginx, который пробрасывается в контейнер. Ключевой момент тут директива fastcgi_pass php:9000. Она задает адрес FastCGI-сервера. Адрес может быть указан в виде доменного имени или IP-адреса, и порта.
php:9000 — имя сервиса это и есть адрес FastCGI-сервера. Nginx обращаясь по адресу php будет получать IP-адрес контейнера, в котором работает php. Порт 9000 это стандартный порт, он объявлен при создание базового контейнера. Данный порт доступен для nginx по сети, но не доступен на хостовой машине, так как не был проброшен.
Тут необычно то, что не указан образ. Вместо этого происходит сборка собственного образа прямо из compose-файла. Директива context указывает на папку, в которой находится Dockerfile.
В Dockerfile указано, что для сборки используется базовый образ php:7.3.2-fpm, далее выполняется запуск команд для установки php-расширений. Далее копируется composer из другого базового образа и устанавливается рабочая директория для проекта. Детальнее вопросы сборки рассмотрю в других постах.
Также во внутрь контейнера пробрасывается файл php.ini и папка html с нашим проектом.
Заметим, что php находится в сети backend и к примеру прокси к нему доступ получить уже не может.
mysql
База находится в сети backend, что позволяет ей держать связь с php. В базовом образе используется стандартный порт 3306. Он доступен по сети докера для php, но не доступен на хостовой машине. Если выполнить проброс для данного порта, то можно к нему коннектиться к примеру из того же PHPSTORM. Но если вам достаточно интерфейса phpmyadmin, то этого можно и не делать.
phpmyadmin
Официальный образ phpmyadmin. В переменных окружения используется VIRTUAL_HOST для взаимодействия с прокси, аналогично nginx. PMA_USER и PMA_PASSWORD доступ к базе. И PMA_HOST сам хост базы. Но это не localhost, как обычно бывает, а mysql. Т.е. связь с базой доступна по имени ее сервиса, т.е. mysql. Контейнер phpmyadmin может связаться с базой, т.к имеет подключение к сети backend.
Видим следующий вывод:
Видим, что в начале происходит создание сети lesson2_backend, затем сборка образа php, потом может происходить скачивание образов, которых еще нет в системе (pull) и собственно запуск описанных сервисов.
Последний штрих, чтобы все заработало это добавление в hosts или доменов site.local и phpmyadmin.local.
Содержимое index.php может быть следующим:
Тут мы проверяем корректность подключения расширения php — mysqli, которое было добавлено при сборке Dockerfile.
И заметим, что для связи с контейнером используется название сервиса — mysql.
Структура всего проекта получилась следующей:
Разворачиваем связку 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 проблема уйдет.
Настройка веб-сервера в Docker (NGINX + PHP + MariaDB)
По данной инструкции мы настроим наш веб сервер в Docker следующим образом:
Данную конфигурацию можно использовать для быстрого развертывания сайтов или для локальной разработки.
Мы будем работать в системе на базе Linux. Предполагается, что Docker уже установлен.
NGINX + PHP + PHP-FPM
Рекомендуется каждый микросервис помещать в свой отдельный контейнер, но мы (для отдельного примера) веб-сервер с интерпретатором PHP поместим в один и тот же имидж, на основе которого будут создаваться контейнеры.
Создание образа
Создадим каталог, в котором будут находиться файлы для сборки образа веб-сервера:
Переходим в созданный каталог:
* где:
1) указываем, какой берем базовый образ. В нашем случае, CentOS 8.
3) задаем для информации того, кто создал образ. Указываем свое имя и адрес электронной почты.
5) создаем переменную окружения TZ с указанием временной зоны (в нашем примере, московское время).
7) запускаем обновление системы.
8) устанавливаем пакеты: веб-сервер nginx, интерпретатор php, сервис php-fpm для обработки скриптов, модуль php-mysqli для работы php с СУБД MySQL/MariaDB.
9) удаляем скачанные пакеты и временные файлы, образовавшиеся во время установки.
10) добавляем в конфигурационный файл nginx строку daemon off, которая запретит веб-серверу автоматически запуститься в качестве демона.
11) создаем каталог /run/php-fpm — без него не сможет запуститься php-fpm.
13) копируем содержимое каталога html, который находится в том же каталоге, что и dockerfile, в каталог /usr/share/nginx/html/ внутри контейнера. В данной папке должен быть наше веб-приложение.
15) запускаем php-fpm и nginx. Команда CMD в dockerfile может быть только одна.
17) открываем порт 80 для работы веб-сервера.
В рабочем каталоге создаем папку html:
. а в ней — файл index.php:
* мы создали скрипт, который будет выводить информацию о php в браузере для примера. По идее, в данную папку мы должны положить сайт (веб-приложение).
Создаем первый билд для нашего образа:
Новый образ должен появиться в системе:
При желании, его можно отправить на Docker Hub следующими командами:
docker tag dmosk/webapp:v1 dmosk/web:nginx_php7
docker push dmosk/web:nginx_php7
* первой командой мы прошли аутентификацию на портале докер-хаба (в качестве id/login мы используем dmosk — это учетная запись, которую мы зарегистрировали в Docker Hub). Вторая команда создает тег для нашего образа, где dmosk — учетная запись на dockerhub; web — имя репозитория; nginx_php7 — сам тег. Последняя команда заливает образ в репозиторий.
* подробнее про загрузку образа в репозиторий докера.
Запуск контейнера и проверка работы
Запускаем веб-сервер из созданного образа:
Открываем браузер и переходим по адресу http:// — откроется страница phpinfo:
Наш веб-сервер из Docker работает.
MariaDB
Для запуска СУБД мы будем использовать готовый образ mariadb. Так как после остановки контейнера, все данные внутри него удаляются, мы должны подключить внешний том, на котором будут храниться наши базы.
Сначала создаем том для докера:
* в данном примере мы создали том с именем mariadb. Будет создан каталог /var/lib/docker/volumes/mariadb/_data/ на хостовом сервере, куда будут размещаться наши файлы базы.
Выполним первый запуск нашего контейнера с mariadb:
В каталоге тома должны появиться файлы базы данных. В этом можно убедиться командой:
Теперь подключаемся к командной строке внутри контейнера с сервером базы данных:
Подключаемся к mariadb:
Меняем пароль для учетной записи root:
> SET PASSWORD FOR ‘root’@’localhost’ = PASSWORD(‘New_Password’);
Выходим из командной строки СУБД:
Выходим из контейнера:
Останавливаем сам контейнер — он нам больше не нужен с данными параметрами запуска:
docker stop maria_db
И запускаем его по новой, но уже без системной переменной с паролем и необходимостью его удаления после остановки:
Сервер баз данных готов к работе.
Подключение к базе из веб-сервера
По отдельности, наши серверы готовы к работе. Теперь настроим их таким образом, чтобы из веб-сервера можно было подключиться к СУБД.
Зайдем в контейнер с базой данных:
Подключимся к mariadb:
Создадим базу данных, если таковой еще нет:
> CREATE DATABASE docker_db DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
* в данном примере мы создаем базу docker_db.
Создаем пользователя для доступа к нашей базе данных:
> GRANT ALL PRIVILEGES ON docker_db.* TO ‘docker_db_user’@’%’ IDENTIFIED BY ‘docker_db_password’;
* и так, мы дали полные права на базу docker_db пользователю docker_db_user, который может подключаться от любого хоста (%). Пароль для данного пользователя — docker_db_password.
Отключаемся от СУБД:
Выходим из контейнера:
Теперь перезапустим наши контейнеры с новым параметром, который будет объединять наши контейнеры по внутренней сети.
Останавливаем работающие контейнеры и удаляем их:
docker stop maria_db web_server
docker rm maria_db web_server
docker network create net1
* мы создали сеть net1.
Создаем новые контейнеры из наших образов и добавляем опцию —net, которая указывает, какую сеть будет использовать контейнер:
* указав опцию —net, наши контейнеры начинают видеть друг друга по своим именам, которые мы задаем опцией —name.
Готово. Для проверки соединения с базой данных в php мы можем использовать такой скрипт:
* в данном примере мы подключаемся к базе docker_db на сервере maria_db с использованием учетной записи docker_db_user и паролем docker_db_password.
После его запуска, мы увидим либо пустой вывод (если подключение выполнено успешно), либо ошибку.
Использование docker-compose
В отличие от docker, с помощью docker-compose можно разворачивать проекты, состоящие из нескольких контейнеров, одной командой.
И так, автоматизируем запуск наших контейнеров с использованием docker-compose. Необходимо, чтобы он был установлен в системе.
Сначала удалим контейнеры, которые создали на предыдущих этапах:
Переходим в каталог для наших сборок:
Создаем yml-файл с инструкциями сборки контейнеров через docker-compose:
maria_db:
image: mariadb
container_name: maria_db
restart: always
volumes:
— /var/lib/docker/volumes/mariadb/_data/:/var/lib/mysql
* в формате yml очень важное значение имеют отступы. Если сделать лишний пробел, то мы получим ошибку.
* где:
Запускаем сборку наших контейнеров с помощью docker-compose:
Запускаем контейнеры в режиме демона:
Проверяем, какие контейнеры запущены:
Возможные проблемы
Рассмотрим некоторые проблемы, которые могут возникнуть в процессе настройки.
1. Errors during downloading metadata for repository ‘AppStream’
Ошибка возникает при попытке собрать имидж на Linux CentOS 8. Полный текст ошибки может быть такой:
Errors during downloading metadata for repository ‘AppStream’:
— Curl error (6): Couldn’t resolve host name for http://mirrorlist.centos.org/?release=8&arch=x86_64&repo=AppStream&infra=container [Could not resolve host: mirrorlist.centos.org]
Error: Failed to download metadata for repo ‘AppStream’: Cannot prepare internal mirrorlist: Curl error (6): Couldn’t resolve host name for http://mirrorlist.centos.org/?release=8&arch=x86_64&repo=AppStream&infra=container [Could not resolve host: mirrorlist.centos.org]
Причина: система внутри контейнера не может разрешить dns-имена в IP-адрес.
Решение: в CentOS 8 запросы DNS могут блокироваться брандмауэром, когда в качестве серверной части (backend) стоит nftables. Переключение на iptables решает проблему. Открываем файл:
Setting up PHP-FPM, Nginx, Mariadb on CentOs using docker
I’m trying to move from from using VirtualBox as my development environment to docker.
With VirtualBox, I mainly install PHP-FPM, Nginx and Mariadb but in Docker, I can’t replicate the same stack despite trying for some days.
Out of all the LEMP/LAMP stack docker guides, only this one chentex/docker-nginx-centos works for me:
Here is the code from the Dockerfile
This works right out of the box, and I can see a default page on http://localhost
The only problem is that, it does not contain PHP-FPM and Mariadb.
4 Answers 4
Docker containers are designed to have a single service running within them, not be an entire virtual system (as you might see with virtual box and virtual machines).
This means ideally you want a single container for each:
Additionally the Centos docker image is designed as a base for others to inherit from, or to perform an OS specific task (for example cURL calls, or a shell) which is not really what you are needing.
I would recommend for your case, using docker-compose which will allow you to easily setup intermediate containers, and manage them all as one project.
I would recommend a docker-compose.yml file setup as such:
You would then have a /config/ folder in your project folder, which you’ll need a site.conf file for the nginx settings.
You will also need a /src/ folder in your project folder, which would contain all the php/web code for your project.
The volume mounts in the docker-compose.yml file will load those into the container for you. Volume mounts work by mapping host folder path : container folder path when something changes in one, it is updated in the other, almost as if copy/pasting. Keep in mind you may need to update file permissions.
For the Mariadb you could add another volume to map the data files in the container to your host folder. Additionally you can open the mysql port so you could interrogate the database with a tool like mysql workbench by adding a ports section for port 3306 as shown in the web section. The value for mysql_root_password will set the root user password.
You can start this up with the command docker-compose up from your project directory.
Let me know if you have any questions or if something is unclear I’d be happy to update my answer!
Развертывание WordPress с NGINX, PHP-FPM и MariaDB с помощью Docker Compose
Рассмотрим как развернуть WordPress с Nginx, PHP-FPM и MariaDB и PhpMyAdmin с помощью Docker Compose на компьютере с Ubuntu.
1. Подготовка хост-машины
Добавим докер в автоматический запуск при загрузке ОС:
2. Установка Docker-Compose
Docker-Compose доступен в репозитории, но его версии немного отстают от последней. Поэтому скачаем актуальную версию с GitHub
После завершения процесса проверьте установленную версию docker-compose:
3. Установка WordPress с nginx, PHP, MariaDB, PhpMyAdmin
В целях безопасности, мы не будем работать через root, а добавим существующего пользователя в группу docker и перезагрузим службу:
Создадим каталоги в которых будут хранится данные.
docker-compose.yml — это конфигурационный файл, в котором мы описываем какие контейнеры запускать, их настройки и связи между контейнерами.
— nginx/: каталог используемый для дополнительной конфигурации nginx, как виртуального хоста и т. д.
— logs/: каталог логов для nginx, mariadb и php.
— data/: каталог с файлами wordpress и файлы базы данных.
Далее в директории wordpress-compose/nginx создайте новый файл с конфигурацией nginx.
Вставьте следующее содержимое:
Сохраните файл и выйдите из редактора
4. Настройка Docker-Compose
Мы будем использовать Nginx последней версии. Настроим сопоставление портов для порта 8080 на хосте с портом 80 в контейнере. Настроим конфигурацию виртуального хоста Nginx, файлы журнала Nginx и корневой каталог веб-сервера /var/www/html. Также укажем что контейнер Nginx связан с контейнером WordPress.
Отредактируем файл docker-compose.yml:
Если вы копируете текст с сайта и вставляете в конфигурационный файл, убедитесь что форматирование не съехало и не появилось новых символов и пробелов, потому что из-за этого нарушается структура файла, что приводит к ошибкам.
Далее определим сервер MySQL, мы используем образ MariaDB последней версии. Назначим root пароль MySQL, имя базы данных, пользователя базы и его пароль. Для этого, вставьте в конфигурационный docker-compose.yml текст:
Теперь мы будем настраивать WordPress с помощью образа WordPress с PHP-FPM 7.4. Подключаем том Docker для директории /var/www/html в каталоге хоста WordPress, настроим базу данных, определив переменную среду WordPress, и свяжем WordPress с MySQL. Данные по настройке базы данных должны соответствовать предыдущей секции. Вставьте в конфигурационный docker-compose.yml текст:
Для управления СУБД прикручиваем phpmyadmin и на порт 8081:
После добавления составных частей в docker-compose.yml — файла, сохраните его и выйдите из редактора. Конфигурация docker-compose готова. У Вас должен получиться файл с таким содержимым:
5. Запуск docker-compose
Начнем создание новых контейнеров с docker-compose. Перейдите в каталог WordPress и запустите новые контейнеры на основании созданного нами файла.
Вы можете увидеть результаты выполнения команды. Были созданы четыре контейнера. Давайте проверим состояние контейнеров.
Если вы хотите увидеть вывод журнала из контейнера, вы можете использовать команды ниже:
6. Установка CMS WordPress
Теперь откройте веб-браузер и введите URL-адрес сервера или IP-адрес.
Вы должны увидеть страницу установки WordPress. Выберите свой язык и нажмите ‘продолжить’.
Если у Вас не открылась страница установки, посмотрите логи nginx, а также файл hosts на компьютере с которого вы пытаете открыть сайт.
Заполните детали, такие как: название сайта, имя пользователя, пароль, адрес электронной почты и нажмите кнопку ‘Установить WordPress’. Вы будете перенаправлены на панель администратора WordPress.

Также по адресу http://server_IP:8081/ доступен phpMyAdmin

WordPress установлен с помощью docker-compose.
7. Доступ в контейнеры docker
Чтобы убедиться, что все контейнеры доступны и проверить их состояние введите команду:
У нас уже 4 контейнера, теперь мы можем попытаться войти в каждый. Войдите в первый контейнер nginx с помощью команды docker-compose.
nginx – имя файла в Docker-Compose yml
bash – выполнение команды в оболочке bash.
Теперь проверим наши настройки виртуального хоста на WordPress.
Файл доступен в контейнере.
Далее попробуйте войти в контейнер MySQL, а затем в оболочку MySQL с помощью нашего пароля на файле.
Посмотреть список баз данных:
Вы увидите нашу базу данных WordPress.
В контейнере WordPress вы увидите все файлы CMS WordPress.







