- Настройка веб-сервера в Docker (NGINX + PHP + MariaDB)
- NGINX + PHP + PHP-FPM
- Создание образа
- Запуск контейнера и проверка работы
- MariaDB
- Подключение к базе из веб-сервера
- Использование docker-compose
- Возможные проблемы
- 1. Errors during downloading metadata for repository ‘AppStream’
- Get Ubuntu Server
- Alternative downloads
- BitTorrents
- Ubuntu Server 20.04 LTS
- Other versions
- Alternative architectures
- Ubuntu Server for ARM
- Ubuntu for POWER
- Ubuntu for IBM Z (s390x)
- Ubuntu for RISC-V
- Installation guides
- Ubuntu Server guide
- Helping hands
Настройка веб-сервера в Docker (NGINX + PHP + MariaDB)
Обновлено: 19.10.2021 Опубликовано: 27.11.2020
- В качестве веб-сервера будет использоваться NGINX.
- Будет поддержка приложений на PHP.
- Мы создадим 2 контейнера Docker — один для NGINX + PHP, второй для СУБД (MariaDB).
- Веб-приложение будет зашито в контейнере. Раздел для данных MariaDB будет монтироваться в качестве volume.
Данную конфигурацию можно использовать для быстрого развертывания сайтов или для локальной разработки.
Мы будем работать в системе на базе Linux. Предполагается, что Docker уже установлен.
NGINX + PHP + PHP-FPM
Рекомендуется каждый микросервис помещать в свой отдельный контейнер, но мы (для отдельного примера) веб-сервер с интерпретатором PHP поместим в один и тот же имидж, на основе которого будут создаваться контейнеры.
Создание образа
Создадим каталог, в котором будут находиться файлы для сборки образа веб-сервера:
mkdir -p /opt/docker/web-server
Переходим в созданный каталог:
- FROM centos:8
- MAINTAINER Dmitriy Mosk
- ENV TZ=Europe/Moscow
- RUN dnf update -y
- RUN dnf install -y nginx php php-fpm php-mysqli
- RUN dnf clean all
- RUN echo «daemon off;» >> /etc/nginx/nginx.conf
- RUN mkdir /run/php-fpm
- COPY ./html/ /usr/share/nginx/html/
- CMD php-fpm -D ; nginx
- EXPOSE 80
* где:
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:
* мы создали скрипт, который будет выводить информацию о php в браузере для примера. По идее, в данную папку мы должны положить сайт (веб-приложение).
Создаем первый билд для нашего образа:
docker build -t dmosk/webapp:v1 .
Новый образ должен появиться в системе:
При желании, его можно отправить на Docker Hub следующими командами:
docker login —username dmosk
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 — сам тег. Последняя команда заливает образ в репозиторий.
* подробнее про загрузку образа в репозиторий докера.
Запуск контейнера и проверка работы
Запускаем веб-сервер из созданного образа:
docker run —name web_server -d -p 80:80 dmosk/webapp:v1
Открываем браузер и переходим по адресу http:// — откроется страница phpinfo:
Наш веб-сервер из Docker работает.
MariaDB
Для запуска СУБД мы будем использовать готовый образ mariadb. Так как после остановки контейнера, все данные внутри него удаляются, мы должны подключить внешний том, на котором будут храниться наши базы.
Сначала создаем том для докера:
docker volume create —name mariadb
* в данном примере мы создали том с именем mariadb. Будет создан каталог /var/lib/docker/volumes/mariadb/_data/ на хостовом сервере, куда будут размещаться наши файлы базы.
Выполним первый запуск нашего контейнера с mariadb:
docker run —rm —name maria_db -d -e MYSQL_ROOT_PASSWORD=password -v mariadb:/var/lib/mysql mariadb
- —rm — удалить контейнер после остановки. Это первый запуск для инициализации базы, после параметры запуска контейнера будут другими.
- —name maria_db — задаем имя контейнеру, по которому будем к нему обращаться.
- -e MYSQL_ROOT_PASSWORD=password — создаем системную переменную, содержащую пароль для пользователя root базы данных. Оставляем его таким, как в данной инструкции, так как следующим шагом мы его будем менять.
- -v mariadb:/var/lib/mysql — говорим, что для контейнера мы хотим использовать том mariadb, который будет примонтирован внутри контейнера по пути /var/lib/mysql.
- mariadb — в самом конце мы указываем имя образа, который нужно использовать для запуска контейнера. Это образ, который при первом запуске будет скачан с DockerHub.
В каталоге тома должны появиться файлы базы данных. В этом можно убедиться командой:
Теперь подключаемся к командной строке внутри контейнера с сервером базы данных:
docker exec -it maria_db /bin/bash
Меняем пароль для учетной записи root:
> SET PASSWORD FOR ‘root’@’localhost’ = PASSWORD(‘New_Password’);
Выходим из командной строки СУБД:
Останавливаем сам контейнер — он нам больше не нужен с данными параметрами запуска:
И запускаем его по новой, но уже без системной переменной с паролем и необходимостью его удаления после остановки:
docker run —name maria_db -d -v mariadb:/var/lib/mysql mariadb
Сервер баз данных готов к работе.
Подключение к базе из веб-сервера
По отдельности, наши серверы готовы к работе. Теперь настроим их таким образом, чтобы из веб-сервера можно было подключиться к СУБД.
Зайдем в контейнер с базой данных:
docker exec -it maria_db /bin/bash
Создадим базу данных, если таковой еще нет:
> 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
Создаем новые контейнеры из наших образов и добавляем опцию —net, которая указывает, какую сеть будет использовать контейнер:
docker run —name maria_db —net net1 -d -v mariadb:/var/lib/mysql mariadb
docker run —name web_server —net net1 -d -p 80:80 dmosk/webapp:v1
* указав опцию —net, наши контейнеры начинают видеть друг друга по своим именам, которые мы задаем опцией —name.
Готово. Для проверки соединения с базой данных в php мы можем использовать такой скрипт:
ini_set(«display_startup_errors», 1);
ini_set(«display_errors», 1);
ini_set(«html_errors», 1);
ini_set(«log_errors», 1);
error_reporting(E_ERROR | E_PARSE | E_WARNING);
$con = mysqli_connect(‘maria_db’, ‘docker_db_user’, ‘docker_db_password’, ‘docker_db’);
* в данном примере мы подключаемся к базе docker_db на сервере maria_db с использованием учетной записи docker_db_user и паролем docker_db_password.
После его запуска, мы увидим либо пустой вывод (если подключение выполнено успешно), либо ошибку.
Использование docker-compose
В отличие от docker, с помощью docker-compose можно разворачивать проекты, состоящие из нескольких контейнеров, одной командой.
И так, автоматизируем запуск наших контейнеров с использованием docker-compose. Необходимо, чтобы он был установлен в системе.
Сначала удалим контейнеры, которые создали на предыдущих этапах:
docker rm -f web_server maria_db
Переходим в каталог для наших сборок:
Создаем yml-файл с инструкциями сборки контейнеров через docker-compose:
web_server:
build:
context: ./web-server/
args:
buildno: 1
container_name: web_server
restart: always
environment:
TZ: «Europe/Moscow»
ports:
— 80:80
maria_db:
image: mariadb
container_name: maria_db
restart: always
environment:
TZ: «Europe/Moscow»
volumes:
— /var/lib/docker/volumes/mariadb/_data/:/var/lib/mysql
* в формате yml очень важное значение имеют отступы. Если сделать лишний пробел, то мы получим ошибку.
* где:
- version — версия файла yml. На странице docs.docker.com представлена таблица, позволяющая понять, какую версию лучше использовать, в зависимости от версии docker (docker -v).
- services — docker-compose оперирует сервисами, где для каждого создается свой блок описания. Все эти блоки входят в раздел services.
- build — опции сборки. В нашем примере для веб-сервера мы должны собрать имидж.
- context — указываем путь до Dockerfile.
- args — позволяет задать аргументы, которые доступны только в процессе сборки. В данном примере мы используем только аргумент с указанием номера сборки.
- container_name — задаем имя, которое будет задано контейнеру после его запуска.
- restart — режим перезапуска. В нашем случае всегда, таким образом, после перезагрузки сервера, наши контейнеры запустятся.
- ports — при необходимости, указываем порт, который будет наш сервер пробрасывать запрос внутрь контейнера.
- environment — задает системные переменные. В данном примере, временную зону.
- volumes — позволяет внутрь контейнера прокинуть каталог сервера. Таким образом, важные данные не будут являться частью контейнера и не будут удалены после его остановки.
Запускаем сборку наших контейнеров с помощью docker-compose:
Запускаем контейнеры в режиме демона:
Проверяем, какие контейнеры запущены:
При внесении изменений можно перезапускать контейнеры командой:
docker-compose up —force-recreate —build -d
Просто пересоздать контейнеры:
или только для одного из сервисов:
docker-compose restart web_server
* где web_server — название сервиса в файле 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 решает проблему. Открываем файл:
Get Ubuntu Server
The latest version of Ubuntu Server, including nine months of security and maintenance updates, until January 2024.
Alternative downloads
BitTorrents
BitTorrent sometimes enables higher download speeds and more reliable downloads of large files.
Ubuntu Server 20.04 LTS
The previous long-term support version of Ubuntu Server, including support guaranteed until April 2025.
Other versions
Other versions of Ubuntu Server including torrents, the network installer, a list of local mirrors and past releases.
Alternative architectures
Ubuntu Server for ARM
Optimised for hyperscale deployments and certified on ARM chipsets — Ubuntu Server for ARM includes the 64-bit ARMv7 and ARMv8 platforms.
Ubuntu for POWER
Ubuntu is available on the IBM POWER platform, bringing the entire Ubuntu ecosystem to IBM POWER.
Ubuntu for IBM Z (s390x)
IBM Z and LinuxONE leverage open technology solutions to meet the demands of the new application economy. Ubuntu is now available on those platforms with Multipass, MicroK8s and more.
Ubuntu for RISC-V
Ubuntu — now available for multiple RISC-V platforms to accelerate innovation.
Installation guides
If you need some help installing Ubuntu, please check out our step-by-step guides.
Ubuntu Server guide
Read the official Ubuntu Server 22.04 LTS documentation.
Helping hands
If you get stuck, help is always at hand.
© 2023 Canonical Ltd. Ubuntu and Canonical are registered trademarks of Canonical Ltd.