쿠버네티스에서 Fluent Bit 테스트하기
이 글에서는 Kind 클러스터에서 Fluent Bit 을 구성하고 테스트하는 방법을 소개합니다.
다음은 우리가 구성할 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 라고 하겠습니다.
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을 가집니다.
- Daemonset은 Pod 를 클러스터의 모든 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
플러그인을 사용하여 이벤트를 전송합니다.
exit
로 Pod 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 라고 하겠습니다.
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
exit
로 Pod 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
- Fluent Bit v2.0 Documentation
- Configuration
- Administration
- Output Plugins
댓글남기기