Если вы разворачиваете контейнеры на VDS, вопрос логов рано или поздно становится критичным: их нужно быстро читать, хранить ровно столько, сколько надо по политике, не терять при нагрузочных всплесках и не забивать диск. В Docker есть три де-факто популярных маршрута: базовый json-file, системный journald и «облачный» стек с Loki (через драйвер или агент Promtail). Ниже — практичный разбор без идеологических войн: как устроено, где узкие места, что быстрее, что надежнее и какие пресеты подойдут для обычного VDS.
Как Docker пишет логи: краткая механика
Любой контейнер пишет в stdout/stderr. Docker Runtime принимает эти потоки и передает их выбранному logging driver. Драйвер решает, куда оседают записи: в файл, в systemd-journald, по сети в агрегатор и т.п.
Есть важная деталь: режим блокировки. По умолчанию логирование может быть блокирующим (контейнер ждет, пока драйвер запишет строку) либо «non-blocking» с кольцевым буфером. Блокировка дает меньше потерь, но в пиках может замедлить приложение; неблокирующий режим позволяет приложению лететь вперед, но риск дропа строк при переполнении буфера реален.
json-file: просто и быстро (по умолчанию)
json-file — стандартный драйвер Docker. Он пишет одну запись лога на строку в JSON, например {"log":"...","stream":"stdout","time":"..."}, в файлы вида /var/lib/docker/containers/<id>/<id>-json.log. Выглядит прозаично, но на практике это самое предсказуемое и быстрое решение на одиночном VDS.
Плюсы
- Минимальные накладные расходы: запись идет локально, без системной очереди или сетевых hop'ов.
- Простая ротация по размеру per-container:
max-size,max-file, опциональноcompress. - Совместимость с большинством агентов: легко «подхватить» файлы с Promtail/Fluent Bit и отправить в централизованное хранилище.
- Диагностика без дополнительных инструментов:
docker logsвсегда работает предсказуемо.
Минусы
- Диск — узкое место: интенсивный поток логов создает IOPS и увеличивает фрагментацию. На недорогих SSD VDS это может конкурировать с БД и кэшем.
- Ротация только по размеру, не по времени; «исторические» файлы сохраняются по количеству (например, 5 штук), но не по дням.
- Многострочные логи (stacktrace) — одна запись на строку. Склейка делается уже на стороне коллектора (Promtail pipelines, Fluent Bit parsers).
- В режиме
non-blockingпри переполнении буфера строки могут теряться.
Практические пресеты для VDS
На компактном VDS (1–2 vCPU, 2–4 ГБ RAM) для большинства web-приложений хорошо заходят параметры ниже. Они ограничивают рост файлов, включают компрессию и снижают риск стопора приложения.
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5",
"compress": "true",
"mode": "non-blocking",
"max-buffer-size": "8m",
"tag": "{{.Name}}"
}
}
Пояснения:
max-sizeиmax-fileограничивают общий объем per-container (в примере примерно до 50–60 МБ с учетом компрессии).mode=non-blockingи увеличенныйmax-buffer-sizeуменьшают шанс «подвесить» приложение из-за медленного диска. Цена — возможная потеря строк при бурстах, если коллектор не успевает.tagупрощает навигацию в аггрегаторе и вdocker logs.
journald: единый журнал узла
Драйвер journald кладет записи контейнеров в системный журнал systemd. У каждой записи появляются знакомые поля: CONTAINER_ID, CONTAINER_NAME, SYSLOG_IDENTIFIER и т.д. Дальше логи можно смотреть через journalctl, настраивать ротацию и форвардинг.
Плюсы
- Единое место логов на узле: системные демоны и контейнеры видны вместе, удобно для аудита и корреляции событий.
- Гибкая ротация и квоты на уровне journald:
SystemMaxUse,RuntimeMaxUse,MaxRetentionSec, компрессия, защита от переполнения. - Встроенный rate limit, чтобы шумные сервисы не выжигали диск и CPU в пиках.
- Нет разрозненных файлов по контейнерам — меньше «мусора» в
/var/lib/docker.
Минусы
- Зависимость от
systemd: в минималистичных окружениях или rootless Docker это либо недоступно, либо неудобно. - Ротация — глобальная для узла: отдельные контейнеры нельзя ограничить по-разному, как в
json-file. - Исторически встречались претензии к устойчивости при внезапном power loss (журнал восстанавливается, но риск повреждения сегмента был темой багфиксов). На современных версиях системный журнал достаточно надежен, но бэкап и форвардинг все равно желательны.
- Чтобы отправлять в централизованное хранилище, почти всегда все равно нужен агент (Promtail/rsyslog/fluent-bit).
Рекомендуемая настройка journald
[Journal]
Storage=persistent
SystemMaxUse=1G
RuntimeMaxUse=256M
MaxRetentionSec=7day
Compress=yes
Seal=yes
RateLimitIntervalSec=30s
RateLimitBurst=10000
И переключение Docker на journald:
{
"log-driver": "journald",
"log-opts": {
"tag": "{{.Name}}"
}
}
Смотреть логи контейнера можно так:
journalctl CONTAINER_NAME=myapp -f
Важный нюанс: если у вас много болтливых контейнеров, поднимите RateLimitBurst, иначе journald может легально дропать записи ради самосохранения. Следите за метриками journald и периодически проверяйте объем /var/log/journal.

Loki: централизованный поиск и хранение
Loki — это хранилище логов с индексом по меткам (labels). В контексте Docker у вас два главных пути: использовать Docker logging driver для Loki (плагин) либо установить Promtail и собирать логи из json-file или journald.
Вариант A: Docker Loki logging driver (плагин)
Идея проста: контейнер пишет, драйвер отправляет напрямую в Loki по HTTP. Плюсы — минимум «прослоек», диску становится легче. Однако есть риски.
- Зависимость от сети и Loki: если Loki недоступен или тормозит, драйвер может блокировать запись (или терять при буферизации, зависит от настроек), что повлияет на приложение.
- Ограниченная логическая обработка: сложные пайплайны парсинга и склейки удобнее делать в Promtail.
- Жизненный цикл и сопровождение плагина: в последние годы экосистема сместилась к сбору через агентов. Плагин работает, но редко — лучший первый выбор.
Типичный «скелет» настроек у демона Docker для Loki-драйвера выглядит так:
{
"log-driver": "loki",
"log-opts": {
"loki-url": "http://127.0.0.1:3100/loki/api/v1/push",
"loki-batch-size": "1024",
"labels": "container_name,compose_service,compose_project",
"env": "ENV,ROLE",
"tag": "{{.Name}}/{{.ID}}"
}
}
Плюс установки и активации плагина. Дальше чрезвычайно важно: грамотно ограничить набор меток (labels), иначе индекс Loki раздуется.
Вариант B: Promtail + json-file или journald
Promtail «скребет» локальные источники и отправляет в Loki с буферизацией на диск, ретраями и пайплайнами. Это более устойчиво к сбоям и позволяет централизовать парсинг/нормализацию.
Частый паттерн: оставить json-file c ротацией, а Promtail читать файлы в /var/lib/docker/containers/*/*-json.log, раскодировать JSON, склеивать многострочные записи и отправлять дальше. Альтернативно — читать journald, если вы хотите единый журнал узла.
Минимальный пример для чтения json-file:
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /var/lib/promtail/positions.yaml
scrape_configs:
- job_name: containers
pipeline_stages:
- docker: {}
static_configs:
- targets: [localhost]
labels:
job: docker
host: my-vds
__path__: /var/lib/docker/containers/*/*-json.log
relabel_configs:
- source_labels: ["__path__"]
target_label: container_id
regex: .*/(.*)/(.*)
replacement: "$1"
И пример для journald:
scrape_configs:
- job_name: systemd-journal
journal:
path: /var/log/journal
max_age: 12h
labels:
job: systemd-journal
relabel_configs:
- source_labels: ["__journal_container_name"]
target_label: container
- source_labels: ["__journal_container_id"]
target_label: container_id
Производительность: что быстрее
В общих чертах:
json-file— самый дешевый по CPU путь: одна локальная запись, минимум посредников. Обычно потолок упирается в IOPS/throughput диска.journaldдобавляет системную очередь и обработку. На нормальном VDS это незаметно для типичных 500–2000 строк/с, но при бурстах rate limit может начать отбрасывать.- Loki driver вносит сетевой hop и сериализацию. На безопасной стороне — поставить Promtail: он читает локально и отправляет партиями, сглаживая пиковую нагрузку.
Если у вас одна-две веб-службы и сотни строк в секунду — json-file с ротацией почти всегда выигрывает простотой и скоростью. При росте до тысяч строк в секунду и необходимости поиска по всем узлам — пора смотреть в сторону Promtail + Loki.
Чтобы наблюдать I/O и нагрузку логопути в динамике, удобно поднять метрики на одном узле — см. наш материал одиночный стек VictoriaMetrics на VDS.
Дисковая политика и ротация
json-file: ротация по размеру per-container (max-size,max-file, компрессия). Хорошо контролируется, легко «вписать» в бюджет диска VDS. Нет ротации по времени нативно.journald: глобальная квота и retention (дни/объем), хорош для единого управления. Но болтливый контейнер съест лимит другим, если общий бюджет маленький.Loki: локальные файлы минимальны (если driver) или есть ротацияjson-file(если Promtail). Реальная ретенция — на стороне Loki: неделя, месяц, год — по вашей политике и кошельку.
Надежность и риск потери строк
json-file: приmode=blockingриски потери минимальны, но можно «придушить» приложение, если диск не успевает. Приmode=non-blockingесть вероятность дропа при переполнении буфера.journald: защищает узел от лог-флуда rate limit'ом; это хорошо для стабильности, но приводит к потерям строк при бурстах, если лимиты не подкручены.- Loki driver: при сетевых проблемах возможна блокировка или дроп. Уточняйте поведение буферов и ретраев. Именно поэтому во многих продакшенах предпочитают Promtail + json-file/journald.
- Promtail: стабильно переживает кратковременные отказы Loki благодаря буферизации и ретраям. Потери минимальны при корректной настройке очередей/диска.
Метки и кардинальность (особенно важно для Loki)
Соблазн навесить на каждую строку как можно больше меток велик, но это путь к взрывному росту индекса. Общие правила:
- В метки годятся редко меняющиеся поля:
container_name,compose_service,env,host. - Не кладите в labels динамические значения:
request_id,user_id,url,ip— оставляйте в payload и используйте полнотекстовый поиск. - Агрегируйте метки на уровне сервиса или релиза, а не на уровне каждого экземпляра, если это не нужно для расследований.
Типовые сценарии на VDS и рекомендации
1. Небольшой проект на одном VDS
Возьмите json-file с ротацией, включите компрессию и неблокирующий режим. Если нужен поиск по истории — добавьте Promtail и поднимите одиночный Loki (или подключитесь к внешнему). Это даст минимум боли и понятный бюджет ресурсов. Для небольших сайтов подойдет и тариф виртуального хостинга с аккуратной ротацией логов.
2. Стадия с несколькими сервисами, но без строгого SLA
journald даст комфортный единый журнал узла. Добавьте Promtail с источником journal, ограничьте retention в Loki (например, 14–30 дней) и держите разумные rate limits.
3. Продакшен с высоким объемом логов
Выбирайте json-file + Promtail или journald + Promtail. Плагин Loki оставьте для ограниченных случаев и тщательно тестируйте. Следите за диском: вынесите логи на отдельный том, настройте мониторинг I/O и свободного места, предупредите алертами 75–80% заполнения.
4. Rootless Docker
journald может быть недоступен или неудобен. Оставайтесь на json-file и собирайте через Promtail; это наименее конфликтный путь.
Диагностика и эксплуатация
- Проверить текущий драйвер:
docker info --format '{{.LoggingDriver}}'. - Быстро оценить диск логов Docker:
du -sh /var/lib/docker/containers. - Смотреть логи:
docker logs --since 10m <container>илиjournalctl CONTAINER_NAME=<name> -f. - При переходе на новый драйвер перезапускайте контейнеры, иначе они останутся на старом драйвере.
- Планируйте ретенцию: «ровно сколько надо» — верное правило. Избыточная история логов на рабочем диске VDS — частая причина инцидентов.
Мини-рецепты под Docker Compose
json-file с ротацией:
services:
app:
image: myorg/app:latest
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
compress: "true"
tag: "{{.Name}}/{{.ID}}"
journald:
services:
app:
image: myorg/app:latest
logging:
driver: journald
options:
tag: "{{.Name}}"
Loki driver (используйте осознанно):
services:
app:
image: myorg/app:latest
logging:
driver: loki
options:
loki-url: "http://127.0.0.1:3100/loki/api/v1/push"
labels: "container_name,compose_service"
loki-batch-size: "1024"
tag: "{{.Name}}"

Чек-лист выбора
- Нужна простота и скорость на одном узле →
json-fileс ротацией. - Нужен единый системный журнал и удобный
journalctl→journald. - Нужен центральный поиск/аналитика → Promtail + Loki; источник выбирайте из предыдущих двух.
- Избегайте драйвера Loki как первого выбора, если нет уверенности в сети и в стабильности бекенда.
- Следите за диском и лимитами; ставьте алерты и тестируйте поведение в бурстах.
FAQ: коротко
Почему «пропали» логи? В json-file ищите следы ротации (переполнен лимит), в journald — RateLimit и Retention. Проверьте, не менялись ли настройки драйвера без перезапуска контейнеров.
Можно ли хранить ровно 7 дней с json-file? Нативно нет, только косвенно через размер. Для точной ретенции используйте journald или отправляйте в Loki c retention-политикой.
Как склеить многострочные stacktrace? Делайте это в Promtail (pipeline stages), а не на уровне драйвера. Для json-file подойдет стадия docker, она корректно раскодирует строки и переносы.
Что с производительностью на маленьком VDS? json-file почти всегда быстрее и дешевле. Главное — ограничить размер логов и включить компрессию. Если вы боитесь потерь, используйте блокирующий режим и следите за I/O.
Итоги
На одиночном VDS оптимальный старт — json-file с грамотной ротацией и компрессией. Когда появляется потребность в поиске по истории и корреляции событий между машинами, подключайте Promtail и Loki. journald уместен, если цените единый системный журнал и хотите централизовать политику retention на уровне узла. Драйвер Loki стоит рассматривать точечно, понимая компромиссы устойчивости. В любом случае заложите мониторинг диска, задайте четкие лимиты и протестируйте поведение логирования в стресс-сценариях — это сохранит вам часы расследований в самый неподходящий момент.


