이전 글들에서 Grafana 와 Loki 까지 구성을 완료했다.
이번 글에서는 Fluent Bit 를 설치하고 로그를 출력할 샘플 app 과 연동해서 Grafana 대시보드에 로그가 출력되는 것까지 완료해보겠다.
1. Fluent Bit 설치
Fluent Bit 공식 문서의 Docker 설치 방법을 참고하여 Docker 컨테이너로 Fluent Bit 서비스를 실행시켜 보겠다.
- installation > download and install fluent bit > docker
Download and install Fluent Bit | Fluent Bit: Official Manual
docs.fluentbit.io
- docker-compose.yaml
공식 문서에서 docker run 명령어로 Fluent Bit 를 실행시키고 있는데, 이를 참고하여 docker-compose.yaml 을 작성했다.
services:
...
fluentbit:
image: fluent/fluent-bit
container_name: fluentbit
restart: unless-stopped
volumes:
- ./fluent-bit/fluent-bit.yaml:/fluent-bit/etc/fluent-bit.yaml
- fluent-bit.yaml
Fluent Bit 서비스의 설정을 위해서는 설정 파일을 작성해야 한다. 설정 파일은 conf 파일과 yaml 파일 두가지 형식이 있는데, conf 형식은 2026년을 마지막으로 deprecated 될 예정이라고 한다. 그래서 이 글에서는 yaml 형식을 사용하여 예제를 작성했다.
예제는 Fluent Bit 의 테스트 예제 설정으로 먼저 구성헀다. 예제 설정은 랜덤 값을 입력값으로 생성해서 이를 표준 출력으로 출력하도록 설정되어 있다.
해당 파일은 docker-compose.yaml 에서 확인할 수 있듯이 volume 연결을 통해 Fluent Bit 가 접근할 수 있도록 해주었다.
# https://github.com/fluent/fluent-bit/blob/master/packaging/testing/smoke/container/fluent-bit.yaml
service:
http_server: "on"
Health_Check: "on"
log_level: debug
pipeline:
inputs:
- name: random
tag: test
samples: 10
filters:
- name: lua
match: test
call: append_tag
code: |
function append_tag(tag, timestamp, record)
new_record = record
new_record["tag"] = tag
return 1, timestamp, new_record
end
- name: expect
match: test
key_exists: tag
key_val_eq: tag test
action: exit
outputs:
- name: stdout
match: test
- Fluent Bit 실행
이제 설정을 기반으로 Fluent Bit 를 실행하고 예제가 잘 동작하는지, 로그가 어떻게 출력되는지 확인해보겠다.
Docker Compose 로 Fluent Bit 를 실행하고 컨테이너가 출력하는 로그를 확인해보니 아래와 같이 랜덤한 수치를 가진 예제 로그가 출력되는 것을 확인할 수 있었다.
[0] cpu.local: [[1773219286.818495144, {}], {"cpu_p"=>0.772727, "user_p"=>0.136364, "system_p"=>0.636364, "cpu0.p_cpu"=>0.000000, "cpu0.p_user"=>0.000000, "cpu0.p_system"=>0.000000, "cpu1.p_cpu"=>0.000000, "cpu1.p_user"=>0.000000, "cpu1.p_system"=>0.000000, "cpu2.p_cpu"=>1.000000, "cpu2.p_user"=>0.000000, "cpu2.p_system"=>1.000000, "cpu3.p_cpu"=>0.000000, "cpu3.p_user"=>0.000000, "cpu3.p_system"=>0.000000, "cpu4.p_cpu"=>0.000000, "cpu4.p_user"=>0.000000, "cpu4.p_system"=>0.000000, "cpu5.p_cpu"=>2.000000, "cpu5.p_user"=>0.000000, "cpu5.p_system"=>2.000000, "cpu6.p_cpu"=>1.000000, "cpu6.p_user"=>1.000000, "cpu6.p_system"=>0.000000, "cpu7.p_cpu"=>0.000000, "cpu7.p_user"=>0.000000, "cpu7.p_system"=>0.000000, "cpu8.p_cpu"=>1.000000, "cpu8.p_user"=>0.000000, "cpu8.p_system"=>1.000000, "cpu9.p_cpu"=>1.000000, "cpu9.p_user"=>0.000000, "cpu9.p_system"=>1.000000, "cpu10.p_cpu"=>0.000000, "cpu10.p_user"=>0.000000, "cpu10.p_system"=>0.000000, "cpu11.p_cpu"=>0.000000, "cpu11.p_user"=>0.000000, "cpu11.p_system"=>0.000000, "cpu12.p_cpu"=>3.000000, "cpu12.p_user"=>0.000000, "cpu12.p_system"=>3.000000, "cpu13.p_cpu"=>0.000000, "cpu13.p_user"=>0.000000, "cpu13.p_system"=>0.000000, "cpu14.p_cpu"=>2.000000, "cpu14.p_user"=>0.000000, "cpu14.p_system"=>2.000000, "cpu15.p_cpu"=>0.000000, "cpu15.p_user"=>0.000000, "cpu15.p_system"=>0.000000, "cpu16.p_cpu"=>2.000000, "cpu16.p_user"=>0.000000, "cpu16.p_system"=>2.000000, "cpu17.p_cpu"=>0.000000, "cpu17.p_user"=>0.000000, "cpu17.p_system"=>0.000000, "cpu18.p_cpu"=>2.000000, "cpu18.p_user"=>1.000000, "cpu18.p_system"=>1.000000, "cpu19.p_cpu"=>0.000000, "cpu19.p_user"=>0.000000, "cpu19.p_system"=>0.000000, "cpu20.p_cpu"=>1.000000, "cpu20.p_user"=>1.000000, "cpu20.p_system"=>0.000000, "cpu21.p_cpu"=>1.000000, "cpu21.p_user"=>0.000000, "cpu21.p_system"=>1.000000}]
...
2. 로그 모니터링 시스템 연동
이제 예제가 아닌 실제 로그를 출력하는 my-app 이라는 application 과 Loki 등을 Fluent Bit 연동하여 로그를 수집하고 저장소에 전송하도록 해보겠다. 그리고 Loki 에 저장된 로그를 Grafana 에서 확인할 수 있도록 대시보드를 구성해보곘다.
- my-app 설정
먼저 로그를 출력할 application 부터 설정해보겠다.
파이썬으로 개발한 간단한 코드이고 5초마다 info, error 로그를 하나씩 출력하도록 개발했다.
import time
import structlog
structlog.configure(
processors=[
structlog.processors.TimeStamper(fmt="iso"),
structlog.processors.add_log_level,
structlog.processors.JSONRenderer(),
]
)
log = structlog.get_logger()
while True:
log.info(
"request handled",
tenant_id="t_123",
status_code=200,
)
log.error(
"request failed",
tenant_id="t_456",
status_code=500,
)
time.sleep(5)
이 코드를 아래의 Dockerfile 과 docker-compose.yaml 을 통해서 빌드 후 도커 서비스로 실행시켜서 로그를 표준 출력으로 출력하도록 하겠다.
FROM python:3.11-slim
WORKDIR /app
COPY main.py .
RUN pip install structlog
CMD ["python", "main.py"]
services:
...
my-app:
image: my-app
container_name: my-app
build:
context: ./app
dockerfile: Dockerfile
logging:
driver: json-file
options:
tag: "my-app-service"
이렇게 구성한 후 Docker Compose 를 실행하면 아래와 같이 로그를 출력하는 것을 확인할 수 있다.
{"tenant_id": "t_123", "status_code": 200, "event": "request handled", "timestamp": "2026-03-11T09:18:29.644095Z", "level": "info"}
{"tenant_id": "t_456", "status_code": 500, "event": "request failed", "timestamp": "2026-03-11T09:18:29.644277Z", "level": "error"}
{"tenant_id": "t_123", "status_code": 200, "event": "request handled", "timestamp": "2026-03-11T09:18:34.642624Z", "level": "info"}
{"tenant_id": "t_456", "status_code": 500, "event": "request failed", "timestamp": "2026-03-11T09:18:34.642734Z", "level": "error"}
- Fluent Bit - input 연동
이제 Fluent Bit 가 my-app 의 로그를 수집하도록 input 연동을 진행해보겠다. 우선 docker container 의 로그를 읽기 위해서는 호스트의 도커 디렉토리를 Fluent Bit 컨테이너에 연결해주어야 한다.
docker container 의 logging driver 가 json-file 로 설정되어 있기 때문에 /var/lib/docker/containers 경로를 fluentbit 서비스에 volume 으로 연결해주어 로그 파일을 읽을 수 있게 해주었다.
fluentbit:
volumes:
- ./fluent-bit/fluent-bit.yaml:/fluent-bit/etc/fluent-bit.yaml
- /var/lib/docker/containers:/var/lib/docker/containers:ro
그 다음 fluent-bit.yaml 설정 파일을 아래와 같이 변경하여 my-app 컨테이너의 로그를 수집하도록 설정했다. tail 플러그인을 통해 도커 컨테이너들의 로그 파일을 읽고 그 중 `my-app-service` 라는 태그를 가진 로그만 필터링 되도록 했다. (이 태그는 my-app 의 docker compose 설정에서 logging.option 의 tag 로 지정한 값이다.)
service:
http_server: on
Health_Check: on
hot_reload: on
parsers:
# application 의 log json 형식 parsing
- name: json
format: json
time_key: timestamp
time_format: '%Y-%m-%dT%H:%M:%S.%L'
pipeline:
inputs:
# docker 로그 파일을 tail 기능으로 로그 수집
- name: tail
tag: docker.service
path: /var/lib/docker/containers/*/*-json.log
multiline.parser: docker, cri
filters:
# my-app 의 로그만 수집되도록 하기 위한 필터
# docker 로깅의 tag 설정 'my-app-service' 를 조건으로 로그 필터링
- name: grep
match: docker.service
regex: $attrs['tag'] ^my-app-service$
# my-app 의 로그에 대한 tag 변경
# docker.service -> my-app.log
- name: rewrite_tag
match: docker.service
rule: $attrs['tag'] ^my-app-service$ my-app.log false
# application log 파싱
- name: parser
match: my-app.log
key_name: log
parser: json
outputs:
- name: stdout
match: my-app.log
- Fluent Bit - Loki 연동
이번에는 output 설정을 변경하여 수집된 로그가 표준 출력이 아닌 Loki 로 전송되도록 변경해보겠다.
loki 플러그인을 사용했고 loki-write 서비스의 접속정보인 호스트와 포트를 지정해주었다. 그리고 labels, label_keys 를 통해 로그의 label 로 job, tenant_id, level 등을 지정해주었다.
pipeline:
...
outputs:
- name: loki
match: my-app.log
host: loki-write
port: 3100
labels: job=app
label_keys: $tenant_id, $level
- Grafana Dashboard 설정
이제 Fluent Bit 를 실행시키고 출력되는 로그를 Grafana 대시보드에서 확인할 수 있도록 설정해보겠다. Docker Compose 로 Grafana, Loki, Fluent Bit, my-app 을 모두 실행시켜보겠다.
그 다음 Grafana 에 접속하여 Loki 를 Data source 로 지정한 대시보드를 생성한다. 그 다음 panel 설정에서 query 를 작성해주면 되는데 간단하게 Label filters 에서 `job = app` 으로 설정해주면 my-app 이 출력한 로그들이 출력되는 것을 확인할 수 있다.

여기에 filter 로 `level = info` 또는 `level = error` 를 지정해주면 my-app 이 출력한 로그 중 INFO 또는 ERROR 로그만 출력되는 것을 확인할 수 있다.
[References]
- https://docs.fluentbit.io/manual
Fluent Bit documentation | Fluent Bit: Official Manual
High Performance Telemetry Agent for Logs, Metrics and Traces
docs.fluentbit.io
'기타' 카테고리의 다른 글
| [로그 모니터링] Grafana Alerting (0) | 2026.03.19 |
|---|---|
| [로그 모니터링] Loki 설치와 Grafana 연동 (0) | 2026.03.11 |
| [로그 모니터링] Garafana 설치 (0) | 2026.03.06 |
| [로그 모니터링] Fluent-bit + Loki + Grafana 로그 모니터링 시스템 (0) | 2026.02.28 |
| [RabbitMQ] RabbitMQ 개념 설명 (0) | 2025.05.13 |