Логгирование в Docker и Kubernetes: полное руководство по настройке Fluent Bit, Filebeat и драйверов | AdminWiki
Timeweb Cloud — сервера, Kubernetes, S3, Terraform. Лучшие цены IaaS.
Попробовать

Логгирование в Docker и Kubernetes: полное руководство по настройке Fluent Bit, Filebeat и драйверов

03 июня 2026 9 мин. чтения

Почему стандартное логгирование в Docker и Kubernetes ломается в production

В production-среде логи контейнеров теряются при перезапуске пода, особенно с политикой restartPolicy: Always. Стандартный драйвер json-file забивает диск, если не настроена ротация. Отсутствие контекста - имени пода, namespace, labels - делает логи бесполезными в масштабе кластера. Эти проблемы системные. Они требуют продуманной архитектуры, а не точечных фиксов.

Типичные сценарии потери логов и как их диагностировать

Диагностируйте текущую конфигурацию Docker:

docker info | grep Logging

Для проверки логов предыдущего экземпляра пода используйте:

kubectl logs --previous <pod-name>

Проверьте лимиты размера лог-файлов в /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Если параметры max-size или max-file отсутствуют, логи будут расти бесконечно. Пример ошибки мониторинга: алерт на высокую загрузку CPU есть, но соответствующих логов ошибок в Elasticsearch нет - они остались на ноде в удаленном контейнере.

Выбор и настройка драйвера логов Docker: json-file, journald, syslog

Сравниваем драйверы по ключевым критериям:

  • Производительность: json-file быстрее для локальной разработки, syslog добавляет сетевую задержку.
  • Ротация логов: journald управляет этим автоматически, для json-file нужна ручная настройка.
  • Интеграция: journald интегрируется с systemd, syslog отправляет логи на центральный сервер.

Пошаговая настройка в /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "5",
    "tag": "{{.ImageName}}/{{.Name}}/{{.ID}}"
  }
}

После изменения перезапустите демон: systemctl restart docker.

Рекомендации:

  • Разработка: Используйте json-file для простоты отладки.
  • Production с systemd: Выберите journald, если вся инфраструктура управляется через systemd и журналы.
  • Production с центральным сервером: Настройте syslog с адресом вашего log-аггрегатора.

Настройка json-file: контроль за дисковым пространством и ротация

Конфигурация daemon.json с параметрами "log-opts":

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "10"
  }
}

Рассчитайте оптимальные max-size и max-file. На ноде с 20 контейнерами и 100 ГБ диска под логи выделите 20 ГБ. При среднем объеме логов 100 МБ в день на контейнер установите max-size="100m" и max-file="7". Это сохранит недельную историю.

Для принудительной очистки старых логов используйте:

docker system prune --volumes --filter "until=168h"

Команда удалит все неиспользуемые данные, включая лог-файлы, созданные более недели назад.

Интеграция с systemd через journald: плюсы и подводные камни

Настройте драйвер journald в /etc/docker/daemon.json:

{ "log-driver": "journald" }

Плюсы:

  • Централизованное управление через journalctl.
  • Встроенная ротация и сжатие журналов.
  • Интеграция с системными логами.

Минусы:

  • Сложность парсинга JSON-логов, так как journald хранит их в собственном бинарном формате.
  • Потенциальные проблемы с производительностью при высокой нагрузке (более 10 тыс. записей в секунду).
  • Для отправки в Elasticsearch или Loki потребуется дополнительный агент (fluentd, fluent-bit).

Фильтрация логов конкретного контейнера:

journalctl CONTAINER_NAME=myapp_container

Или по тегу образа:

journalctl -t docker/myapp:latest

Архитектура сбора логов в Kubernetes: DaemonSet как стандарт де-факто

Модель DaemonSet гарантирует запуск одного пода-агента на каждой ноде кластера. Это эффективнее sidecar-подхода, который создает контейнер для каждого пода и потребляет больше ресурсов. Агент получает доступ к логам контейнеров через монтирование hostPath:

  • /var/lib/docker/containers для Docker runtime.
  • /var/log/pods для контейнерных логов в формате Kubernetes.

Базовый манифест DaemonSet для развертывания агента:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: log-collector
  namespace: kube-system
spec:
  selector:
    matchLabels:
      name: log-collector
  template:
    metadata:
      labels:
        name: log-collector
    spec:
      containers:
      - name: fluent-bit
        image: fluent/fluent-bit:2.2
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

Настройка Fluent Bit в качестве DaemonSet для эффективного сбора и фильтрации

Fluent Bit - легковесный инструмент для сбора, парсинга и отправки логов. Полный манифест DaemonSet с комментариями:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluent-bit
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: fluent-bit
  template:
    metadata:
      labels:
        app: fluent-bit
    spec:
      serviceAccountName: fluent-bit
      containers:
      - name: fluent-bit
        image: fluent/fluent-bit:2.2
        env:
        - name: FLUENT_ELASTICSEARCH_HOST
          value: "elasticsearch-logging.kube-system.svc.cluster.local"
        - name: FLUENT_ELASTICSEARCH_PORT
          value: "9200"
        volumeMounts:
        - name: fluent-bit-config
          mountPath: /fluent-bit/etc/
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
        - name: dockerlogs
          mountPath: /var/log/pods
          readOnly: true
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 100Mi
      volumes:
      - name: fluent-bit-config
        configMap:
          name: fluent-bit-config
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
      - name: dockerlogs
        hostPath:
          path: /var/log/pods

Конфигурация Fluent Bit (fluent-bit.conf) в ConfigMap:

[SERVICE]
    Flush        5
    Daemon       Off
    Log_Level    info
    Parsers_File parsers.conf
    Plugins_File plugins.conf
    HTTP_Server  On
    HTTP_Listen  0.0.0.0
    HTTP_Port    2020

[INPUT]
    Name              tail
    Path              /var/log/containers/*.log
    Parser            docker
    Tag               kube.*
    Mem_Buf_Limit     50MB
    Skip_Long_Lines   On
    Refresh_Interval  10

[FILTER]
    Name                kubernetes
    Match               kube.*
    Kube_URL            https://kubernetes.default.svc:443
    Kube_CA_File        /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    Kube_Token_File     /var/run/secrets/kubernetes.io/serviceaccount/token
    Kube_Tag_Prefix     kube.var.log.containers.
    Merge_Log           On
    Merge_Log_Key      log_processed

[OUTPUT]
    Name            es
    Match           *
    Host            ${FLUENT_ELASTICSEARCH_HOST}
    Port            ${FLUENT_ELASTICSEARCH_PORT}
    Logstash_Format On
    Retry_Limit     False
    Type            flb_type_kube
    Replace_Dots    On
    Generate_ID     On

Тюнинг производительности: настройте Mem_Buf_Limit для ограничения использования памяти. Включите многопоточность для INPUT плагинов, если число лог-файлов превышает 100.

Конфигурация парсера и фильтров: из сырых логов в структурированные события

Пример парсера для JSON-логов в parsers.conf:

[PARSER]
    Name        docker
    Format      json
    Time_Key    time
    Time_Format %Y-%m-%dT%H:%M:%S.%LZ
    Time_Keep   On

Фильтр 'kubernetes' автоматически обогащает записи метаданными: именем пода, namespace, labels. Для обработки multiline-логов, например Java stack traces, добавьте отдельный парсер:

[PARSER]
    Name          multiline_java
    Format        regex
    Regex         /^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}) (?<level>\w+) \[(?<thread>[^\]]+)\] (?<logger>[^ ]+) - (?<message>.*)/
    Time_Key      time
    Time_Format   %Y-%m-%d %H:%M:%S,%L

Добавление custom-полей через фильтр Lua или record_modifier:

[FILTER]
    Name          record_modifier
    Match         *
    Record        cluster_name production-us-east-1
    Record        team platform

Альтернатива: сбор логов с помощью Filebeat и Elasticsearch

Сравнение Fluent Bit и Filebeat для Kubernetes:

  • Потребление ресурсов: Fluent Bit легче (около 20 МБ памяти), Filebeat требует 50-100 МБ.
  • Простота конфигурации: Fluent Bit использует единый конфиг, Filebeat - модули (containers, kubernetes).
  • Возможности обработки: Filebeat имеет больше готовых модулей для парсинга (nginx, apache), Fluent Bit гибче в кастомной обработке.

Манифест DaemonSet для Filebeat:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: filebeat
  template:
    metadata:
      labels:
        app: filebeat
    spec:
      serviceAccountName: filebeat
      containers:
      - name: filebeat
        image: docker.elastic.co/beats/filebeat:8.12.0
        args: ["-c", "/etc/filebeat.yml", "-e"]
        volumeMounts:
        - name: filebeat-config
          mountPath: /etc/filebeat.yml
          subPath: filebeat.yml
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
        - name: varlogpods
          mountPath: /var/log/pods
          readOnly: true
      volumes:
      - name: filebeat-config
        configMap:
          name: filebeat-config
          items:
          - key: filebeat.yml
            path: filebeat.yml
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
      - name: varlogpods
        hostPath:
          path: /var/log/pods

Ключевые настройки filebeat.yml:

filebeat.inputs:
- type: container
  paths:
    - /var/lib/docker/containers/*/*.log
  processors:
    - add_kubernetes_metadata:
        host: ${NODE_NAME}
        matchers:
        - logs_path:
            logs_path: "/var/log/containers/"

output.elasticsearch:
  hosts: ["elasticsearch-logging.kube-system.svc.cluster.local:9200"]
  indices:
    - index: "filebeat-%{[agent.version]}-%{+yyyy.MM.dd}"

setup.template.name: "filebeat"
setup.template.pattern: "filebeat-*"

Для комплексного решения рассмотрите готовое руководство по централизованному сбору логов Python-микросервисов в Kubernetes. Оно включает развертывание Fluent Bit в режиме DaemonSet и настройку отправки структурированных JSON-логов в Elasticsearch.

Структурированное логгирование: обязательные метаданные для Pod, Namespace и Labels

Стандарт структурированного лога для Kubernetes включает обязательные поля:

  • timestamp: Время события в формате ISO 8601.
  • log_level: Уровень (DEBUG, INFO, WARN, ERROR).
  • message: Текст сообщения.
  • kubernetes.pod_name: Имя пода.
  • kubernetes.namespace: Пространство имен.
  • kubernetes.labels: Все labels пода в виде ключ-значение.

Пример лога "до":

ERROR: Database connection failed

Пример лога "после":

{
  "timestamp": "2026-06-03T14:30:15.123Z",
  "level": "ERROR",
  "message": "Database connection failed",
  "kubernetes": {
    "pod_name": "backend-7f8c6b9d5-2xzqk",
    "namespace": "production",
    "labels": {
      "app": "backend",
      "tier": "api",
      "version": "v2.1.0"
    }
  }
}

Настройте Python приложение для вывода JSON:

import json
import logging

class JSONFormatter(logging.Formatter):
    def format(self, record):
        log_record = {
            "timestamp": self.formatTime(record, self.datefmt),
            "level": record.levelname,
            "message": record.getMessage(),
            "module": record.module,
            "funcName": record.funcName
        }
        return json.dumps(log_record)

logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger.addHandler(handler)

Используйте метки для логической группировки. Например, labels app=backend и tier=production позволят в Grafana Loki или Kibana быстро отфильтровать логи только production backend-сервисов. Для глубокой настройки логирования в Python изучите полное руководство по настройке логирования в Python для продакшена.

Гарантии доставки и предотвращение потери логов при перезапуске подов

Паттерны обеспечения надежности:

  1. VolumeMounts для persistent-хранения логов на ноде: Логи пишутся в volume, который переживает перезапуск контейнера.
  2. Буферизация в агенте: Fluent Bit или Filebeat буферизуют данные на диск или в память при недоступности Elasticsearch.
  3. Политики retry и backoff: Агент повторяет отправку с экспоненциальной задержкой.

Используйте sidecar для критически важных логов приложения, если DaemonSet недостаточно. Например, для аудит-логов финансовой транзакции.

Настройка Volume и VolumeMounts для логов пода

Пример манифеста пода с emptyDir volume:

apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  volumes:
  - name: log-volume
    emptyDir: {}
  containers:
  - name: app
    image: myapp:latest
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/myapp
  - name: log-sidecar
    image: busybox
    command: ["sh", "-c", "tail -f /var/log/myapp/app.log"]
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/myapp

Логи приложения пишутся в /var/log/myapp внутри volume. Sidecar-контейнер читает их и может отправлять дальше. emptyDir существует, пока под жив. Для более долгого хранения используйте hostPath:

volumes:
- name: log-volume
  hostPath:
    path: /var/log/kubernetes/myapp
    type: DirectoryOrCreate

Преимущество hostPath - логи сохраняются после удаления пода. Риск - потенциальная проблема безопасности, если путь доступен другим подам на ноде. Всегда ограничивайте права доступа.

Для мониторинга подов с несколькими контейнерами, включая sidecar, обратитесь к практическому руководству по мониторингу логов пода с несколькими контейнерами.

Оптимизация и housekeeping: политики ротации, хранения и очистки

Стратегии управления жизненным циклом логов:

  1. Ротация на уровне ноды: Настройте logrotate для директорий Docker и системных логов.
  2. Политики хранения в Elasticsearch: Настройте ILM (Index Lifecycle Management) для автоматического удаления старых индексов.
  3. Мониторинг объема: Создайте алерт на заполнение диска логами более чем на 80%.

Настройка политики хранения в Elasticsearch через ILM:

PUT _ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "50gb",
            "max_age": "7d"
          }
        }
      },
      "delete": {
        "min_age": "30d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

Используйте Curator для устаревших версий Elasticsearch или сложных сценариев очистки.

Расчет необходимого дискового пространства:

  • Средний объем лога на запрос: 500 байт.
  • Количество запросов в секунду: 1000.
  • Объем в день: 500 Б * 1000 * 86400 сек = 43.2 ГБ.
  • С учетом сжатия в Elasticsearch (коэффициент ~0.3): ~13 ГБ в день.
  • На 30 дней хранения: 390 ГБ.

Добавьте 20% запаса на пиковые нагрузки. Для ноды с 10 подами выделите минимум 500 ГБ под том с логами.

Чтобы выбрать оптимальный стек для ваших задач и бюджета, сравните Elastic Stack и Grafana Loki в обзоре систем сбора и анализа логов в 2026 году.

Для полного цикла наблюдения за контейнеризованными приложениями, включая мониторинг метрик, изучите руководство по мониторингу Docker-контейнеров для продакшена.

Поделиться:
Сохранить гайд? В закладки браузера