5 분 소요


이 글에서는 Kind 클러스터에서 Fluent Bit 을 구성하고 테스트하는 방법을 소개합니다.

다음은 우리가 구성할 Workload 구성도입니다:

그림. collector, aggregator Workload 구성

쿠버네티스에서 Pod 는 리소스의 기본 단위이고,
Workload 는 실행되는 애플리케이션(이하 앱)입니다.


목표

  • Helm Chart 를 사용하여 Fluentd collector Statefulset 배포하기
  • Helm Chart 를 사용하여 Fluentd aggregator Daemonset 배포하기
    • Fluentd aggregator 는 구성된 Upstream 서버로 로그를 forward 합니다.
  • 테스트하기




준비하기

  • WSL(윈도우즈일 경우)
  • Docker
  • Helm
  • Kind

위 구성이 준비되지 않았다면,
Containerization Part.0 - Containerization 준비 과정을 따라하세요. 😉




시작하기

Kind 클러스터 구성하기

다음 명령을 실행하여 3 개의 노드로 구성된 Kind 클러스터를 생성합니다:

  cat <<EOF | kind create cluster --config=-
  kind: Cluster
  apiVersion: kind.x-k8s.io/v1alpha4
  nodes:
  - role: control-plane
  - role: worker
  - role: worker
  EOF

role 을 보면 하나의 control-plane 과 두 worker 들로 구성한다는 것을 알 수 있습니다.

kind get nodes 명령으로 3 개의 Node 가 생성된 것을 확인할 수 있습니다:

  $ kind get nodes
  kind-worker
  kind-worker2
  kind-control-plane




collector 배포하기

Forward Input으로 로그를 수집하는 Fluentd 앱을 collector 라고 하겠습니다.

그림. Fluentd collector Workload 구성

Forward Input 플러그인은 주로 다른 Fluentd 인스턴스, fluent-cat 명령 또는
Fluentd 클라이언트 라이브러리에서 이벤트 로그를 수신하는 데 사용됩니다.


TL;DR 🤖

helm repo add bitnami https://charts.bitnami.com/bitnami
helm install collector bitnami/fluentd --set aggregator.enabled=true --set forwarder.enabled=false


collector 소개

bitnami/fluent Helm Chart를 사용하여 collector 를 실행합니다.
먼저, bitnami Helm chart 저장소를 추가하고, fluentd 를 배포합니다.
실행할 때 파라미터로 전달하는 aggregator.enabled 는 fluentd 를 Statefulset 으로 실행하는 지 여부고, forwarder.enabled 는 fluentd 를 Daemonset 으로 실행하는 지 여부입니다.

Pod 를 배포하기 위한 Workload 리소스에는 Deployments, Statefulset, Daemonset 등이 있습니다.
많이 사용되는 세 가지 리소스는 다음과 같습니다:

  • Deployments는 일반적으로 Stateless 앱을 배포합니다. 모든 Pod 는 동일한 Persistent Volume 을 공유하고 모든 Pod 의 데이터가 동일합니다.
  • Statefulset은 Stateful 앱을 배포합니다. Pod 들의 배포 및 확장을 관리하고 순서 및 고유성을 보장합니다. 모든 Replica 는 각각의 PVC(Persistent Volume Claim) 를 생성하여 고유한 Volume을 가집니다.
  • DaemonsetPod 를 클러스터의 모든 Node 에 배포합니다. Node 가 클러스터에 추가/제거되면 DaemonSet 이 자동으로 Pod 를 추가/삭제합니다.


bitnami/fluentd 의 Helm Chart 템플릿, 기본 값들은 ArtifactHub bitnami/fluentd 를 참고하세요.




collector 테스트하기

테스트 하기 전에 다음 명령으로 collector Statefulset 의 상태를 확인합니다:

kubectl get statefulset

Statefulset 이 준비되었다면, 결과 화면은 다음과 같습니다:

NAME                READY   AGE
collector-fluentd   1/1     17s

watch "kubectl get statefulset" 명령을 사용하면 재실행하지 않고도 결과를 확인할 수 있습니다.


kubectl get svc 명령으로 collector의 서비스를 확인합니다:

$ kubectl get svc
NAME                         TYPE      CLUSTER-IP   EXTERNAL-IP PORT(S)            AGE
collector-fluentd-aggregator ClusterIP 10.96.251.86 <none>      9880/TCP,24224/TCP 119m
collector-fluentd-headless   ClusterIP None         <none>      9880/TCP,24224/TCP 119m
kubernetes                   ClusterIP 10.96.0.1    <none>      443/TCP            159m

클러스터 내에서는 서비스 이름(collector-fluentd-aggregator)과 포트(24224)로 직접 접근할 수 있습니다.

fluentd 로깅을 확인해보기 위해 다음 명령으로 실행 중인 컨테이너의 Shell 을 얻습니다:

kubectl exec -it collector-fluentd-0 -- /bin/bash

fluent-cat 으로 collector-fluentd-aggregator에 로그를 전송합니다:

echo '{"message":"hello"}' | fluent-cat debug.log --host collector-fluentd-aggregator --port 24224

fluent-cat 은 테스트를 위한 툴로 in_forward/in_unix 플러그인을 사용하여 이벤트를 전송합니다.


exitPod Shell 에서 나온 후,
kubectl logs 명령으로 collector-fluentd-0 Pod 의 로그를 확인합니다:

kubectl logs -f collector-fluentd-0

구성에 문제가 없다면 전송한 로그를 확인할 수 있습니다.

... debug.log: {"message":"hello"}




aggregator 배포하기

Fluent에서 Upstream Server 는 네트워크로 로그를 전달할 서버입니다.
Upstream 은 하나 이상의 노드로 구성되고 round-robin 밸런싱 모드를 사용합니다.
Upstream 구성으로 로그를 Forward Output 하는 Fluent Bit 앱을 aggregator 라고 하겠습니다.

그림. collector, aggregator Workload 구성


TL;DR 🤖

helm repo add fluent https://fluent.github.io/helm-charts
helm install aggregator fluent/fluent-bit -f https://raw.githubusercontent.com/cppis/tutorials-on-k8s/main/tutorials-on-k8s/values.yaml


aggregator 소개

fluent/fluent-bit Helm Chart를 사용하여 aggregator 를 실행합니다.
먼저, fluent Helm chart 저장소를 추가하고, fluent-bit 을 배포합니다.
fluent-bit 의 구성은 https://raw.githubusercontent.com/cppis/tutorials-on-k8s/main/tutorials-on-k8s/values.yaml 파일에 있고, 다음은 파일의 일부 내용입니다:

image:
  repository: cr.fluentbit.io/fluent/fluent-bit
  tag: "latest-debug"

service:
  type: NodePort
  port: 24224
  labels: {}
  annotations: {}

## https://docs.fluentbit.io/manual/administration/configuring-fluent-bit/configuration-file
config:
  service: |
    [SERVICE]
        Daemon Off
        Flush 
        Log_Level 
        Parsers_File parsers.conf
        Parsers_File custom_parsers.conf
        HTTP_Server On
        HTTP_Listen 0.0.0.0
        HTTP_Port 
        Health_Check On

  ## https://docs.fluentbit.io/manual/pipeline/inputs
  inputs: |
    [INPUT]
        Name tail
        Path /var/log/containers/*.log
        Exclude_Path /var/log/containers/aggregator-*.log,/var/log/containers/kindnet-*.log,/var/log/containers/collector-*.log
        multiline.parser docker, cri
        Tag kube.*
        Mem_Buf_Limit 5MB
        Skip_Long_Lines On

    [INPUT]
        Name forward
        Listen 0.0.0.0
        Port 24224
        Buffer_Chunk_Size 1M
        Buffer_Max_Size 6M

  ...

  ## https://docs.fluentbit.io/manual/pipeline/outputs
  outputs: |
    [OUTPUT]
        Name stdout
        Match *

    [OUTPUT]
        Name forward
        Match *
        Upstream /fluent-bit/etc/upstream.conf

  ...

  ## https://docs.fluentbit.io/manual/pipeline/parsers
  customParsers: |
    [PARSER]
        Name        docker
        Format      json
        Time_Key    time
        Time_Format %Y-%m-%dT%H:%M:%S.%L
        Time_Keep   Off
        # Command      |  Decoder     | Field | Optional Action
        # =============|======================|=================
        Decode_Field_As   json       log

    [PARSER]
        Name        json
        Format      json

  extraFiles:
    upstream.conf: |
      [UPSTREAM]
          name        forward-balancing

      [NODE]
          name       node-01
          host       collector-fluentd-aggregator
          port       24224

      #[NODE]
      #    name       node-02
      #    host       127.0.0.1
      #    port       24224

# The config volume is mounted by default, either to the existingConfigMap value, or the default of "fluent-bit.fullname"
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

daemonSetVolumes:
  - name: varlog
    hostPath:
      path: /var/log
  - name: varlibdockercontainers
    hostPath:
      path: /var/lib/docker/containers
  - name: etcmachineid
    hostPath:
      path: /etc/machine-id
      type: File

daemonSetVolumeMounts:
  - name: varlog
    mountPath: /var/log
  - name: varlibdockercontainers
    mountPath: /var/lib/docker/containers
    readOnly: true
  - name: etcmachineid
    mountPath: /etc/machine-id
    readOnly: true

logLevel: info

fluent/fluent-bit Helm Chart 에서 Upstream 서버를 위한 구성으로 upstream 는 더 이상 사용하지 않고, 대신 extraFiles 을 사용합니다.

다음은 fluentbit.yaml 설정 파일에 대한 설명입니다:

  • image
    cr.fluentbit.io/fluent/fluent-bit 이미지에서 디버깅을 위해 Shell 접근을 할 수 있는 latest-debug Tag 를 사용합니다.

  • service
    NodePort 타입으로 24224 를 사용합니다.

  • config.inputs
    Input 파이프라인으로 tail 과 forward 를 구성합니다.

    • tail
      • 노드의 컨테이너 로그 경로: /var/log/containers/
      • docker, cri multiline parser 설정
    • forward
      • 0.0.0.0:24224 로 forward 를 받습니다.
  • config.outputs
    Output 파이프라인으로 stdout 과 forward 를 구성합니다.

    • stdout
      • 컨테이너 stdout 으로 출력합니다.
    • forward
      • Upstream 서버로 forward 보냅니다.
  • config.extraFiles

    • upstream.conf
      upstream 노드 구성입니다.

      collector-fluentd-aggregator:24224 노드로 forward 보냅니다.


fluent/helm-charts 의 Helm Chart 템플릿, 기본 값들은 ArtifactHub fluent/fluent-bit 을 참고하세요.




테스트하기

다음 명령으로 /var/log/containers 볼륨이 마운트된 Pod 에 접속합니다:

kubectl exec -it $(kubectl get pod -l app.kubernetes.io/instance=aggregator -o jsonpath="{.items[0].metadata.name}") -- /bin/bash

접속한 Pod 에서 로깅하기 위해 다음 명령을 실행합니다:

echo '{"message":"hello"}' >> /var/log/containers/debug.log

exitPod Shell 에서 나온 후,
접속한 Pod 에서 로깅을 확인하기 위해 다음 명령을 실행합니다:

kubectl logs -f collector-fluentd-0

로그가 잘 출력되는 것을 확인할 수 있습니다:

... kube.var.log.containers.debug.log: {"message":"{\"message\":\"hello\"}"}      

Flush 구성에 따라 로그가 수집되는 데 약간의 시간이 걸릴 수도 있습니다.




결론

Fluent Bit 과 Fluentd 는 Observability Pipeline 이라는 컨셉의 솔루션입니다.
모니터링은 앱을 추적하고 관리하기 위해 정보를 수집, 분석 및 사용하는 과정입니다.
Observability 는 관찰가능성이라는 의미로 로그, 메트릭(Metrics) 및 추적(Traces)과 같이 시스템이 생성하는 데이터를 분석하여 시스템의 내부 상태를 이해하는 기능입니다. Observability는 팀이 멀티 클라우드 환경에서 컨텍스트에서 발생하는 상황을 분석하여 문제의 근본적인 원인을 감지하고 해결할 수 있도록 도와줍니다.


이 글에서는 Fluent Bit, Fluentd 를 쿠버네티스에 배포하고 구성을 테스트하는 방법을 소개했습니다. 😎




참고자료

쿠버네티스

Fluent

Helm Chart

댓글남기기