Cluster level логирование в kubernetes с помощью Fluent Bit

Fluent Bit - кроссплатформенное решение по сбору, обработке и маршрутизации логов. Может использоваться в качестве агента на уровне сервера и агента на уровне пода.

Содержание

Архитектура и принцип действия

Fluent Bit собирает, парсит и фильтрует сообщения из различных источников ввода и сохраняет их в хранилище (в памяти или файловой системе). После успешного сохранения, сообщения поступают из хранилища на вход в маршрутизатор, который определяет в какой выход оно будет отправлено.

flb_pipeline

Ключевая особенность Fluent Bit - использование корутин. Сетевые задержки минимизируются за счет дешевого переключения контекста между разными потоками.

С точки зрения производительности Fluent Bit имеет лучшие показатели в производительности и использовании ОЗУ. Исследование AWS показало что Fluent Bit в ~5 раз меньше утлизировал процессор и память чем Fluentd.

Плагины ввода

Позволяют получать сообщения из различных источников. К основным можно отнести:

  • systemd - журнал операционной системы;
  • kmsg - журнал ядра операционной системы;
  • tail - чтение файла из файловой системы

Обработка сообщения

Под обработкой сообщения подразумевается парсинг и фильтрация/модификация сообщений. К основным можно отнести:

  • json - парсер json сообщений;
  • decoder - позволяет декодировать структуры из строки (например, экранированный json);
  • kubernetes - позволяет дополнять сообщения метаданными о поде в кластере kubernetes
  • record_modifier - позволяет добавлять/удалять поля из сообщений

Хранение сообщений

Хранение сообщений позволяет решить классическую проблему "Fast publisher, slow subscriber". С помощью хранилища организуется "обратное давление" на источник сообщений, вплоть до его полной остановки. Всего реализовано 2 типа хранилищ: в памяти и файловой системе.

Плагины вывода

Позволяют отправлять сообщения в различные источники. К основным можно отнести:

  • file - записывать сообщения в файл;
  • pgsql - сохранять сообщения в PostgreSQL;
  • es - сохранять сообщения в Elasticsearch;

Установка в kubernetes

Существует несколько подходов к cluster-level журналированию в kubernetes. Fluent Bit можно применить в каждом из них, а так же он может быть использован совместно с Fluentd. Для упрощения примера далее будет использован подход журналирования на уровне сервера.

Подготовка манифестов и установка

Daemon set лучше всего подходит для журналирования на уровне сервера. Kubernetes сам запустит Fluent Bit на новых узлах.

Манифест основан на репозитории fluent/fluent-bit-kubernetes-logging. В нём дополнительно монтируется хост директория /run/log для интеграции с systemd-journald:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluent-bit
  namespace: monitoring
  labels:
    k8s-app: fluent-bit
spec:
  selector:
    matchLabels:
      k8s-app: fluent-bit
  template:
    metadata:
      labels:
        k8s-app: fluent-bit
    spec:
      priorityClassName: system-node-critical
      containers:
      - name: fluent-bit
        image: fluent/fluent-bit:1.7.0
        imagePullPolicy: Always
        ports:
        - containerPort: 2020
          name: http
          protocol: TCP
        volumeMounts:
        - name: config
          mountPath: /fluent-bit/etc/fluent-bit.conf
          subPath: fluent-bit.conf
        - name: config
          mountPath: /fluent-bit/etc/custom_parsers.conf
          subPath: custom_parsers.conf
        - name: var-log
          mountPath: /var/log
        - name: run-log
          mountPath: /run/log
        - name: etcmachineid
          mountPath: /etc/machine-id
          readOnly: true
      volumes:
      - name: config
        configMap:
          defaultMode: 420
          name: fluent-bit
      - name: var-log
        hostPath:
          path: /var/log
      - name: run-log
        hostPath:
          path: /run/log
      - name: etcmachineid
        hostPath:
          path: /etc/machine-id
          type: File

Манифест задействует 3 точки монтирования: /var/log, /run/log и /etc/machine-id. Fluent Bit, при открытии журнала sd_journal_open(), использует флаг SD_JOURNAL_LOCAL_ONLY - открывать только локальные журналы. Для их фильтрации используется идентификатор machine-id хранящийся в одноименном файле. В режиме Storage=auto файлы журналов могут храниться в одной из двух директорий: /var/log/journal, /run/log/journal. Если директория /var/log/journal не существует, journald будет использовать /run/log/journal для ведения журнала.

Конфигурация описывает одну цепочку обработки логов. Стандартный вывод docker.service дополняется мета-информацией из kubernetes api server и записываются в файл /var/log/k8s.log:

apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    k8s-app: fluent-bit
  name: fluent-bit
  namespace: monitoring
data:
  fluent-bit.conf: |
    [SERVICE]
        Flush 1
        Daemon Off
        Log_Level info
        Parsers_File parsers.conf
        HTTP_Server On
        HTTP_Listen 0.0.0.0
        HTTP_Port 2020

    [INPUT]
        Name systemd
        Tag kube.*
        Systemd_Filter _SYSTEMD_UNIT=docker.service
        Read_From_Tail On

    [FILTER]
        Name kubernetes
        Match kube.*
        Kube_URL https://192.168.1.57:6443
        Use_Journal On
        tls.verify Off
        Merge_Log On
        Keep_Log Off
        K8S-Logging.Parser On
        K8S-Logging.Exclude On

    [OUTPUT]
        Name file
        Match *
        Path /var/log/k8s.log

Установка и применение изменений производится с помощью команды kubectl apply:

~ % ~ % kubectl apply -f fluent-bit-configmap.yaml && kubectl apply -f fluent-bit-ds.yaml

После этого можно убедиться в успехе установки:

~ % kubectl -n monitoring get ds fluent-bit
NAME      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
fluent-bit   1         1         1       1            1           <none>          27s
~ % kubectl -n monitoring get pods -lk8s-app=fluent-bit
NAME            READY   STATUS    RESTARTS   AGE
fluent-bit-mf8k2   1/1     Running   0          30s
~ % kubectl -n monitoring exec -ti ds/fluent-bit  -- tail -f /var/log/k8s.log
{"kubernetes":{"container_hash":"k8s.gcr.io/ingress-nginx/controller@sha256:e6019e536cfb921afb99408d5292fa88b017c49dd29d05fc8dbc456aa770d590","container_image":"k8s.gcr.io/ingress-nginx/controller:v0.41.0","container_name":"controller","docker_id":"d7802a01649248c5aa781548192528f67666c5ed27061860384f192e07053ae5","host":"inf-1","labels":{"k8s-app":"ingress-nginx","pod-template-hash":"84d9759c66"},"namespace_name":"kube-system","pod_id":"b0bd1b8d-5a21-4cec-91af-30a250d3610b","pod_name":"ingress-nginx-84d9759c66-vgkk6"},"log":"10.10.0.1 - - [01/Mar/2021:05:36:53 +0000] \"GET /healthz HTTP/1.1\" 200 13 \"\" \"dashboard/v2.0.0\"","stream":"stdout","time":"2021-03-01T05:36:53.900282242Z"}
...

Выводы

Fluent Bit обладает схожей с rsyslog функциональностью. Различные плагины ввода и вывода позволяют встраивать его в различные схемы cluster level журналирования.

Разработка Fluent Bit ведется с пониманием того, что с высокой долей вероятности сервис будет запущен в контейнеризированном окружении. За счет этого интеграция в kubernetes состоит из нескольких шагов.