Ожидание базы в Docker
Ожидание базы пускает сайт только после того, как сервер ответил на проверку, а не сразу после старта процесса. Контейнер MySQL может уже работать, но ещё не принимать клиентов - страница с PDO в этот момент падает или отдаёт пустой ответ.
Простой depends_on
лишь задаёт порядок:
PHP стартует после
запуска процесса db,
но готовность не ждёт.
Условие service_healthy
откладывает app,
пока проверка здоровья
не отметит успех.
Сервис db
получает healthcheck
с mysqladmin ping
и паузой 5 секунд.
Образ PHP
и связка с nginx
те же, что при запросе PDO.
Шаблон Dockerfile:
FROM php:8.5-fpm
RUN docker-php-ext-install pdo_mysql
Файл compose.yaml
с проверкой здоровья:
services:
web:
image: nginx
ports:
- "8080:80"
volumes:
- ./site:/var/www/html
- ./default.conf:/etc/nginx/conf.d/default.conf
app:
build: .
environment:
DB_HOST: db
DB_NAME: app
DB_USER: app
DB_PASSWORD: demo
volumes:
- ./site:/var/www/html
depends_on:
db:
condition: service_healthy
db:
image: mysql:9.7
environment:
MYSQL_ROOT_PASSWORD: demo
MYSQL_DATABASE: app
MYSQL_USER: app
MYSQL_PASSWORD: demo
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 10
Конфиг nginx
на порту 8080
с общей папкой сайта:
server {
listen 80;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Сценарий читает
поле body
через PDO:
<?php
$dsn = 'mysql:host=' . getenv('DB_HOST') . ';dbname=' . getenv('DB_NAME');
$pdo = new PDO($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'));
$row = $pdo->query('SELECT body FROM notes LIMIT 1')->fetch(PDO::FETCH_ASSOC);
echo $row['body'];
Таблицу notes
со словом hello
создают командой клиента
после подъёма.
Подъём проекта:
docker compose up -d --build
docker compose exec db mysql -uapp -pdemo app -e "CREATE TABLE IF NOT EXISTS notes (id INT PRIMARY KEY AUTO_INCREMENT, body VARCHAR(255)); INSERT INTO notes (body) VALUES ('hello');"
Первое открытие
localhost:8080
чаще сразу показывает hello,
потому что FPM
не стартовал раньше
успешной проверки db.
Список сервисов
покажет здоровье базы
перед тем, как app
перейдёт в работу.
Добавьте проверку готовности сервису db с паузой 3 секунды и свяжите php с условием здоровья, а не только с порядком запуска.
Поднимите проект в фоне и отметьте в списке сервисов, что PHP стартовал после успешной проверки базы.