- Published on
Fluent Bit 완벽 가이드: 경량 로그 프로세서의 아키텍처, 설정, Kubernetes 연동까지 총정리
- Authors
- Name
- 1. Fluent Bit 소개
- 2. 핵심 아키텍처: 파이프라인 구조
- 3. 설치 방법
- 4. 설정 파일 구조
- 5. Input 플러그인 상세
- 6. Parser 설정
- 7. Filter 플러그인 상세
- 8. Output 플러그인 상세
- 9. Buffer와 Backpressure 관리
- 10. Kubernetes 연동 완벽 가이드
- 11. 실전 파이프라인 예제
- 12. 성능 튜닝
- 13. 모니터링 및 Observability
- 14. 트러블슈팅 가이드
- 15. 운영 Best Practices
- 16. 참고 자료
1. Fluent Bit 소개
1.1 Fluent Bit이란?
Fluent Bit은 C 언어로 작성된 초경량 텔레메트리 에이전트로, 다양한 소스에서 로그(Logs), 메트릭(Metrics), **트레이스(Traces)**를 수집하고, 처리한 뒤 원하는 목적지로 전달하는 역할을 한다. 바이너리 크기 약 450KB, 메모리 사용량 1MB 미만이라는 극도로 가벼운 풋프린트를 자랑하며, 임베디드 시스템부터 대규모 Kubernetes 클러스터까지 폭넓게 활용된다.
Fluent Bit은 CNCF(Cloud Native Computing Foundation) Graduated 프로젝트로, Kubernetes, Prometheus, Envoy 등과 같은 레벨의 성숙도를 인정받았다. Fluentd 프로젝트의 산하에서 2019년에 졸업 지위를 획득했으며, 2024년 기준 DockerHub에서 130억 회 이상 다운로드되며 클라우드 네이티브 로그 수집의 사실상 표준으로 자리잡았다.
2024년 3월 KubeCon + CloudNativeCon EU에서 Fluent Bit v3가 발표되었으며, 같은 해 12월 v3.2, 2025년 3월에는 v4.0이 출시되어 YAML 표준 설정, Processor 지원, SIMD 기반 JSON 인코딩(2.5배 성능 향상), OpenTelemetry 강화 등 지속적으로 진화하고 있다.
1.2 핵심 특징
- 초경량: C 기반, ~450KB 바이너리, 1MB 미만 메모리 사용
- 고성능: 비동기 I/O, 멀티스레드 파이프라인, SIMD 최적화
- 플러그인 아키텍처: 100개 이상의 Input/Filter/Output 플러그인
- 통합 텔레메트리: Logs, Metrics, Traces 단일 에이전트로 처리
- YAML 네이티브: v3.2부터 YAML이 표준 설정 포맷
- Hot Reload: 서비스 중단 없이 설정 재로드 (SIGHUP / HTTP API)
- 크로스 플랫폼: Linux, macOS, Windows, BSD, 임베디드 Linux 지원
1.3 Fluent Bit vs Fluentd 비교
| 항목 | Fluent Bit | Fluentd |
|---|---|---|
| 개발 언어 | C | Ruby + C |
| 바이너리 크기 | ~450KB | ~40MB |
| 메모리 사용량 | ~1MB | ~30-40MB |
| 플러그인 수 | 100개 이상 (내장) | 1,000개 이상 (gem 포함) |
| 성능(처리량) | 매우 높음 | 높음 |
| CPU 사용량 | 낮음 | Fluent Bit 대비 4배 |
| 설정 형식 | INI / YAML | Ruby DSL |
| 주요 용도 | 에지/노드 레벨 수집 및 전달 | 중앙 집중식 로그 집계 |
| Kubernetes | DaemonSet으로 노드별 배포 | Aggregator로 중앙 배포 |
| CNCF 상태 | Graduated (Fluentd 산하) | Graduated |
| 적합 환경 | IoT, 컨테이너, 에지 | 대규모 집계, 복잡한 라우팅 |
일반적 권장 아키텍처: Fluent Bit을 각 노드에 DaemonSet으로 배포하여 로그를 수집하고, 필요시 중앙의 Fluentd Aggregator로 전달하는 하이브리드 패턴이 가장 널리 사용된다. 다만 Fluent Bit의 기능이 꾸준히 강화되면서 Fluentd 없이 Fluent Bit만으로 전체 파이프라인을 구성하는 사례도 빠르게 늘고 있다.
1.4 아키텍처 개요
+------------------------------------------------------------------+
| Fluent Bit Engine |
| |
| +--------+ +--------+ +--------+ +--------+ +--------+ |
| | Input |-->| Parser |-->| Filter |-->| Buffer |-->| Output | |
| +--------+ +--------+ +--------+ +--------+ +--------+ |
| | tail | | json | | k8s | | memory | | es | |
| | systemd| | regex | | grep | | filesys| | loki | |
| | forward| | logfmt | | modify | | | | s3 | |
| | http | | cri | | lua | | | | kafka | |
| | tcp | | docker | | nest | | | | stdout | |
| +--------+ +--------+ +--------+ +--------+ +--------+ |
| |
| [Scheduler] [Router / Tag Matching] [HTTP Server / Monitoring]|
+------------------------------------------------------------------+
Fluent Bit의 데이터 처리는 파이프라인(Pipeline) 구조를 따르며, 각 단계가 명확하게 분리되어 있다. 이 구조 덕분에 모듈별 독립적 확장과 교체가 가능하다.
2. 핵심 아키텍처: 파이프라인 구조
2.1 파이프라인 전체 흐름
Fluent Bit의 데이터 처리 파이프라인은 다음과 같은 단계로 구성된다.
[Data Source]
|
v
+---------+ +---------+ +---------+ +---------+ +---------+
| INPUT | --> | PARSER | --> | FILTER | --> | BUFFER | --> | OUTPUT |
| | | | | | | | | |
| 데이터 | | 비정형 | | 데이터 | | 메모리/ | | 최종 |
| 수집 | | -> 정형 | | 가공 | | 디스크 | | 전달 |
+---------+ +---------+ +---------+ +---------+ +---------+
| | | | |
Tag 부여 구조화 변환 enrichment 안정성 보장 목적지 전송
필터링 (Tag 매칭)
2.2 각 단계별 역할
Input (입력)
데이터의 진입점이다. 파일, 시스템 저널, 네트워크 소켓, Kubernetes 이벤트 등 다양한 소스에서 데이터를 수집한다. 모든 입력 데이터에는 Tag가 부여되며, 이 Tag는 이후 라우팅에 사용된다.
Parser (파서)
비정형(unstructured) 텍스트 데이터를 정형(structured) 데이터로 변환한다. JSON, 정규식(Regex), Logfmt, Docker, CRI 등 다양한 파서를 제공하며, Input 플러그인 단계에서 적용된다.
Filter (필터)
수집된 데이터를 가공하는 단계이다. 필드 추가/삭제, Kubernetes 메타데이터 enrichment, 정규식 기반 필터링, Lua 스크립트 변환 등을 수행한다. 여러 Filter를 체이닝하여 복잡한 변환 로직을 구성할 수 있다.
Buffer (버퍼)
Filter를 통과한 데이터는 Output으로 전달되기 전에 버퍼에 저장된다. 메모리 버퍼와 파일시스템 버퍼 두 가지 방식을 지원하며, 파일시스템 버퍼를 사용하면 장애 시에도 데이터 손실을 방지할 수 있다.
Router (라우터)
Tag 매칭 규칙에 따라 데이터를 적절한 Output으로 라우팅한다. 와일드카드(*) 매칭을 지원하며, 하나의 입력을 여러 Output으로 동시에 전달(fan-out)할 수 있다.
Output (출력)
최종 목적지로 데이터를 전송한다. Elasticsearch, Loki, S3, Kafka, CloudWatch, Prometheus 등 다양한 백엔드를 지원한다. 전송 실패 시 자동 재시도(Retry) 메커니즘이 작동한다.
2.3 멀티 파이프라인 구조
Fluent Bit은 단일 인스턴스에서 여러 개의 독립적인 파이프라인을 동시에 운영할 수 있다. 각 파이프라인은 고유한 Input, Filter, Output 조합을 가지며, Tag 기반 라우팅으로 서로 다른 데이터 흐름을 분리한다.
Pipeline A: [tail: app-*.log] --tag:app--> [filter:k8s] --> [output:elasticsearch]
Pipeline B: [tail: sys-*.log] --tag:sys--> [filter:grep] --> [output:loki]
Pipeline C: [forward:24224] --tag:fwd--> [filter:lua] --> [output:s3]
이 구조는 다음과 같은 이점을 제공한다.
- 격리성: 파이프라인 간 독립적 동작으로 장애 전파 방지
- 유연성: 용도별로 다른 처리 로직과 목적지 지정
- 효율성: 단일 에이전트로 다양한 데이터 흐름 처리
3. 설치 방법
3.1 Linux (apt/yum)
Ubuntu/Debian (apt)
# GPG 키 및 저장소 추가
curl https://raw.githubusercontent.com/fluent/fluent-bit/master/install.sh | sh
# 또는 수동 설치
wget -qO - https://packages.fluentbit.io/fluentbit.key | sudo apt-key add -
echo "deb https://packages.fluentbit.io/ubuntu/$(lsb_release -cs) $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/fluent-bit.list
sudo apt-get update
sudo apt-get install -y fluent-bit
# 서비스 시작
sudo systemctl start fluent-bit
sudo systemctl enable fluent-bit
CentOS/RHEL (yum)
cat > /etc/yum.repos.d/fluent-bit.repo << 'EOF'
[fluent-bit]
name=Fluent Bit
baseurl=https://packages.fluentbit.io/centos/$releasever/
gpgcheck=1
gpgkey=https://packages.fluentbit.io/fluentbit.key
enabled=1
EOF
sudo yum install -y fluent-bit
sudo systemctl start fluent-bit
sudo systemctl enable fluent-bit
3.2 Docker
# 최신 버전 실행
docker run -ti cr.fluentbit.io/fluent/fluent-bit:latest
# 설정 파일 마운트
docker run -ti \
-v /path/to/fluent-bit.yaml:/fluent-bit/etc/fluent-bit.yaml \
-v /var/log:/var/log \
cr.fluentbit.io/fluent/fluent-bit:latest \
/fluent-bit/bin/fluent-bit -c /fluent-bit/etc/fluent-bit.yaml
# Docker Compose 예시
cat > docker-compose.yaml << 'EOF'
version: '3.8'
services:
fluent-bit:
image: cr.fluentbit.io/fluent/fluent-bit:latest
volumes:
- ./fluent-bit.yaml:/fluent-bit/etc/fluent-bit.yaml
- /var/log:/var/log:ro
ports:
- "2020:2020" # HTTP 모니터링
- "24224:24224" # Forward 프로토콜
EOF
3.3 macOS (Homebrew)
brew install fluent-bit
# 실행
fluent-bit -c /opt/homebrew/etc/fluent-bit/fluent-bit.conf
# 또는 YAML 설정 파일로 실행
fluent-bit -c /path/to/fluent-bit.yaml
3.4 Kubernetes (Helm Chart)
# Helm 저장소 추가
helm repo add fluent https://fluent.github.io/helm-charts
helm repo update
# 기본 설치
helm install fluent-bit fluent/fluent-bit \
--namespace logging \
--create-namespace
# values.yaml 커스터마이징으로 설치
helm install fluent-bit fluent/fluent-bit \
--namespace logging \
--create-namespace \
-f custom-values.yaml
# 업그레이드
helm upgrade fluent-bit fluent/fluent-bit \
--namespace logging \
-f custom-values.yaml
3.5 바이너리 직접 설치
# GitHub Releases에서 바이너리 다운로드
FLUENT_BIT_VERSION=3.2.2
wget https://github.com/fluent/fluent-bit/releases/download/v${FLUENT_BIT_VERSION}/fluent-bit-${FLUENT_BIT_VERSION}-linux-x86_64.tar.gz
tar xzf fluent-bit-${FLUENT_BIT_VERSION}-linux-x86_64.tar.gz
cd fluent-bit-${FLUENT_BIT_VERSION}-linux-x86_64/
# 실행
./bin/fluent-bit -c conf/fluent-bit.yaml
# 버전 확인
./bin/fluent-bit --version
4. 설정 파일 구조
Fluent Bit은 **Classic 모드(INI 형식)**와 YAML 모드 두 가지 설정 형식을 지원한다. v3.2부터 YAML이 표준 설정 포맷이며, Classic 모드는 2025년 말 deprecated 예정이다.
4.1 Classic 모드 (fluent-bit.conf)
# fluent-bit.conf - Classic INI 형식
[SERVICE]
Flush 5
Daemon Off
Log_Level info
Parsers_File parsers.conf
HTTP_Server On
HTTP_Listen 0.0.0.0
HTTP_Port 2020
Hot_Reload On
[INPUT]
Name tail
Path /var/log/containers/*.log
Parser cri
Tag kube.*
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
DB /var/log/flb_kube.db
[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
Merge_Log On
K8S-Logging.Parser On
K8S-Logging.Exclude On
[OUTPUT]
Name es
Match kube.*
Host elasticsearch.logging.svc.cluster.local
Port 9200
Logstash_Format On
Logstash_Prefix kube
Retry_Limit False
4.2 YAML 모드 (fluent-bit.yaml)
# fluent-bit.yaml - YAML 형식 (v3.2+ 표준)
service:
flush: 5
daemon: off
log_level: info
parsers_file: parsers.conf
http_server: on
http_listen: 0.0.0.0
http_port: 2020
hot_reload: on
pipeline:
inputs:
- name: tail
path: /var/log/containers/*.log
parser: cri
tag: kube.*
mem_buf_limit: 5MB
skip_long_lines: on
refresh_interval: 10
db: /var/log/flb_kube.db
filters:
- 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
merge_log: on
k8s-logging.parser: on
k8s-logging.exclude: on
outputs:
- name: es
match: kube.*
host: elasticsearch.logging.svc.cluster.local
port: 9200
logstash_format: on
logstash_prefix: kube
retry_limit: false
4.3 두 형식 비교
| 항목 | Classic (INI) | YAML |
|---|---|---|
| 파일 확장자 | .conf | .yaml / .yml |
| 상태 | Deprecated 예정 (2025 말) | 표준 (v3.2+) |
| Processor 지원 | 미지원 | 지원 |
| 가독성 | 보통 | 우수 |
| 중첩 구조 | 제한적 | 완전 지원 |
| 배열/리스트 | 미지원 | 지원 |
| 주석 | # | # |
4.4 환경변수 사용
두 형식 모두 ${ENV_VAR} 문법으로 환경변수를 참조할 수 있다.
# YAML 환경변수 예시
pipeline:
outputs:
- name: es
match: '*'
host: ${ELASTICSEARCH_HOST}
port: ${ELASTICSEARCH_PORT}
http_user: ${ES_USER}
http_passwd: ${ES_PASSWORD}
tls: ${ES_TLS_ENABLED}
# Classic 환경변수 예시
[OUTPUT]
Name es
Match *
Host ${ELASTICSEARCH_HOST}
Port ${ELASTICSEARCH_PORT}
HTTP_User ${ES_USER}
HTTP_Passwd ${ES_PASSWORD}
v4.0부터는 file:// 프리픽스를 사용하여 파일시스템에서 시크릿 값을 안전하게 참조할 수 있다.
pipeline:
outputs:
- name: es
http_passwd: file:///run/secrets/es-password
4.5 @INCLUDE 디렉티브
설정 파일을 모듈화하여 관리할 수 있다.
# fluent-bit.conf (Classic)
[SERVICE]
Flush 5
@INCLUDE inputs.conf
@INCLUDE filters.conf
@INCLUDE outputs.conf
YAML에서는 includes 섹션을 활용한다.
# fluent-bit.yaml
includes:
- inputs.yaml
- filters.yaml
- outputs.yaml
service:
flush: 5
5. Input 플러그인 상세
Input 플러그인은 데이터 수집의 시작점이다. 각 Input에는 고유한 Tag가 부여되어 이후 Filter와 Output의 매칭 기준이 된다.
5.1 tail: 파일 로그 수집
가장 많이 사용되는 Input 플러그인으로, tail -f처럼 파일의 끝부터 새로운 라인을 실시간으로 읽는다.
pipeline:
inputs:
- name: tail
tag: app.logs
path: /var/log/app/*.log
path_key: filename # 파일 경로를 레코드에 포함
exclude_path: /var/log/app/debug.log # 특정 파일 제외
parser: json # 기본 파서
db: /var/log/flb_app.db # offset 저장 DB (재시작 시 이어서 수집)
db.sync: normal # DB 동기화 모드
refresh_interval: 10 # 파일 목록 갱신 주기 (초)
read_from_head: false # true: 파일 처음부터 읽기
skip_long_lines: on # 매우 긴 라인 스킵
mem_buf_limit: 5MB # 메모리 버퍼 한도
rotate_wait: 5 # 로테이션 대기 시간 (초)
multiline.parser: docker, cri # 멀티라인 파서
주요 설정 항목 설명
| 설정 | 기본값 | 설명 |
|---|---|---|
Path | (필수) | 로그 파일 경로 (와일드카드 지원) |
Path_Key | - | 파일 경로를 레코드에 키로 추가 |
Exclude_Path | - | 제외할 파일 경로 |
DB | - | 파일 offset 저장 SQLite DB 경로 |
Refresh_Interval | 60 | 파일 목록 갱신 주기 (초) |
Read_from_Head | false | 파일 처음부터 읽을지 여부 |
Skip_Long_Lines | Off | Buffer_Max_Size 초과 라인 스킵 |
Mem_Buf_Limit | - | 메모리 버퍼 한도 |
Rotate_Wait | 5 | 로그 로테이션 후 대기 시간 |
5.2 systemd: systemd journal 수집
pipeline:
inputs:
- name: systemd
tag: host.systemd
systemd_filter: _SYSTEMD_UNIT=docker.service
systemd_filter: _SYSTEMD_UNIT=kubelet.service
read_from_tail: on
strip_underscores: on
db: /var/log/flb_systemd.db
5.3 forward: Fluentd 프로토콜 수신
pipeline:
inputs:
- name: forward
tag: forward.incoming
listen: 0.0.0.0
port: 24224
buffer_chunk_size: 1M
buffer_max_size: 6M
5.4 http / tcp / udp: 네트워크 수신
pipeline:
inputs:
# HTTP 수신
- name: http
tag: http.logs
listen: 0.0.0.0
port: 9880
successful_response_code: 201
# TCP 수신
- name: tcp
tag: tcp.logs
listen: 0.0.0.0
port: 5170
format: json
# UDP 수신
- name: udp
tag: udp.logs
listen: 0.0.0.0
port: 5170
format: json
5.5 kubernetes_events: K8s 이벤트 수집
pipeline:
inputs:
- name: kubernetes_events
tag: kube.events
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
interval_sec: 1
retention_time: 1h
5.6 node_exporter_metrics / prometheus_scrape
pipeline:
inputs:
# 노드 메트릭 수집
- name: node_exporter_metrics
tag: node.metrics
scrape_interval: 30
# Prometheus 엔드포인트 스크레이핑
- name: prometheus_scrape
tag: prom.metrics
host: 127.0.0.1
port: 9090
metrics_path: /metrics
scrape_interval: 10s
5.7 fluentbit_metrics: 내부 메트릭
pipeline:
inputs:
- name: fluentbit_metrics
tag: fb.metrics
scrape_interval: 30
scrape_on_start: true
6. Parser 설정
Parser는 비정형 텍스트 로그를 정형 데이터로 변환하는 핵심 컴포넌트이다. 별도의 parsers.conf 또는 YAML 파일에 정의한다.
6.1 내장 파서
Fluent Bit은 자주 사용되는 로그 형식에 대한 내장 파서를 제공한다.
| 파서 | 형식 | 용도 |
|---|---|---|
json | JSON | JSON 형식 로그 |
docker | JSON (Docker 특화) | Docker 컨테이너 로그 |
cri | 정규식 | CRI (containerd) 로그 |
syslog-rfc5424 | 정규식 | RFC 5424 Syslog |
syslog-rfc3164 | 정규식 | RFC 3164 Syslog |
apache | 정규식 | Apache 액세스 로그 |
nginx | 정규식 | Nginx 액세스 로그 |
logfmt | Logfmt | key=value 쌍 형식 |
6.2 커스텀 정규식 파서 작성
# parsers.conf
# Nginx 에러 로그 파서
[PARSER]
Name nginx_error
Format regex
Regex ^(?<time>\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[(?<level>\w+)\] (?<pid>\d+).(?<tid>\d+): (?<message>.*)$
Time_Key time
Time_Format %Y/%m/%d %H:%M:%S
# Spring Boot 로그 파서
[PARSER]
Name spring_boot
Format regex
Regex ^(?<time>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+)\s+(?<level>\w+)\s+(?<pid>\d+)\s+---\s+\[(?<thread>[^\]]+)\]\s+(?<logger>\S+)\s+:\s+(?<message>.*)$
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
# Apache Combined 로그 파서
[PARSER]
Name apache_combined
Format regex
Regex ^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$
Time_Key time
Time_Format %d/%b/%Y:%H:%M:%S %z
YAML 형식으로도 동일하게 정의할 수 있다.
# parsers.yaml
parsers:
- name: nginx_error
format: regex
regex: '^(?<time>\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[(?<level>\w+)\] (?<pid>\d+).(?<tid>\d+): (?<message>.*)$'
time_key: time
time_format: '%Y/%m/%d %H:%M:%S'
- name: spring_boot
format: regex
regex: '^(?<time>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+)\s+(?<level>\w+)\s+(?<pid>\d+)\s+---\s+\[(?<thread>[^\]]+)\]\s+(?<logger>\S+)\s+:\s+(?<message>.*)$'
time_key: time
time_format: '%Y-%m-%dT%H:%M:%S.%L'
6.3 멀티라인 파서
Java Stack Trace와 같이 여러 라인에 걸친 로그를 하나의 레코드로 병합한다.
# 멀티라인 파서 정의
[MULTILINE_PARSER]
Name java_stacktrace
Type regex
Flush_Timeout 1000
# 첫 줄 패턴: 타임스탬프로 시작
Rule "start_state" "/^\d{4}-\d{2}-\d{2}/" "cont"
# 연속 줄 패턴: 공백이나 Caused by로 시작
Rule "cont" "/^\s+|^Caused by:/" "cont"
[MULTILINE_PARSER]
Name python_traceback
Type regex
Flush_Timeout 1000
Rule "start_state" "/^Traceback/" "python_tb"
Rule "python_tb" "/^\s+/" "python_tb"
Rule "python_tb" "/^\w+Error/" "end"
Input에서 멀티라인 파서를 적용하는 방법은 다음과 같다.
pipeline:
inputs:
- name: tail
tag: app.java
path: /var/log/app/application.log
multiline.parser: java_stacktrace
read_from_head: true
6.4 Time_Key와 Time_Format
로그 메시지에서 타임스탬프를 추출하여 레코드의 시간으로 사용한다.
[PARSER]
Name custom_time
Format regex
Regex ^(?<time>[^ ]+) (?<message>.*)$
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%LZ
Time_Keep On # 변환 후에도 time 필드 유지
Time_Offset +0900 # KST 타임존
6.5 파서 테스트 및 디버깅
파서 동작을 검증하는 가장 쉬운 방법은 stdout Output을 사용하는 것이다.
# 파서 테스트용 설정
service:
flush: 1
log_level: debug
pipeline:
inputs:
- name: tail
tag: test
path: /tmp/test.log
parser: my_custom_parser
outputs:
- name: stdout
match: test
format: json_lines
# 테스트 로그 생성 및 확인
echo '2026-03-01T12:00:00.000Z ERROR [main] App - Connection failed' >> /tmp/test.log
fluent-bit -c test.yaml
7. Filter 플러그인 상세
Filter 플러그인은 수집된 데이터를 가공하는 중간 단계이다. 여러 Filter를 순서대로 체이닝하여 복잡한 변환 파이프라인을 구성할 수 있다.
7.1 kubernetes: Pod 메타데이터 enrichment
Kubernetes 환경에서 가장 중요한 필터로, 컨테이너 로그에 Pod 이름, Namespace, Labels, Annotations 등의 메타데이터를 자동으로 추가한다.
pipeline:
filters:
- 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
merge_log: on # JSON 로그를 최상위로 병합
merge_log_key: log_parsed # 병합 키 이름
keep_log: off # 원본 log 필드 제거
k8s-logging.parser: on # Pod 어노테이션의 파서 설정 사용
k8s-logging.exclude: on # Pod 어노테이션으로 로그 제외
labels: on # Pod Labels 포함
annotations: off # Pod Annotations 포함 여부
buffer_size: 0 # API 응답 버퍼 (0=무제한)
kube_meta_cache_ttl: 300 # 메타데이터 캐시 TTL (초)
use_kubelet: false # kubelet API 사용 여부
enrichment 후 레코드 구조 예시는 다음과 같다.
{
"log": "Connection established to database",
"kubernetes": {
"pod_name": "api-server-7d4b8c6f5-x2k9j",
"namespace_name": "production",
"pod_id": "abc-123-def",
"container_name": "api-server",
"container_image": "myregistry/api-server:v2.1.0",
"labels": {
"app": "api-server",
"version": "v2.1.0",
"team": "backend"
},
"host": "node-01"
}
}
7.2 modify: 필드 추가/삭제/이름 변경
pipeline:
filters:
- name: modify
match: "*"
# 필드 추가
add: environment production
add: cluster_name main-cluster
# 필드 이름 변경
rename: log message
rename: stream source
# 필드 삭제
remove: unwanted_field
# 조건부 필드 추가 (키가 없을 때만)
set: default_level INFO
# 하드카피
copy: source source_backup
7.3 grep: 정규식 기반 필터링
특정 패턴에 매칭되는 레코드만 통과시키거나 제외할 수 있다.
pipeline:
filters:
# ERROR 또는 WARN 레벨만 통과
- name: grep
match: app.*
regex: level (ERROR|WARN)
# healthcheck 경로 제외
- name: grep
match: access.*
exclude: path /health
# 특정 네임스페이스만 통과
- name: grep
match: kube.*
regex: $kubernetes['namespace_name'] ^(production|staging)$
# 여러 조건 조합 (AND)
- name: grep
match: app.*
regex: level ERROR
regex: message .*timeout.*
7.4 record_modifier: 레코드 변경
pipeline:
filters:
- name: record_modifier
match: "*"
record: hostname ${HOSTNAME}
record: service_name my-application
remove_key: unnecessary_field
allowlist_key: timestamp
allowlist_key: level
allowlist_key: message
7.5 nest: 중첩 구조 변환
플랫 구조를 중첩 구조로 변환하거나 그 반대로 변환한다.
pipeline:
filters:
# 중첩(Nest): 플랫 -> 중첩
- name: nest
match: '*'
operation: nest
wildcard: 'app_*'
nest_under: application
# app_name, app_version -> application: { name, version }
# 해제(Lift): 중첩 -> 플랫
- name: nest
match: '*'
operation: lift
nested_under: kubernetes
# kubernetes: { pod_name, namespace } -> pod_name, namespace
7.6 lua: Lua 스크립트 기반 커스텀 변환
가장 유연한 변환 방법으로, Lua 스크립트로 복잡한 로직을 구현할 수 있다.
pipeline:
filters:
- name: lua
match: app.*
script: /fluent-bit/scripts/transform.lua
call: process_log
-- /fluent-bit/scripts/transform.lua
function process_log(tag, timestamp, record)
-- 로그 레벨 정규화
if record["level"] then
record["level"] = string.upper(record["level"])
end
-- 민감 정보 마스킹
if record["message"] then
record["message"] = string.gsub(
record["message"],
"%d%d%d%d%-%d%d%d%d%-%d%d%d%d%-%d%d%d%d",
"****-****-****-****"
)
end
-- 응답 시간에 따른 등급 추가
if record["response_time"] then
local rt = tonumber(record["response_time"])
if rt > 5000 then
record["performance"] = "critical"
elseif rt > 1000 then
record["performance"] = "slow"
else
record["performance"] = "normal"
end
end
-- 타임스탬프 필드 추가
record["processed_at"] = os.date("!%Y-%m-%dT%H:%M:%SZ")
-- 2 = MODIFIED
return 2, timestamp, record
end
Lua 콜백 함수의 반환값은 다음과 같다.
| 코드 | 의미 |
|---|---|
| -1 | 레코드 삭제 (Drop) |
| 0 | 원본 유지 (Keep) |
| 1 | 타임스탬프만 변경 |
| 2 | 레코드 변경 (Modified) |
7.7 rewrite_tag: 태그 기반 라우팅 변경
레코드의 내용에 따라 Tag를 동적으로 변경하여 다른 Output으로 라우팅할 수 있다.
pipeline:
filters:
- name: rewrite_tag
match: kube.*
rule: $kubernetes['namespace_name'] ^(production)$ prod.$TAG false
rule: $kubernetes['namespace_name'] ^(staging)$ stg.$TAG false
rule: $level ^(ERROR)$ alert.$TAG false
Rule 문법: rule: $KEY REGEX NEW_TAG KEEP_ORIGINAL
$KEY: 매칭할 필드REGEX: 정규식 패턴NEW_TAG: 새로운 TagKEEP_ORIGINAL: 원본도 유지할지 여부 (true/false)
7.8 throttle: 로그 속도 제한
과도한 로그 생성을 제한하여 시스템을 보호한다.
pipeline:
filters:
- name: throttle
match: app.*
rate: 1000 # 윈도우당 허용량
window: 5 # 윈도우 크기 (초)
interval: 1s # 평가 주기
print_status: true # 상태 출력
7.9 multiline: 멀티라인 로그 병합
Filter 단계에서 멀티라인 로그를 병합하는 방식이다 (Input의 multiline.parser와는 별도).
pipeline:
filters:
- name: multiline
match: app.*
multiline.parser: java_stacktrace
multiline.key_content: log
8. Output 플러그인 상세
Output 플러그인은 처리된 데이터를 최종 목적지로 전송한다. 하나의 Fluent Bit 인스턴스에서 여러 Output을 동시에 사용할 수 있다.
8.1 elasticsearch / opensearch
pipeline:
outputs:
# Elasticsearch
- name: es
match: kube.*
host: ${ES_HOST}
port: 9200
index: logs
type: _doc
http_user: ${ES_USER}
http_passwd: ${ES_PASSWORD}
logstash_format: on
logstash_prefix: kube-logs
logstash_dateformat: %Y.%m.%d
time_key: '@timestamp'
include_tag_key: true
tag_key: fluentbit_tag
generate_id: on # 중복 방지 ID 생성
buffer_size: 512KB
tls: on
tls.verify: on
tls.ca_file: /certs/ca.pem
retry_limit: 5
workers: 2
suppress_type_name: on # ES 8.x 호환
# OpenSearch
- name: opensearch
match: app.*
host: opensearch.logging.svc
port: 9200
index: app-logs
http_user: admin
http_passwd: ${OPENSEARCH_PASSWORD}
tls: on
suppress_type_name: on
trace_output: off
주요 설정 항목
| 설정 | 기본값 | 설명 |
|---|---|---|
Host | 127.0.0.1 | Elasticsearch 호스트 |
Port | 9200 | 포트 번호 |
Index | fluent-bit | 인덱스 이름 |
Logstash_Format | Off | 날짜 기반 인덱스 사용 |
Logstash_Prefix | logstash | 인덱스 접두어 |
HTTP_User | - | Basic Auth 사용자 |
HTTP_Passwd | - | Basic Auth 비밀번호 |
TLS | Off | TLS 활성화 |
Generate_ID | Off | 문서 ID 자동 생성 |
Workers | 0 | 병렬 Worker 수 |
Retry_Limit | 1 | 재시도 횟수 (False=무한) |
Suppress_Type_Name | Off | ES 8.x _type 비활성화 |
8.2 loki: Grafana Loki 연동
pipeline:
outputs:
- name: loki
match: kube.*
host: loki-gateway.logging.svc
port: 3100
uri: /loki/api/v1/push
tenant_id: my-tenant
labels: job=fluent-bit
label_keys: $kubernetes['namespace_name'],$kubernetes['pod_name'],$kubernetes['container_name']
label_map_path: /fluent-bit/etc/loki-labelmap.json
remove_keys: kubernetes,stream
auto_kubernetes_labels: on
line_format: json
drop_single_key: on
http_user: ${LOKI_USER}
http_passwd: ${LOKI_PASSWORD}
tls: on
tls.verify: on
workers: 2
Loki Label Map 파일 예시
{
"kubernetes": {
"namespace_name": "namespace",
"pod_name": "pod",
"container_name": "container",
"labels": {
"app": "app"
}
},
"stream": "stream"
}
8.3 s3: AWS S3 저장
pipeline:
outputs:
- name: s3
match: archive.*
region: ap-northeast-2
bucket: my-log-bucket
s3_key_format: /logs/$TAG/%Y/%m/%d/%H/$UUID.gz
s3_key_format_tag_delimiters: .
total_file_size: 50M # 이 크기에 도달하면 업로드
upload_timeout: 10m # 크기 미달이라도 이 시간 후 업로드
use_put_object: on
compression: gzip
content_type: application/gzip
store_dir: /tmp/fluent-bit-s3 # 로컬 버퍼 디렉터리
store_dir_limit_size: 512M
retry_limit: 5
# IAM 역할 사용 시 (IRSA / EKS Pod Identity)
role_arn: arn:aws:iam::123456789012:role/fluent-bit-s3
# 정적 자격증명 (비권장)
# endpoint:
# sts_endpoint:
8.4 kafka: Kafka 연동
pipeline:
outputs:
- name: kafka
match: app.*
brokers: kafka-0:9092,kafka-1:9092,kafka-2:9092
topics: application-logs
timestamp_key: '@timestamp'
timestamp_format: iso8601
format: json
message_key: log
queue_full_retries: 10
rdkafka.request.required.acks: 1
rdkafka.log.connection.close: false
rdkafka.compression.codec: snappy
8.5 cloudwatch_logs: AWS CloudWatch
pipeline:
outputs:
- name: cloudwatch_logs
match: kube.*
region: ap-northeast-2
log_group_name: /eks/my-cluster/containers
log_group_template: /eks/my-cluster/$kubernetes['namespace_name']
log_stream_prefix: from-fluent-bit-
log_stream_template: $kubernetes['pod_name']
auto_create_group: on
extra_user_agent: fluent-bit
retry_limit: 5
workers: 1
8.6 stdout: 디버깅용 표준 출력
pipeline:
outputs:
- name: stdout
match: '*'
format: json_lines # json_lines | msgpack
8.7 forward: Fluentd로 전달
pipeline:
outputs:
- name: forward
match: '*'
host: fluentd-aggregator.logging.svc
port: 24224
time_as_integer: off
send_options: true
require_ack_response: true
# TLS
tls: on
tls.verify: on
tls.ca_file: /certs/ca.pem
# 공유 키 인증
shared_key: my-shared-secret
self_hostname: fluent-bit-node01
8.8 prometheus_exporter: 메트릭 노출
pipeline:
outputs:
- name: prometheus_exporter
match: metrics.*
host: 0.0.0.0
port: 2021
add_label: app fluent-bit
9. Buffer와 Backpressure 관리
대규모 환경에서는 로그 생성 속도가 전송 속도를 초과할 수 있다. Fluent Bit의 Buffer와 Backpressure 관리를 올바르게 설정하면 데이터 손실 없이 안정적으로 운영할 수 있다.
9.1 메모리 버퍼 vs 파일시스템 버퍼
| 항목 | 메모리 버퍼 | 파일시스템 버퍼 |
|---|---|---|
| 저장 위치 | RAM | 디스크 + RAM (하이브리드) |
| 속도 | 매우 빠름 | 상대적으로 느림 |
| 데이터 안전성 | 프로세스 종료 시 손실 | 디스크에 보존 |
| 용량 한계 | RAM 크기 제한 | 디스크 크기까지 확장 |
| 설정 복잡도 | 단순 | 추가 설정 필요 |
| 적합 환경 | 개발/테스트 | 프로덕션 |
9.2 Service 레벨 설정
service:
flush: 1
log_level: info
# 파일시스템 버퍼 활성화
storage.path: /var/log/fluent-bit/buffer/
storage.sync: normal # normal | full
storage.checksum: off # 데이터 무결성 검증
storage.max_chunks_up: 128 # 메모리에 올릴 최대 청크 수
storage.backlog.mem_limit: 5M # 백로그 메모리 한도
storage.metrics: on # 스토리지 메트릭 활성화
9.3 Input 레벨 버퍼 설정
pipeline:
inputs:
# 메모리 버퍼 사용 (기본)
- name: tail
tag: app.mem
path: /var/log/app/*.log
mem_buf_limit: 10MB # 메모리 버퍼 한도
# 파일시스템 버퍼 사용
- name: tail
tag: app.fs
path: /var/log/app/*.log
storage.type: filesystem # filesystem | memory
storage.pause_on_chunks_overlimit: off # 한도 초과 시 디스크에 계속 기록
9.4 Output 레벨 버퍼 설정
pipeline:
outputs:
- name: es
match: '*'
host: elasticsearch
port: 9200
storage.total_limit_size: 1G # Output별 파일시스템 버퍼 총량 제한
retry_limit: 10 # 재시도 횟수
# retry_limit: false # 무한 재시도
9.5 Backpressure 메커니즘
Backpressure는 Output이 데이터를 충분히 빠르게 전송하지 못할 때 발생한다. Fluent Bit은 다음과 같은 단계로 Backpressure를 처리한다.
[Input: 데이터 수집]
|
v
[메모리 버퍼에 저장]
|
메모리 한도 도달?
/ \
No Yes
| |
v v
[계속 수집] storage.type=filesystem?
/ \
No Yes
| |
v v
[Input 일시 정지] [디스크에 기록]
(데이터 손실 위험) |
디스크 한도 도달?
/ \
No Yes
| |
v v
[계속 기록] [Input 일시 정지]
권장 Backpressure 설정 (프로덕션)
service:
storage.path: /var/log/fluent-bit/buffer/
storage.sync: normal
storage.max_chunks_up: 128
storage.backlog.mem_limit: 10M
pipeline:
inputs:
- name: tail
tag: kube.*
path: /var/log/containers/*.log
storage.type: filesystem
storage.pause_on_chunks_overlimit: off
outputs:
- name: es
match: kube.*
host: elasticsearch
storage.total_limit_size: 5G
retry_limit: false
net.keepalive: on
net.keepalive_idle_timeout: 30
9.6 Mem_Buf_Limit vs storage.max_chunks_up
| 설정 | 적용 범위 | 버퍼 모드 | 동작 |
|---|---|---|---|
Mem_Buf_Limit | Input별 | memory만 | 한도 초과 시 Input 일시 정지 |
storage.max_chunks_up | 전역 (SERVICE) | filesystem | 메모리 내 청크 수 제한 |
storage.total_limit_size | Output별 | filesystem | 디스크 버퍼 총량 제한 |
주의: storage.type: filesystem을 사용하면 Mem_Buf_Limit은 효과가 없다. 대신 storage.max_chunks_up이 메모리 내 청크 수를 제어한다.
10. Kubernetes 연동 완벽 가이드
10.1 DaemonSet 배포 아키텍처
+---------------------------------------------------------------------+
| Kubernetes Cluster |
| |
| +-------------------+ +-------------------+ +-------------------+|
| | Node 1 | | Node 2 | | Node 3 ||
| | | | | | ||
| | +------+ +------+ | | +------+ +------+ | | +------+ +------+ ||
| | |Pod A | |Pod B | | | |Pod C | |Pod D | | | |Pod E | |Pod F | ||
| | +--+---+ +--+---+ | | +--+---+ +--+---+ | | +--+---+ +--+---+ ||
| | | | | | | | | | | | ||
| | v v | | v v | | v v ||
| | /var/log/containers| | /var/log/containers| | /var/log/containers||
| | | | | | | | | ||
| | +----+-----+ | | +----+-----+ | | +----+-----+ ||
| | |Fluent Bit| | | |Fluent Bit| | | |Fluent Bit| ||
| | |(DaemonSet)| | | |(DaemonSet)| | | |(DaemonSet)| ||
| | +----+-----+ | | +----+-----+ | | +----+-----+ ||
| +---------|----------+ +---------|----------+ +---------|----------+|
| | | | |
| +----------+------------+----------+------------+ |
| | | |
| +-------v--------+ +--------v--------+ |
| | Elasticsearch | | Grafana Loki | |
| +----------------+ +-----------------+ |
+---------------------------------------------------------------------+
10.2 Helm Chart 설치
# 저장소 추가
helm repo add fluent https://fluent.github.io/helm-charts
helm repo update
# 기본 설치
helm install fluent-bit fluent/fluent-bit \
--namespace logging \
--create-namespace
# 설치 확인
kubectl get pods -n logging -l app.kubernetes.io/name=fluent-bit
kubectl get ds -n logging
10.3 values.yaml 커스터마이징
# custom-values.yaml
kind: DaemonSet
image:
repository: cr.fluentbit.io/fluent/fluent-bit
tag: '3.2.2'
pullPolicy: IfNotPresent
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
tolerations:
- operator: Exists # 모든 노드에 배포 (master 포함)
serviceAccount:
create: true
annotations:
# IRSA (EKS)
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/fluent-bit
# 볼륨 마운트
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: etcmachineid
mountPath: /etc/machine-id
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: etcmachineid
hostPath:
path: /etc/machine-id
# 환경변수
env:
- name: ELASTICSEARCH_HOST
value: 'elasticsearch-master.logging.svc.cluster.local'
- name: ELASTICSEARCH_PORT
value: '9200'
# Fluent Bit 설정
config:
service: |
[SERVICE]
Flush 5
Log_Level info
Daemon off
Parsers_File /fluent-bit/etc/parsers.conf
HTTP_Server On
HTTP_Listen 0.0.0.0
HTTP_Port 2020
storage.path /var/log/fluent-bit/buffer/
storage.sync normal
storage.max_chunks_up 128
Hot_Reload On
inputs: |
[INPUT]
Name tail
Tag kube.*
Path /var/log/containers/*.log
multiline.parser docker, cri
DB /var/log/flb_kube.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
storage.type filesystem
filters: |
[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
Keep_Log Off
K8S-Logging.Parser On
K8S-Logging.Exclude On
Labels On
Annotations Off
outputs: |
[OUTPUT]
Name es
Match kube.*
Host ${ELASTICSEARCH_HOST}
Port ${ELASTICSEARCH_PORT}
Logstash_Format On
Logstash_Prefix kube
Retry_Limit False
Suppress_Type_Name On
# Prometheus 메트릭 수집을 위한 ServiceMonitor
serviceMonitor:
enabled: true
interval: 30s
scrapeTimeout: 10s
# Liveness/Readiness Probe
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /api/v1/health
port: http
10.4 컨테이너 로그 경로와 CRI 파싱
Kubernetes에서 컨테이너 로그는 다음 경로에 저장된다.
/var/log/containers/<pod-name>_<namespace>_<container-name>-<container-id>.log
-> symlink -> /var/log/pods/<namespace>_<pod-name>_<pod-uid>/<container-name>/0.log
CRI 로그 포맷 (containerd / CRI-O)
2026-03-01T12:00:00.123456789Z stdout F This is a log message
2026-03-01T12:00:00.123456789Z stderr P This is a partial log line
| 필드 | 설명 |
|---|---|
2026-03-01T12:00:00.123456789Z | RFC 3339 나노초 타임스탬프 |
stdout / stderr | 스트림 유형 |
F / P | Full(완전) / Partial(부분) 로그 플래그 |
| 나머지 | 로그 메시지 본문 |
Fluent Bit은 multiline.parser: docker, cri를 지정하면 Docker 형식과 CRI 형식을 자동으로 감지하여 파싱한다.
10.5 Namespace별 로그 라우팅
# Namespace에 따라 다른 Output으로 라우팅
pipeline:
filters:
- name: kubernetes
match: kube.*
merge_log: on
labels: on
# 프로덕션 네임스페이스 태그 변경
- name: rewrite_tag
match: kube.*
rule: $kubernetes['namespace_name'] ^(production)$ prod.$TAG false
rule: $kubernetes['namespace_name'] ^(staging)$ stg.$TAG false
rule: $kubernetes['namespace_name'] ^(monitoring)$ mon.$TAG false
outputs:
# 프로덕션 로그 -> Elasticsearch
- name: es
match: prod.*
host: es-production.logging.svc
port: 9200
logstash_format: on
logstash_prefix: prod-logs
# 스테이징 로그 -> Loki
- name: loki
match: stg.*
host: loki.logging.svc
port: 3100
labels:
env=staging
# 모니터링 로그 -> S3 아카이빙
- name: s3
match: mon.*
bucket: monitoring-logs-archive
region: ap-northeast-2
total_file_size: 100M
upload_timeout: 10m
compression: gzip
# 기타 로그 -> 기본 Elasticsearch
- name: es
match: kube.*
host: es-default.logging.svc
port: 9200
logstash_format: on
logstash_prefix: default-logs
10.6 멀티테넌트 로그 분리
pipeline:
filters:
- name: kubernetes
match: kube.*
merge_log: on
labels: on
# 팀 Label 기반 태그 재작성
- name: rewrite_tag
match: kube.*
rule: $kubernetes['labels']['team'] ^(backend)$ team.backend.$TAG false
rule: $kubernetes['labels']['team'] ^(frontend)$ team.frontend.$TAG false
rule: $kubernetes['labels']['team'] ^(data)$ team.data.$TAG false
outputs:
# 백엔드 팀 -> 전용 Elasticsearch 인덱스
- name: es
match: team.backend.*
host: elasticsearch.logging.svc
logstash_format: on
logstash_prefix: team-backend
# 프론트엔드 팀 -> 전용 Loki tenant
- name: loki
match: team.frontend.*
host: loki.logging.svc
tenant_id: frontend-team
labels:
team=frontend
# 데이터 팀 -> S3 + Elasticsearch 듀얼
- name: es
match: team.data.*
host: elasticsearch.logging.svc
logstash_format: on
logstash_prefix: team-data
- name: s3
match: team.data.*
bucket: data-team-logs
region: ap-northeast-2
compression: gzip
10.7 ServiceAccount 및 RBAC 설정
# fluent-bit-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: fluent-bit
namespace: logging
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: fluent-bit
rules:
- apiGroups: ['']
resources:
- namespaces
- pods
- pods/logs
- nodes
- nodes/proxy
verbs: ['get', 'list', 'watch']
- apiGroups: ['']
resources:
- events
verbs: ['get', 'list', 'watch']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: fluent-bit
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: fluent-bit
subjects:
- kind: ServiceAccount
name: fluent-bit
namespace: logging
11. 실전 파이프라인 예제
11.1 예제 1: K8s 로그를 Elasticsearch + Kibana로
가장 일반적인 EFK(Elasticsearch + Fluent Bit + Kibana) 스택 구성이다.
# fluent-bit-efk.yaml
service:
flush: 5
log_level: info
parsers_file: /fluent-bit/etc/parsers.conf
http_server: on
http_listen: 0.0.0.0
http_port: 2020
storage.path: /var/log/fluent-bit/buffer/
storage.sync: normal
storage.max_chunks_up: 128
pipeline:
inputs:
- name: tail
tag: kube.*
path: /var/log/containers/*.log
multiline.parser: docker, cri
db: /var/log/flb_kube.db
mem_buf_limit: 5MB
skip_long_lines: on
refresh_interval: 10
storage.type: filesystem
filters:
- 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
merge_log: on
keep_log: off
k8s-logging.parser: on
k8s-logging.exclude: on
labels: on
# kube-system, logging 네임스페이스 로그 제외
- name: grep
match: kube.*
exclude: $kubernetes['namespace_name'] ^(kube-system|logging)$
# 환경 정보 추가
- name: modify
match: kube.*
add: cluster_name my-eks-cluster
add: environment production
outputs:
- name: es
match: kube.*
host: elasticsearch-master.logging.svc.cluster.local
port: 9200
http_user: elastic
http_passwd: ${ES_PASSWORD}
logstash_format: on
logstash_prefix: kube-logs
logstash_dateformat: "%Y.%m.%d"
time_key: "@timestamp"
include_tag_key: true
tag_key: fluentbit_tag
suppress_type_name: on
generate_id: on
retry_limit: false
workers: 2
tls: on
tls.verify: on
tls.ca_file: /certs/es-ca.pem
11.2 예제 2: K8s 로그를 Grafana Loki + Grafana로
# fluent-bit-loki.yaml
service:
flush: 5
log_level: info
http_server: on
http_listen: 0.0.0.0
http_port: 2020
pipeline:
inputs:
- name: tail
tag: kube.*
path: /var/log/containers/*.log
multiline.parser: docker, cri
db: /var/log/flb_kube.db
mem_buf_limit: 5MB
skip_long_lines: on
filters:
- name: kubernetes
match: kube.*
merge_log: on
keep_log: off
labels: on
annotations: off
outputs:
- name: loki
match: kube.*
host: loki-gateway.logging.svc.cluster.local
port: 3100
uri: /loki/api/v1/push
labels: job=fluent-bit,cluster=my-cluster
label_keys: $kubernetes['namespace_name'],$kubernetes['pod_name'],$kubernetes['container_name']
auto_kubernetes_labels: on
line_format: json
workers: 2
retry_limit: false
11.3 예제 3: S3 아카이빙 + Elasticsearch 듀얼 출력
하나의 입력을 두 개의 Output으로 동시에 전송하는 패턴이다.
# fluent-bit-dual.yaml
service:
flush: 5
log_level: info
storage.path: /var/log/fluent-bit/buffer/
storage.sync: normal
storage.max_chunks_up: 128
pipeline:
inputs:
- name: tail
tag: kube.*
path: /var/log/containers/*.log
multiline.parser: docker, cri
db: /var/log/flb_kube.db
storage.type: filesystem
filters:
- name: kubernetes
match: kube.*
merge_log: on
keep_log: off
labels: on
outputs:
# 실시간 검색/분석용 Elasticsearch
- name: es
match: kube.*
host: elasticsearch.logging.svc
port: 9200
logstash_format: on
logstash_prefix: kube-logs
suppress_type_name: on
retry_limit: false
workers: 2
# 장기 보관용 S3 아카이빙
- name: s3
match: kube.*
region: ap-northeast-2
bucket: log-archive-bucket
s3_key_format: /kubernetes/$TAG/%Y/%m/%d/%H/$UUID.gz
s3_key_format_tag_delimiters: .
total_file_size: 100M
upload_timeout: 10m
compression: gzip
content_type: application/gzip
store_dir: /tmp/fluent-bit-s3
store_dir_limit_size: 1G
use_put_object: on
retry_limit: 5
workers: 1
11.4 예제 4: 네임스페이스별 필터링 및 다중 목적지 라우팅
# fluent-bit-routing.yaml
service:
flush: 5
log_level: info
storage.path: /var/log/fluent-bit/buffer/
storage.sync: normal
pipeline:
inputs:
- name: tail
tag: kube.*
path: /var/log/containers/*.log
multiline.parser: docker, cri
db: /var/log/flb_kube.db
storage.type: filesystem
filters:
- name: kubernetes
match: kube.*
merge_log: on
labels: on
# Namespace별 태그 재작성
- name: rewrite_tag
match: kube.*
rule: $kubernetes['namespace_name'] ^(production)$ route.prod.$TAG false
rule: $kubernetes['namespace_name'] ^(staging)$ route.stg.$TAG false
rule: $kubernetes['namespace_name'] ^(kube-system)$ route.sys.$TAG false
# 프로덕션에서 ERROR만 추출
- name: rewrite_tag
match: route.prod.*
rule: $log ^.*ERROR.*$ alert.prod.$TAG true
outputs:
# 프로덕션 전체 로그 -> Elasticsearch
- name: es
match: route.prod.*
host: es-prod.logging.svc
port: 9200
logstash_format: on
logstash_prefix: prod-all
suppress_type_name: on
workers: 2
# 프로덕션 ERROR 알림 -> 별도 인덱스
- name: es
match: alert.prod.*
host: es-prod.logging.svc
port: 9200
logstash_format: on
logstash_prefix: prod-alerts
suppress_type_name: on
# 스테이징 로그 -> Loki (비용 효율)
- name: loki
match: route.stg.*
host: loki.logging.svc
port: 3100
labels:
env=staging
auto_kubernetes_labels: on
line_format: json
# 시스템 로그 -> S3 아카이빙 (장기 보관)
- name: s3
match: route.sys.*
bucket: system-logs-archive
region: ap-northeast-2
total_file_size: 50M
upload_timeout: 15m
compression: gzip
s3_key_format: /kube-system/%Y/%m/%d/$UUID.gz
# 미분류 로그 -> 기본 Elasticsearch
- name: es
match: kube.*
host: es-default.logging.svc
port: 9200
logstash_format: on
logstash_prefix: default-logs
suppress_type_name: on
12. 성능 튜닝
12.1 Workers 설정
Output 플러그인에 Workers 파라미터를 설정하면 병렬 전송이 가능하다. 각 Worker는 독립적인 스레드로 동작한다.
pipeline:
outputs:
- name: es
match: '*'
host: elasticsearch
port: 9200
workers: 4 # 4개 병렬 Worker
net.keepalive: on
net.keepalive_idle_timeout: 30
Workers 설정 가이드라인
| 상황 | 권장 Workers | 비고 |
|---|---|---|
| 낮은 처리량 | 0-1 | 기본값으로 충분 |
| 중간 처리량 | 2-4 | 대부분의 프로덕션 환경 |
| 높은 처리량 | 4-8 | CPU 코어 수 고려 |
| 매우 높은 처리량 | 8 이상 | 네트워크/목적지 병목 확인 필요 |
12.2 Flush Interval 최적화
Flush 값은 초 단위로, 버퍼에서 Output으로 데이터를 전송하는 주기를 결정한다.
service:
flush: 1 # 1초마다 플러시 (실시간성 중시)
# flush: 5 # 5초마다 플러시 (처리량 중시)
| Flush 값 | 특성 |
|---|---|
| 1초 | 낮은 지연시간, 높은 CPU 사용 |
| 5초 | 균형잡힌 설정 (기본 권장) |
| 10초 이상 | 높은 처리량, 큰 배치 크기 |
12.3 Buffer 크기 조정
pipeline:
inputs:
- name: tail
path: /var/log/containers/*.log
# 높은 처리량 환경
buffer_chunk_size: 512KB # 청크 단위 크기 (기본 32KB)
buffer_max_size: 5MB # 최대 버퍼 크기 (기본 32KB)
mem_buf_limit: 50MB # 메모리 버퍼 한도
outputs:
- name: es
match: '*'
buffer_size: 512KB # HTTP 버퍼 크기
12.4 파이프라인 병렬화
높은 처리량이 필요한 환경에서는 Input과 Output을 분리하여 병렬 파이프라인을 구성할 수 있다.
pipeline:
inputs:
# 애플리케이션 로그 파이프라인
- name: tail
tag: app.*
path: /var/log/containers/app-*.log
multiline.parser: docker, cri
threaded: on # 별도 스레드에서 실행
# 시스템 로그 파이프라인
- name: tail
tag: sys.*
path: /var/log/containers/kube-*.log
multiline.parser: docker, cri
threaded: on
outputs:
- name: es
match: app.*
host: elasticsearch
workers: 4
- name: es
match: sys.*
host: elasticsearch
workers: 2
12.5 Hot Reload
v2.1부터 지원되는 Hot Reload 기능으로, 서비스 중단 없이 설정을 다시 로드할 수 있다.
# Hot Reload 활성화
service:
hot_reload: on
리로드를 트리거하는 방법은 세 가지이다.
# 방법 1: SIGHUP 시그널
kill -SIGHUP $(pidof fluent-bit)
# 방법 2: HTTP API (v4.0+)
curl -X POST http://localhost:2020/api/v2/reload
# 방법 3: 커맨드라인 옵션
fluent-bit -c fluent-bit.yaml -Y # --enable-hot-reload
Hot Reload 시 주의사항
- 버퍼에 있는 데이터는 보존된다
- 파일시스템 버퍼의 경우 디스크의 데이터도 유지된다
- 새 설정에 문법 오류가 있으면 리로드가 실패하고 기존 설정이 유지된다
- SIGHUP은 Windows에서 지원되지 않는다
12.6 메모리 사용량 모니터링
# Fluent Bit 프로세스 메모리 확인
ps aux | grep fluent-bit
# HTTP API로 내부 메트릭 확인
curl -s http://localhost:2020/api/v1/storage | jq .
# Prometheus 메트릭으로 확인
curl -s http://localhost:2020/api/v2/metrics/prometheus | grep fluentbit_input
12.7 성능 벤치마크 참고
다음은 일반적인 환경에서의 Fluent Bit 성능 참고치이다 (하드웨어, 네트워크, 설정에 따라 차이가 있다).
| 시나리오 | 처리량 | CPU 사용률 | 메모리 |
|---|---|---|---|
| 단순 전달 (tail 입력, stdout 출력) | 약 100K events/s | 5-10% (1 core) | 5-10MB |
| K8s Filter + ES 출력 | 약 40-60K events/s | 15-25% (1 core) | 30-50MB |
| K8s Filter + Lua 변환 + ES 출력 | 약 20-40K events/s | 25-40% (1 core) | 40-80MB |
| 복합 파이프라인 (Filter 다수 + 듀얼 출력) | 약 15-30K events/s | 30-50% (1 core) | 50-100MB |
v4.1의 SIMD 최적화: JSON 인코딩을 SIMD(Single Instruction, Multiple Data) 명령어로 처리하여 JSON 변환 성능이 2.5배 향상되었다.
13. 모니터링 및 Observability
13.1 내장 HTTP 모니터링 엔드포인트
Fluent Bit은 내장 HTTP 서버를 통해 자체 상태를 모니터링할 수 있다.
service:
http_server: on
http_listen: 0.0.0.0
http_port: 2020
health_check: on
hc_errors_count: 5 # 이 수 이상 에러 발생 시 unhealthy
hc_retry_failure_count: 5 # 이 수 이상 재시도 실패 시 unhealthy
hc_period: 60 # 헬스체크 주기 (초)
사용 가능한 엔드포인트
| 엔드포인트 | 설명 |
|---|---|
/ | Fluent Bit 빌드 정보 |
/api/v1/health | 헬스 체크 (200=OK, 500=Unhealthy) |
/api/v1/metrics | JSON 형식 메트릭 |
/api/v1/metrics/prometheus | Prometheus 형식 메트릭 |
/api/v2/metrics | v2 메트릭 엔드포인트 |
/api/v2/metrics/prometheus | v2 Prometheus 메트릭 |
/api/v1/storage | 스토리지/버퍼 상태 |
/api/v2/reload | Hot Reload 트리거 (POST) |
/api/v1/uptime | 가동 시간 |
# 헬스 체크
curl -s http://localhost:2020/api/v1/health
# 응답: ok (HTTP 200) 또는 error (HTTP 500)
# 스토리지 상태 확인
curl -s http://localhost:2020/api/v1/storage | jq .
# {
# "storage_layer": {
# "chunks": {
# "total_chunks": 15,
# "mem_chunks": 10,
# "fs_chunks": 5,
# "fs_chunks_up": 3,
# "fs_chunks_down": 2
# }
# }
# }
# Prometheus 메트릭 확인
curl -s http://localhost:2020/api/v2/metrics/prometheus
13.2 Prometheus 메트릭 수집 구성
Fluent Bit의 내부 메트릭을 Prometheus로 수집하고 Grafana에서 시각화하는 구성이다.
# Fluent Bit 자체 메트릭을 Prometheus로 노출
pipeline:
inputs:
- name: fluentbit_metrics
tag: fb.metrics
scrape_interval: 30
outputs:
- name: prometheus_exporter
match: fb.metrics
host: 0.0.0.0
port: 2021
Kubernetes ServiceMonitor 설정
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: fluent-bit
namespace: logging
labels:
release: prometheus
spec:
selector:
matchLabels:
app.kubernetes.io/name: fluent-bit
endpoints:
- port: http
path: /api/v2/metrics/prometheus
interval: 30s
scrapeTimeout: 10s
namespaceSelector:
matchNames:
- logging
주요 Prometheus 메트릭
| 메트릭 | 타입 | 설명 |
|---|---|---|
fluentbit_input_records_total | Counter | Input별 수집 레코드 수 |
fluentbit_input_bytes_total | Counter | Input별 수집 바이트 수 |
fluentbit_output_proc_records_total | Counter | Output별 처리 레코드 수 |
fluentbit_output_proc_bytes_total | Counter | Output별 처리 바이트 수 |
fluentbit_output_errors_total | Counter | Output별 에러 수 |
fluentbit_output_retries_total | Counter | Output별 재시도 수 |
fluentbit_output_retries_failed_total | Counter | Output별 재시도 실패 수 |
fluentbit_filter_records_total | Counter | Filter별 처리 레코드 수 |
fluentbit_uptime | Gauge | 가동 시간 (초) |
fluentbit_storage_chunks | Gauge | 스토리지 청크 수 |
13.3 Grafana 대시보드
Grafana에서 Fluent Bit 모니터링 대시보드를 구성할 때 포함해야 할 핵심 패널은 다음과 같다.
대시보드 패널 구성
| 패널 | PromQL 예시 | 용도 |
|---|---|---|
| Input 처리량 | rate(fluentbit_input_records_total[5m]) | 초당 수집 레코드 수 |
| Output 처리량 | rate(fluentbit_output_proc_records_total[5m]) | 초당 전송 레코드 수 |
| Output 에러율 | rate(fluentbit_output_errors_total[5m]) | 초당 에러 발생 수 |
| 재시도 비율 | rate(fluentbit_output_retries_total[5m]) | 재시도 추세 |
| 버퍼 사용량 | fluentbit_storage_chunks | 현재 버퍼 청크 수 |
| 가동 시간 | fluentbit_uptime | 프로세스 안정성 |
| Input/Output 차이 | rate(input[5m]) - rate(output[5m]) | Backpressure 감지 |
Grafana Labs 커뮤니티 대시보드(ID: 7752)를 Import하면 기본적인 Fluent Bit 모니터링 대시보드를 빠르게 구성할 수 있다.
14. 트러블슈팅 가이드
14.1 로그가 수집되지 않는 경우
체크리스트
# 1. Fluent Bit 프로세스 상태 확인
kubectl get pods -n logging -l app.kubernetes.io/name=fluent-bit
kubectl logs -n logging <fluent-bit-pod> --tail=50
# 2. 설정 파일 문법 검증
fluent-bit -c fluent-bit.yaml --dry-run
# 3. 로그 파일 경로 확인
kubectl exec -n logging <fluent-bit-pod> -- ls -la /var/log/containers/
# 4. DB 파일(offset) 확인
kubectl exec -n logging <fluent-bit-pod> -- ls -la /var/log/flb_kube.db
# 5. 권한 확인
kubectl exec -n logging <fluent-bit-pod> -- cat /var/log/containers/<target-log>
일반적인 원인과 해결 방법
| 원인 | 증상 | 해결 방법 |
|---|---|---|
| 파일 경로 오류 | Input에서 레코드 수 0 | Path 확인, 와일드카드 패턴 검증 |
| 권한 부족 | Permission denied 에러 | SecurityContext, hostPath 권한 확인 |
| DB 파일 손상 | offset이 파일 끝을 가리킴 | DB 파일 삭제 후 재시작 |
| Parser 불일치 | 파싱 실패, 빈 레코드 | stdout Output으로 원본 확인 |
| Tag 매칭 실패 | Filter/Output에 도달 안 함 | Match 패턴과 Tag 일치 확인 |
14.2 메모리 누수 / OOM
# 메모리 제한 설정
pipeline:
inputs:
- name: tail
path: /var/log/containers/*.log
mem_buf_limit: 5MB # Input 메모리 한도
skip_long_lines: on # 긴 라인 스킵
buffer_chunk_size: 32KB # 청크 크기 제한
buffer_max_size: 32KB # 최대 버퍼
service:
storage.path: /var/log/fluent-bit/buffer/
storage.max_chunks_up: 64 # 메모리 청크 수 제한 (기본 128)
OOM 방지 체크리스트
Mem_Buf_Limit또는storage.max_chunks_up이 설정되어 있는지 확인Skip_Long_Lines: On활성화- 불필요한 Filter 제거 (특히 Lua에서 큰 테이블 생성 시)
- Kubernetes Filter의
Buffer_Size확인 (0=무제한) - Kubernetes Resource Limits 적절히 설정
14.3 Backpressure로 인한 로그 손실
# Backpressure 발생 확인
curl -s http://localhost:2020/api/v1/storage | jq .
# 메트릭으로 확인
curl -s http://localhost:2020/api/v2/metrics/prometheus | grep -E "retries|errors|dropped"
Backpressure 발생 시 대응 순서
- Output의
Workers수를 늘려 병렬 전송 강화 Flush주기를 줄여 더 자주 전송 (예: 5 -> 1)storage.type: filesystem으로 전환하여 디스크 버퍼 활용storage.total_limit_size를 충분히 설정- 목적지(Elasticsearch 등)의 처리 능력 확인 및 증설
# Backpressure 대응 설정 예시
service:
flush: 1
storage.path: /var/log/fluent-bit/buffer/
storage.sync: normal
storage.max_chunks_up: 256
pipeline:
inputs:
- name: tail
tag: kube.*
path: /var/log/containers/*.log
storage.type: filesystem
storage.pause_on_chunks_overlimit: off
outputs:
- name: es
match: kube.*
host: elasticsearch
port: 9200
workers: 4
storage.total_limit_size: 10G
retry_limit: false
net.keepalive: on
net.keepalive_idle_timeout: 15
14.4 TLS/인증 오류
# TLS 연결 테스트
kubectl exec -n logging <fluent-bit-pod> -- \
curl -v --cacert /certs/ca.pem https://elasticsearch:9200
# 인증서 만료 확인
kubectl exec -n logging <fluent-bit-pod> -- \
openssl x509 -in /certs/ca.pem -noout -enddate
일반적인 TLS 오류 및 해결
| 에러 | 원인 | 해결 |
|---|---|---|
SSL_ERROR_SYSCALL | 인증서 경로 오류 | tls.ca_file 경로 확인 |
certificate verify failed | CA 인증서 불일치 | 올바른 CA 인증서 사용 |
certificate has expired | 인증서 만료 | 인증서 갱신 |
connection refused | 포트/호스트 오류 | Host, Port, TLS 포트 확인 |
401 Unauthorized | 인증 실패 | http_user, http_passwd 확인 |
14.5 디버깅 방법
단계 1: Log Level을 debug로 설정
service:
log_level: debug # error, warn, info, debug, trace
단계 2: stdout Output 추가
pipeline:
outputs:
# 디버깅용: 모든 레코드를 표준 출력으로
- name: stdout
match: '*'
format: json_lines
# 실제 Output
- name: es
match: '*'
host: elasticsearch
단계 3: 파이프라인 단계별 확인
# Input만 테스트
fluent-bit -i tail -p path=/var/log/test.log -o stdout
# Parser 테스트
fluent-bit -i tail -p path=/var/log/test.log -p parser=json -o stdout
# 전체 설정 테스트 (dry-run)
fluent-bit -c fluent-bit.yaml --dry-run
단계 4: Kubernetes에서 실시간 로그 확인
# Fluent Bit 로그 스트리밍
kubectl logs -n logging -l app.kubernetes.io/name=fluent-bit -f --tail=100
# 특정 Pod의 로그
kubectl logs -n logging fluent-bit-xxxxx -f
# 이전 컨테이너 로그 (crash 시)
kubectl logs -n logging fluent-bit-xxxxx --previous
15. 운영 Best Practices
15.1 프로덕션 체크리스트
| 항목 | 권장 설정 | 이유 |
|---|---|---|
storage.type | filesystem | 데이터 손실 방지 |
storage.path | 별도 볼륨 마운트 | 디스크 I/O 분리 |
storage.total_limit_size | 디스크 여유 공간의 50-70% | 디스크 풀 방지 |
Retry_Limit | false (무한) 또는 충분한 값 | 일시적 장애 복구 |
Workers | 2-4 | 병렬 전송 성능 |
Hot_Reload | on | 무중단 설정 변경 |
HTTP_Server | on | 모니터링 활성화 |
health_check | on | Kubernetes Probe 연동 |
Skip_Long_Lines | on | 비정상 로그에 의한 장애 방지 |
| Resource Limits | 적절한 CPU/Memory | OOM 방지 |
15.2 보안 권장 사항
# Kubernetes Pod Security
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
capabilities:
drop: ['ALL']
# 필요한 볼륨만 마운트
volumes:
- name: varlog
hostPath:
path: /var/log
type: ''
- name: buffer
emptyDir:
sizeLimit: 2Gi
# TLS 강제 (Output)
pipeline:
outputs:
- name: es
tls: on
tls.verify: on
tls.ca_file: /certs/ca.pem
15.3 로그 로테이션 대응
Fluent Bit의 tail Input은 로그 로테이션을 자동으로 감지한다. 다만 다음 설정을 확인해야 한다.
pipeline:
inputs:
- name: tail
path: /var/log/app/*.log
db: /var/log/flb_app.db # 필수: offset 추적
rotate_wait: 5 # 로테이션 후 대기 시간 (초)
refresh_interval: 10 # 파일 목록 갱신 주기
16. 참고 자료
공식 문서 및 저장소
- Fluent Bit 공식 문서 - 전체 설정 레퍼런스 및 가이드
- Fluent Bit GitHub - 소스 코드 및 이슈 트래커
- Fluent Bit Helm Charts - Kubernetes 배포용 Helm Chart
- Fluent Bit Performance Tools - 벤치마크 도구
CNCF 관련 자료
- CNCF Fluent Bit v3 발표
- CNCF Fluent Bit v3.2 발표
- CNCF Fluentd to Fluent Bit 마이그레이션 가이드
- CNCF Parsing 101 with Fluent Bit