Published on

Exporting Kubernetes Logs to BetterStack using FluentBit

Authors
FluentBit

Following on from my previous post on Exporting Kubernetes Logs to Linode S3 using FluentBit, we found that the logs were being exported to S3, but we had no way to query them or set up alerts.

To keep costs down we wanted to minimise the cluster overhead of managing a full logging stack such as Grafana Loki. As we already had BetterStack set up for uptime alerting, we explored the possibility of extending this to logs and discovered it has native support for FluentBit. The decision was made to continue to use Linode S3 for long-term storage of logs, but we will now forward error logs to BetterStack for real-time monitoring and alerting.

Overview

The architecture is shown below. Kubernetes by default rotates logs based on file size. Our aim is to export these logs now to BetterStack. BetterStack's free tier allows us to store logs for 3 days, up to 3GB in size. Because of this, we decided to only forward error logs to BetterStack.

Logging Architecture

Kubernetes Logging

Kubernetes default behaviour is defined here. Kubernetes logs and application logs are stored via the underlying container runtime on each Node. The kubelet is responsible for rotating container logs and managing the logging directory structure. The kubelet sends this information to the container runtime (using CRI), and the runtime writes the container logs to the given location.

These logs are rotated based on two environment variables:

  1. containerLogMaxSize (default 10Mi)
  2. containerLogMaxFiles (default 5)

These settings let you configure the maximum size for each log file and the maximum number of files allowed for each container respectively. Crucially, using the command kubectl logs will only ever return the latest file. The others would need to be accessed directly.

Our requirement is to extend this functionality to make these logs available in BetterStack for error reporting, and for 30 days in S3 for archive purposes.

FluentBit

FluentBit is a logging and metrics processor and forwarder. It can connect to multiple sources, allows you to enrich and filter incoming data and forward to a range of destinations. It's focus is on performance and efficiency which suits situations where resources are limited.

Comparison to FluentD

My understanding is FluentBit is the next-generation version of FluentD, heavily optimised. FluentD supports a wider range of connectors. A full comparison is provided here.

Tail Plugin

The tail plugin allows you to monitor one or several text files. We define an input block to leverage this plugin and point to log files generated by Kubernetes or Applications:

fluentbit.yaml
    [INPUT]
        Name tail
        Path /var/log/containers/*.log
        Parser docker
        Tag kube.*
        Mem_Buf_Limit 5MB
        Skip_Long_Lines On

Filter Plugins

The kubernetes plugin allows you to enrich logs with Kubernetes metadata. This is useful for identifying which pod, namespace, or container the logs originated from.

fluentbit.yaml
    [INPUT]
        Name kubernetes
        Tag kube.*
        Merge_Log On
        Kube_Tag_Prefix kube.var.log.containers.
        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

Filtering for Errors:

To filter logs for errors and exclude static file requests, we can use the grep plugin.

fluentbit.yaml
    [FILTER]
        Name    grep
        Match   kube.*
        Regex   log (?i)(error|failed|exception)

    [FILTER]
        Name    grep
        Match   container.*
        Exclude log (?i)\.(png|jpg|jpeg|gif|svg|ico|css|js|woff|woff2|ttf|eot|otf|php)\b

    [FILTER]
        Name    grep
        Match   container.*
        Exclude code ^(2|3)\d\d$

HTTP Output Plugin

The http plugin allows you to forward logs to an HTTP endpoint. We will use this to forward logs to the BetterStack ingestion API.

fluentbit.yaml
     [OUTPUT]
        name    http
        match   *
        tls     On
        host    xxxx
        port    443
        uri     /fluentbit
        header  Authorization Bearer xxxx
        header  Content-Type application/msgpack
        format  msgpack
        retry_limit 5

Deployment

Kubernetes logs for an application are stored on it's underlying node. This means we need to deploy FluentBit as a DaemonSet, ensuring an instance of FluentBit runs once on each node.

Here is an example deployment manifest:

deployment.yaml
aapiVersion: apps/v1
kind: DaemonSet
metadata:
  name: better-stack-logger
  namespace: logging
  labels:
    k8s-app: better-stack-logger
spec:
  selector:
    matchLabels:
      name: better-stack-logger
  template:
    metadata:
      labels:
        name: better-stack-logger
    spec:
      serviceAccountName: fluent-bit
      containers:
        - name: fluent-bit
          image: fluent/fluent-bit:3.0
          imagePullPolicy: Always
          volumeMounts:
            - name: varlog
              mountPath: /var/log
            - name: varlogpods
              mountPath: /var/log/pods
            - name: varlibdockercontainers
              mountPath: /var/lib/docker/containers
            - name: config
              mountPath: /fluent-bit/etc/
      terminationGracePeriodSeconds: 10
      volumes:
        - name: varlog
          hostPath:
            path: /var/log
        - name: varlogpods
          hostPath:
            path: /var/log/pods
            type: ""
        - name: varlibdockercontainers
          hostPath:
            path: /var/lib/docker/containers
            type: ""
        - name: config
          configMap:
            name: better-stack-fluent-bit-config
      tolerations:
        - effect: NoSchedule
          operator: Exists

BetterStack

BetterStack is a monitoring and alerting platform that provides a free tier for log management. It allows you to collect, search, and analyze logs in real-time, making it suitable for monitoring applications and infrastructure. BetterStack provides a simple HTTP endpoint to which you can send logs. It supports various formats, including JSON and MsgPack.

Betterstack supports FluentBit as a data source, allowing you to forward logs directly from FluentBit to BetterStack. Their documentation provides a guide on how to set up FluentBit as a source.

Once configured, you can use the LiveTail feature to view logs in real-time, set up alerts based on log patterns, and create dashboards to visualize log data. In the image below you can see the LiveTail with a log highlighted, inclulding the Kubernetes metadata we enriched it with. BetterStack Portal