Top.Mail.Ru
OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

Docker: json-file vs journald vs Loki — что выбрать для логов на VDS

Логи контейнеров — больное место продакшена на VDS: дисковая нагрузка, ротация, потери строк при пиках. Разбираем три подхода в Docker — json-file, journald и Loki: как они работают, что с производительностью и надежностью, какие настройки выбрать без сюрпризов.
Docker: json-file vs journald vs Loki — что выбрать для логов на VDS

Если вы разворачиваете контейнеры на 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.

Docker и journald: единый журнал узла

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: неделя, месяц, год — по вашей политике и кошельку.
Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Надежность и риск потери строк

  • 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}}"

Promtail отправляет логи Docker в Loki

Чек-лист выбора

  • Нужна простота и скорость на одном узле → json-file с ротацией.
  • Нужен единый системный журнал и удобный journalctljournald.
  • Нужен центральный поиск/аналитика → 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 стоит рассматривать точечно, понимая компромиссы устойчивости. В любом случае заложите мониторинг диска, задайте четкие лимиты и протестируйте поведение логирования в стресс-сценариях — это сохранит вам часы расследований в самый неподходящий момент.

Поделиться статьей

Вам будет интересно

MariaDB MaxScale vs ProxySQL: как выбрать MySQL‑прокси для продакшена OpenAI Статья написана AI (GPT 5)

MariaDB MaxScale vs ProxySQL: как выбрать MySQL‑прокси для продакшена

Чёткий обзор двух популярных MySQL‑прокси — MariaDB MaxScale и ProxySQL. Разбираем архитектуру, read/write split, отказоустойчивос ...
BBR или CUBIC на VDS: как выбрать TCP congestion control и не потерять ни в throughput, ни в latency OpenAI Статья написана AI (GPT 5)

BBR или CUBIC на VDS: как выбрать TCP congestion control и не потерять ни в throughput, ни в latency

BBR и CUBIC — ключевые TCP‑алгоритмы в Linux. На VDS выбор влияет на скорость скачиваний и задержку API. Разберём, когда BBR полез ...
Alt‑Svc на практике: плавная миграция между HTTP/2, HTTP/3 и сменой origin OpenAI Статья написана AI (GPT 5)

Alt‑Svc на практике: плавная миграция между HTTP/2, HTTP/3 и сменой origin

Alt‑Svc позволяет объявить браузеру альтернативный протокол (HTTP/3/QUIC) и даже другой host для того же origin. Разбираем включен ...