Docker збирає все, що процес пише в stdout і stderr, і передає драйверу логування. Звідти логи бачить docker logs, їх забирають збирачі (Loki, Fluent Bit, Vector, CloudWatch) і оркестратори.
Чому не файли всередині контейнера:
- файл у записуваному шарі зникає разом з контейнером - саме тоді, коли логи потрібні, щоб зрозуміти, чому він упав;
- файл росте без обмежень і з'їдає диск;
- кожен сервіс пише в свій шлях, і збирати логи доводиться з десятка місць.
Laravel: канал stderr замість single/daily:
LOG_CHANNEL=stderr
Для PHP-FPM ще потрібно, щоб помилки воркерів потрапляли в stderr (catch_workers_output = yes, error_log = /proc/self/fd/2).
Структуровані логи. JSON-рядки замість тексту дозволяють збирачу індексувати поля: рівень, ID запиту, користувача, тривалість. Тоді пошук «усі помилки запиту X» - це запит, а не grep.
Ротація на хості. Драйвер за замовчуванням json-file не обмежує розмір, і логи балакучого контейнера можуть заповнити диск сервера. Налаштовують:
{
"log-driver": "local",
"log-opts": { "max-size": "20m", "max-file": "5" }
}
(у /etc/docker/daemon.json для всіх контейнерів або logging: у Compose для окремого сервісу).
Що ще варто: не логувати секрети й персональні дані; додавати ID запиту в усі записи, щоб пов'язати лог застосунку, проксі й воркера черги; мати окремий моніторинг помилок (Sentry), бо логи - для розслідування, а не для сповіщень.