Docker Compose: быстрый способ развернуть стек Nginx + PHP + MySQL.
Docker Compose — это инструмент, который позволяет описывать и запускать целые проекты с несколькими контейнерами через один YAML-файл. В этой статье разберём два способа развёртывания простого веб-стека:
- Через обычный shell-скрипт с использованием
docker run - Через
docker-compose.yaml— более удобный и современный способ
1. Проект через Shell-Script
Начнём с классического подхода: создадим необходимые директории, сконфигурируем Nginx, соберём PHP-FPM и запустим все контейнеры вручную.
#!/bin/bash
mkdir -p mysql-data www images/php && docker network create --driver bridge dockernet1
# Конфиг для Nginx (ручной режим)
echo 'server {
listen 80;
root /var/www/public_html;
index index.php index.html index.htm;
server_name localhost devopz.tech www.devopz.tech;
location ~ \.php$ {
fastcgi_pass fpm71:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}' > www/nginx.conf
# Конфиг для Nginx (вариант для Compose)
echo 'server {
listen 80;
root /var/www/public_html;
index index.php index.html index.htm;
server_name localhost devopz.tech www.devopz.tech;
location ~ \.php$ {
fastcgi_pass compose-fpm71:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}' > www/compos.cnf
# Простой PHP-скрипт для проверки подключения к MySQL
echo "<?php
$user = 'root';
$pass = 'root';
$dsn = 'mysql:host=mysql1;dbname=information_schema;charset=utf8';
$pdo = new PDO(\$dsn, \$user, \$pass);
\$stmt = \$pdo->query('select * from tables');
\$row = \$stmt->fetch();
print_r(\$row);" > www/index.php
# Dockerfile для PHP-FPM
mkdir -p images/fpm71
echo 'FROM php:7.1-fpm
RUN apt update && apt install -y curl git && docker-php-ext-install pdo pdo_mysql
WORKDIR /var/www/public_html
ENTRYPOINT ["php-fpm"]' > images/fpm71/Dockerfile
# Сборка и запуск контейнеров вручную
docker build -t php71fpm images/fpm71
docker run -d -v ./www:/var/www/public_html --network dockernet1 --name fpm71 php71fpm
docker run -d -p 80:80 -v ./www/nginx.conf:/etc/nginx/conf.d/default.conf -v ./www:/var/www/public_html --network dockernet1 --name nginx1 nginx
docker run -d -v ./mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --network dockernet1 --name mysql1 mysql
docker run -d -p 81:80 -e PMA_HOST=mysql1 --network dockernet1 --name phpmyadmin1 phpmyadmin
sleep 10 && docker ps -a
После выполнения скрипта вы получите рабочий стек:
- Nginx —
http://localhost:80 - PHP-FPM — собран из кастомного Dockerfile
- MySQL — с паролем root/root
- phpMyAdmin — доступен на порту
81
2. Проект через docker-compose.yaml
Теперь сделаем то же самое, но в одном YAML-файле. Это гораздо удобнее и поддерживается командой docker compose up -d.
networks:
dockernet:
name: dockernet
services:
nginx:
container_name: compose-nginx
image: nginx:latest
ports:
- 80:80
volumes:
- ./www/compos.cnf:/etc/nginx/conf.d/default.conf
- ./www:/var/www/public_html
networks:
- dockernet
depends_on:
- php
- mysql
php:
container_name: compose-fpm71
build: ./images/fpm71
volumes:
- ./www:/var/www/public_html
networks:
- dockernet
mysql:
container_name: compose-mysql
image: mysql:latest
volumes:
- ./mysql-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=root
networks:
- dockernet
phpmyadmin:
container_name: compose-admin
image: phpmyadmin:latest
ports:
- 82:80
environment:
- PMA_HOST=compose-mysql
networks:
- dockernet
Запуск всего стека:
docker compose up -d
Теперь вы можете изменять конфиги и код без пересборки контейнеров — docker-compose сам всё подхватит при рестарте.
3. Dockerfile — основные инструкции
Dockerfile — это рецепт сборки образа. Вот краткий список ключевых команд:
- FROM — базовый образ.
- LABEL — метаданные образа (автор, версия и т.д.).
- ENV — переменные среды.
- RUN — выполнение команд при сборке.
- COPY — копирование файлов в образ.
- ADD — как COPY, но умеет распаковывать архивы.
- CMD — команда, выполняемая при запуске контейнера.
- WORKDIR — рабочая директория для следующих команд.
- ARG — переменные сборки.
- ENTRYPOINT — основная команда контейнера (не переопределяется).
- EXPOSE — объявление портов.
- VOLUME — точки монтирования.
# Пример: создание Dockerfile и переход в директорию
mkdir dockerproject && cd dockerproject && nano Dockerfile
4. Docker Compose — Чеклист команд
Ниже — короткая шпаргалка по самым нужным командам Docker Compose:
# Запуск всех сервисов в фоне
docker compose up -d
# Остановка всех контейнеров проекта
docker compose down
# Просмотр логов всех сервисов
docker compose logs -f
# Пересборка образов и перезапуск контейнеров
docker compose up -d --build
# Проверка списка работающих контейнеров
docker compose ps
# Просмотр списка сервисов и их состояния
docker compose top
# Выполнить команду внутри контейнера
docker compose exec SERVICE_NAME bash
# Проверка конфигурации файла docker-compose.yaml
docker compose config
Вывод
Shell-скрипт подходит для быстрых экспериментов и ручного управления контейнерами.
Docker Compose удобен для реальных проектов: легко масштабируется, читается и разворачивается одной командой.
5. Volumes — постоянные данные вне контейнера
По умолчанию, всё, что находится внутри контейнера, — временное. При удалении контейнера данные исчезают. Чтобы сохранять данные между перезапусками, используют volumes.
Виды Volume
| Тип | Пример | Особенности |
|---|---|---|
| Анонимный | VOLUME /var/lib/mysql |
Docker сам создаёт volume без имени. Живёт, пока его не очистят вручную. |
| Именованный | volumes: - dbdata:/var/lib/mysql |
Можно использовать повторно в разных контейнерах. Управляется через Docker CLI. |
| Bind Mount | volumes: - ./www:/var/www/html |
Монтирует локальную папку хоста. Удобно для разработки, но требует аккуратности в проде. |
Пример в docker-compose.yaml
volumes:
dbdata:
services:
mysql:
image: mysql:8
container_name: mysql-prod
environment:
- MYSQL_ROOT_PASSWORD=supersecret
volumes:
- dbdata:/var/lib/mysql
app:
build: ./images/php
volumes:
- ./src:/var/www/html # bind mount для кода
depends_on:
- mysql
Советы по Volume
- Для баз данных и конфигов — используй именованные volume.
- Для локальной разработки — bind mount удобен, но в продакшене лучше собирать код в образ.
- Очищай неиспользуемые volume:
docker volume prune
6. Secrets — безопасное хранение паролей и токенов
Жёстко прописывать пароли в docker-compose.yaml ❌ — плохая идея. Есть несколько способов передавать секреты безопасно:
.env файл
# .env
MYSQL_ROOT_PASSWORD=supersecret
PMA_PASSWORD=adminpass
# docker-compose.yaml
services:
mysql:
image: mysql:8
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
.env не коммитим в Git (добавляем в .gitignore).
Docker Secrets (Swarm / Compose v3.5+)
# Создание секрета
echo "supersecret" | docker secret create mysql_root_password -
# docker-compose.yaml
version: '3.8'
services:
mysql:
image: mysql:8
secrets:
- mysql_root_password
secrets:
mysql_root_password:
external: true
Секрет монтируется в контейнер как файл в `/run/secrets/...`, а не как переменная среды ✅
HashiCorp Vault или внешние Secret Manager
Для продакшена на k8s или сложных проектах удобно подключать HashiCorp Vault, AWS Secrets Manager, Google Secret Manager и т.д. Vault позволяет ротацию ключей, политки доступа и логирование, а не просто хранение паролей в файлах.
# Пример (через Vault CLI)
vault kv put secret/mysql root_password=supersecret
Далее контейнеры могут получать секреты через entrypoint-скрипты, sidecar или init-контейнеры.
7. Best Practices для продакшена
- Multi-stage builds — собирай код и зависимости в одном этапе, а финальный образ делай максимально лёгким.
# Stage 1 — Build
FROM composer:2 as builder
WORKDIR /app
COPY . .
RUN composer install --no-dev --optimize-autoloader
# Stage 2 — Runtime
FROM php:8.2-fpm
WORKDIR /var/www/html
COPY --from=builder /app ./
- Минимизируй количество слоёв в Dockerfile — объединяй RUN команды.
- Никогда не храни пароли в git, даже в приватных репозиториях.
- Не запускай процессы от root внутри контейнера — используй
USER. - Храни конфиги отдельно от кода (12-Factor App), используй переменные окружения или volume.
- Чисти временные файлы и кэш в RUN инструкциях, чтобы не раздувать образ.
- Мониторь контейнеры: логирование (Filebeat, Loki), метрики (Prometheus), алерты.
- Регулярно обновляй образы базовых контейнеров и зависимости.
- Версионируй образы (tag'и), не используй
:latestв продакшене.
Вывод
Volumes обеспечивают постоянство данных. Secrets — защищённое хранение конфиденциальных параметров. Best practices делают твой стек безопасным, предсказуемым и оптимальным для CI/CD и продакшена.
Следующий шаг — оркестрация через Kubernetes или Docker Swarm