Рекомендація Docker - один основний процес на контейнер, а різні відповідальності - окремі контейнери, що взаємодіють через мережу й томи:
services:
web: # Nginx
app: # PHP-FPM
queue: # php artisan queue:work
scheduler: # php artisan schedule:work
Чому окремі контейнери кращі:
- незалежне масштабування: воркерів черги може бути п'ять, а вебконтейнерів два;
- окремі ресурси й ліміти: воркер, що обробляє відео, не з'їсть пам'ять вебзапитів;
- ізольовані перезапуски й деплой: падіння воркера не вбиває веб;
- логи й стан кожного процесу окремо, зрозумілий
docker psі healthcheck; - PID 1 - сам процес, тож сигнали зупинки доходять напряму.
Той самий образ - різні команди. Не потрібно чотири образи: один образ застосунку, а контейнери відрізняються command:
x-app: &app
image: myapp:${TAG}
env_file: .env
services:
app: { <<: *app }
queue: { <<: *app, command: php artisan queue:work --max-jobs=1000 }
scheduler: { <<: *app, command: php artisan schedule:work }
Коли кілька процесів в одному контейнері виправдані:
- тісно пов'язані процеси, що мають жити й масштабуватися разом: Nginx + PHP-FPM у одному «вебконтейнері» - поширений і прийнятний компроміс;
- середовища, що дають лише один контейнер (деякі PaaS);
- сайдкар-процеси, без яких основний не працює.
Як робити це правильно:
- менеджер процесів у PID 1 -
supervisord,s6-overlay,tini+ скрипт. Він запускає процеси, перезапускає впалі й передає сигнали зупинки всім; - вивід усіх процесів у
stdout/stderrконтейнера; - визначитися, що робити при падінні одного процесу: перезапустити лише його чи завершити весь контейнер (щоб оркестратор побачив проблему). Тихий перезапуск ховає помилки.
Сучасна альтернатива для Laravel: FrankenPHP поєднує веб-сервер і PHP в одному процесі - зв'язка Nginx + PHP-FPM стає непотрібною, і «вебконтейнер» знову має один процес.
Антипатерн: запускати в одному контейнері ще й базу чи Redis «для простоти» - дані, оновлення й масштабування бази стають залежними від деплою застосунку.
Докладніше в документації: Docker: кілька сервісів у контейнері