В предыдущих статьях мы научились выполнять отдельные задачи: запускать контейнеры, использовать Dockerfile и связывать контейнеры по сети.
Сегодня мы объедим все эти знания и создадим рабочее окружение для сайта с помощью Docker.
- Шаг 1. Создаем структуру проекта
- Шаг 2. Создаем docker-compose.yml и Dockerfile
- Шаг 3. Настраиваем php.ini (опционально)
- Шаг 4. Создаем конфигурацию NGINX
- Шаг 5. Загружаем файлы сайта
- Шаг 6. Настройка соединения с базой данных
- Шаг 7. Запуск контейнеров
- Шаг 8. Проверка сайта
В качестве примера сайта будем использовать популярную CMS WordPress. Для WordPress существует готовый образ, но мы не будем его использовать, так как наша цель сделать окружение для запуска любого сайта работающего на php.
В отличие от использования готового образа WordPress, мы создадим контейнеры с чистым PHP, Web-сервером и базой данных. Сами скачаем и установим WordPress внутри этого контейнера. Такой подход поможет понять, как работают PHP-приложения и как их запускать в Docker.
В ходе выполнения практического примера, мы будем опираться на знания, полученные из предыдущих статей. Если на данном этапе, какой то аспект остается для вас неизвестным, обратитесь к соответствующей статье:
- Docker контейнеры
- Docker образы и Dockerfile
- Docker compose
- Монтирование томов в Docker
- Настройка сетей в Docker
- Стек LEMP
- Установка WordPress
Шаг 1. Создаем структуру проекта
Любой, даже небольшой проект, должен быть правильно организован. Для начала подготовим директорию:
[root@waky ~]# mkdir my_site
[root@waky ~]# cd my_site
[root@waky my_site]#
Здесь мы будем хранить все файлы проекта. Добавим поддиректории, которые будут хранить данные отдельных контейнеров:
[root@waky my_site]# mkdir db_files
[root@waky my_site]# mkdir site_files
[root@waky my_site]# mkdir php_files
[root@waky my_site]# mkdir nginx_files
[root@waky my_site]#
Шаг 2. Создаем docker-compose.yml и Dockerfile
Создадим файл docker-compose.yml со следующим содержимым:
services:
db:
image: mariadb:11.4
container_name: mariadb_container
restart: always
environment:
MYSQL_ROOT_PASSWORD: your_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wp_user
MYSQL_PASSWORD: wp_password
networks:
- my_site_network
volumes:
- ./db_files:/var/lib/mysql
php-fpm:
build: ./PHP-FPM
container_name: php_container
restart: always
networks:
- my_site_network
depends_on:
- db
volumes:
- ./site_files:/var/www/html
- ./php_files/php.ini:/usr/local/etc/php/php.ini
tty: true
nginx:
image: nginx:1.29
container_name: nginx_container
restart: always
networks:
- my_site_network
ports:
- "80:80"
volumes:
- ./nginx_files/default.conf:/etc/nginx/conf.d/default.conf
- ./site_files:/var/www/html
depends_on:
- php-fpm
networks:
my_site_network:
driver: bridge
Здесь мы создаем:
- контейнер с MariaDB — базу данных для WordPress.
- контейнер с PHP, который будет обрабатывать динамические страницы сайта, его мы создадим с помощью Dockerfile.
- контейнер с Nginx —веб-сервер, который будет обслуживать сайт.
Подключаем все контейнеры к одной сети. Задаем монтирование директорий и файлов контейнеров в директорию нашего проекта, чтобы иметь возможность редактировать настройки сервисов и сохранять изменения данных.
Создадим отдельную директорию PHP-FPM:
[root@waky my_site]# mkdir PHP-FPM
[root@waky my_site]# touch PHP-FPM/Dockerfile
[root@waky my_site]#
А в ней Dockerfile следующего содержания:
FROM php:8.3-fpm
RUN apt-get update && docker-php-ext-install -j$(nproc) mysqli
Для работы модулей и плагинов сайты используют разные расширения php. WordPress так же имеет рекомендуемый набор расширений, но одно является необходимым – mysqli. Это расширение используется для работы с базой данных.
Обычно дополнительные программы и расширения в контейнер устанавливаются с помощью пакетного менеджера, но данный поставщик рекомендует в рамках своего образа использовать docker-php-ext-install.
Обратите внимание, что указаны конкретные версии образов вместо latest. Это убережет вас от неожиданностей в случае смены последней версии образа. В серьезных проектах безопаснее использовать фиксированную версию и обновлять используемые образы запланировано и контролировано.
Второй момент, который следует учитывать, что мы транслируем 80 порт контейнер с NGINX на порт хоста, это значит, что на самом хосте этот порт должен быть свободен.
Шаг 3. Настраиваем php.ini (опционально)
Мы должны иметь возможность менять параметры PHP. Создадим файл ./php_files/php.ini в соответствующей поддиректории:
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
max_execution_time = 180
Реальные параметры могут варьироваться в зависимости от сайта.
Шаг 4. Создаем конфигурацию NGINX
Теперь подготовим настройки NGINX. Создадим файл ./nginx_files/default.conf со следующим содержимым:
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
Этот конфиг обеспечит работу PHP-страниц через NGINX. Это максимально упрощенный вариант, для реального сайта его нужно дополнить 443 портом, используемыми доменными именами, сертификатами и прочим.
Шаг 5. Загружаем файлы сайта
Перейдем в поддиректорию site_files/. Скачаем архив с WordPress и распакуем его:
[root@waky site_files]# cd site_files/
[root@waky site_files]# curl -O https://ru.wordpress.org/latest-ru_RU.zip
[root@waky site_files]# unzip latest-ru_RU.zip
[root@waky site_files]# mv wordpress/* ./ && rm -rf latest-ru_RU.zip wordpress
[root@waky site_files]#
Теперь в папке site_files находятся файлы WordPress.
Шаг 6. Настройка соединения с базой данных
В директории есть файл wp-config-sample.php – cкопируем его с названием wp-config.php:
[root@waky site_files]# cp -a wp-config-sample.php wp-config.php
[root@waky site_files]#
Отредактируем полученный файл. В файле wp-config.php найдите параметры подключения к базе данных и замените на те, которые использовались в docker-compose.yml:
define('DB_NAME', 'wordpress');
define('DB_USER', 'wp_user');
define('DB_PASSWORD', 'wp_password');
define('DB_HOST', 'db:3306');
Шаг 7. Запуск контейнеров
Вернемся в основную директорию проекта и выполним команду docker compose:
[root@waky site_files]# cd ..
[root@waky my_site]# docker compose up -d
[+] Building 0.8s (8/8) FINISHED
=> [internal] load local bake definitions
0.0s
=> => reading from stdin 499B
0.0s
=> [internal] load build definition from Dockerfile
0.1s
=> => transferring dockerfile: 177B
0.0s
=> [internal] load metadata for docker.io/library/php:8.3-fpm
0.0s
=> [internal] load .dockerignore
0.1s
=> => transferring context: 2B
0.0s
=> [1/2] FROM docker.io/library/php:8.3-fpm
0.0s
=> CACHED [2/2] RUN apt-get update && docker-php-ext-install -j$(nproc) mysqli
0.0s
=> exporting to image
0.1s
=> => exporting layers
0.0s
=> => writing image sha256:bf988a478410efca868e23e851594d6ff1892f12f3d80389347c31f7846b0526
0.0s
=> => naming to docker.io/library/my_site-php-fpm
0.0s
=> resolving provenance for metadata file
0.0s
[+] Running 5/5
✔ my_site-php-fpm Built
0.0s
✔ Network my_site_my_site_network Created
0.6s
✔ Container mariadb_container Started
1.1s
✔ Container php_container Started
1.8s
✔ Container nginx_container Started
3.0s
[root@waky my_site]#
Это скачает все необходимые образы, создаст образ из Dockerfile, создаст контейнеры и запустит их.
Проверим, что все три контейнера работают:
[root@waky my_site]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4ffd28bbfea4 nginx:1.29 "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp, [::]:80->80/tcp nginx_container
1c4edc78c3b6 my_site-php-fpm "docker-php-entrypoi…" 4 minutes ago Up 4 minutes 9000/tcp php_container
18a495ca56a6 mariadb:11.4 "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 3306/tcp mariadb_container
[root@waky my_site]#
Шаг 8. Проверка сайта
После запуска контейнеров зайдите на сайт в браузер по адресу http://localhost. Если вы настраивали NGINX на работу с доменом или IP адресом используйте их. Вы должны увидеть интерфейс установки WordPress.

Следуйте инструкциям на экране для завершения первичной настройки. После этого у вас будет сайт, использующий стек LEMP, только каждый сервис запущен в отдельном контейнере.
Заключение
Теперь у вас есть рабочий окружение для запуска PHP сайта, в котором все компоненты — веб-сервер, PHP и база данных — работают в отдельных контейнерах Docker.
В качестве примера мы установили WordPress вручную, скачивая файлы и настраивая соединение с базой данных.
Рассмотренный пример подходит для любых проектов на PHP — от CMS до собственных приложений. Вы можете легко адаптировать его для своих нужд, добавляя свои файлы, конфигурации и расширения.