본문 바로가기
Engineering/Fluent Bit

[Fluent Bit] #2 docker container을 활용한 INPUT 예시

by 거북이주인장 2022. 11. 21.

https://steady-programming.tistory.com/26

 

[Fluent Bit] #1 Fluent Bit란? (feat. Fluentd 동생)

정리배경 입사 후 담당하게 된 두번째 프로젝트가 팀에서 사용하는 로깅 (Logging) 파이프라인을 재구성하는 것이었다. 사내에서 사용하는 로깅 시스템이 있었지만 아래 이유 때문에 재구성의 필

steady-programming.tistory.com

이전 포스팅에서 fluent bit에 대해 간략히 알아보았다. 이번 포스팅에서는 fluent bit 도커 이미지를 활용해서 다양한 INPUT, OUTPUT 파이프라인을 만들어 보겠다.

사용할 도커 이미지


fluent bit 공식 도커 이미지를 사용한다.

https://hub.docker.com/r/fluent/fluent-bit/tags

 

Docker Hub

 

hub.docker.com

latest 태그 이미지의 마지막 실행 명령어는 아래와 같다.

CMD ["/fluent-bit/bin/fluent-bit" "-c" "/fluent-bit/etc/fluent-bit.conf"]

 

다시 말하면, fluent bit을 실행하는 명령어로써 우리가 원하는 INPUT과 OUTPUT으로 fluent bit을 실행하려면 원하는 .conf을 실행하는 이미지를 직접 빌드하든가, docker run의 volume 옵션을 사용하는 선택지가 있다. 필자는 후자의 방법이 더 간단한 것 같아서 이를 선택했다.

감을 잡기 위해 아래 도커 명령어를 실행해보자.

$ docker run -ti cr.fluentbit.io/fluent/fluent-bit:2.0 \
  -i cpu -o stdout -f 1

 

이는 아래의 .conf 파일을 실행한 것과 동일하다.

[INPUT]
  Name cpu

[OUTPUT]
  Name stdout
  Match *

 

아래와 같이 뜬다.

$ docker run -ti cr.fluentbit.io/fluent/fluent-bit:2.0 \
  -i cpu -o stdout -f 1
Fluent Bit v2.0.5
* Copyright (C) 2015-2022 The Fluent Bit Authors
* Fluent Bit is a CNCF sub-project under the umbrella of Fluentd
* https://fluentbit.io

[2022/11/20 07:34:07] [ info] [fluent bit] version=2.0.5, commit=8e5f9f9106, pid=1
[2022/11/20 07:34:07] [ info] [storage] ver=1.3.0, type=memory, sync=normal, checksum=off, max_chunks_up=128
[2022/11/20 07:34:07] [ info] [cmetrics] version=0.5.7
[2022/11/20 07:34:07] [ info] [ctraces ] version=0.2.5
[2022/11/20 07:34:07] [ info] [input:cpu:cpu.0] initializing
[2022/11/20 07:34:07] [ info] [input:cpu:cpu.0] storage_strategy='memory' (memory only)
[2022/11/20 07:34:07] [ info] [output:stdout:stdout.0] worker #0 started
[2022/11/20 07:34:07] [ info] [sp] stream processor started
[0] cpu.0: [1668929647.913392216, {"cpu_p"=>3.800000, "user_p"=>2.000000, "system_p"=>1.800000, "cpu0.p_cpu"=>4.000000, "cpu0.p_user"=>2.000000, "cpu0.p_system"=>2.000000, "cpu1.p_cpu"=>4.000000, "cpu1.p_user"=>2.000000, "cpu1.p_system"=>2.000000, "cpu2.p_cpu"=>4.000000, "cpu2.p_user"=>2.000000, "cpu2.p_system"=>2.000000, "cpu3.p_cpu"=>4.000000, "cpu3.p_user"=>2.000000, "cpu3.p_system"=>2.000000, "cpu4.p_cpu"=>3.000000, "cpu4.p_user"=>2.000000, "cpu4.p_system"=>1.000000}]
[0] cpu.0: [1668929648.913363716, {"cpu_p"=>4.400000, "user_p"=>1.800000, "system_p"=>2.600000, "cpu0.p_cpu"=>5.000000, "cpu0.p_user"=>2.000000, "cpu0.p_system"=>3.000000, "cpu1.p_cpu"=>4.000000, "cpu1.p_user"=>2.000000, "cpu1.p_system"=>2.000000, "cpu2.p_cpu"=>3.000000, "cpu2.p_user"=>1.000000, "cpu2.p_system"=>2.000000, "cpu3.p_cpu"=>3.000000, "cpu3.p_user"=>1.000000, "cpu3.p_system"=>2.000000, "cpu4.p_cpu"=>7.000000, "cpu4.p_user"=>3.000000, "cpu4.p_system"=>4.000000}]
...

 

그럼 본격적으로 INPUT과 OUTPUT을 원하는 형태로 바꿔보자.

여러 INPUT 예시


1) HTTP INPUT

먼저, 간단하게 http request 메세지를 INPUT으로 받는 fluent bit을 띄워보자. 관련 docs는 여기를 참고하자.

 

.conf 파일과 docker-compose.yml 파일을 아래와 같이 작성한다.

# fluent-bit.conf

[INPUT]
  Name http
  host 127.0.0.1
  port 8888

[OUTPUT]
  Name stdout
  Match *

# docker-compose.yml

version: "3.7"

services:
  fluent-bit:
    image: fluent/fluent-bit
    ports:
      - "8888:8888"
    platform: linux/amd64
    volumes:
      - ./fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf

 

  • ports: 컨테이너 포트와 호스트의 포트를 지정해줘야 한다.
  • platform: apple m1 mac이기 때문에 amd64로 지정했다.
  • volumes: 컨테이너에서 사용하는 fluent-bit.conf 파일을 호스트의 ./fluent-bit.conf로 바꾼다.

샘플로 보낼 test.json 파일을 아래와 같이 작성한다.

{"a": 123}
{"message": "my app rocks1", "running": true}

{"b": 456}
{"c": 0.123}

그리고 fluent bit로 로그를 보내본다.

$ curl -d @test.json -XPOST -H "content-type: application/json" http://localhost:8888

아래와 같이 로그가 잘 들어온 것을 확인할 수 있다.

2) Tail INPUT

로그를 처리하다보면 로거가 바라보는 파일에서 추가되는 line을 OUTPUT으로 보내는 경우가 종종 있다. Tail INPUT은 그러한 경우에 사용되며, 새롭게 추가되는 줄을 바라본다. 몇 가지 옵션을 살펴보고 자세한 내용은 공식 문서를 확인하자.

  • path: 하나의, 또는 여러개의 로그 파일 경로에 대한 패턴이다. 와일드 카드를 사용할 수 있고 ,로 여러 경로를 지정할 수 있다.
  • exclude_path: 특정 조건을 만족하는 파일을 제외한다. (예: *.gz,*.zip)
  • multiline.parser: Tail INPUT은 기본값으로 one line = one log로 인식한다. 근데 일부 로그는 multi lines = one log이다. 이를 위해 정규표현식 등을 사용하여 multiline.parser로 지정하고 multi lines = one log로 인식하도록 한다.

tail은 fluent bit가 띄워지는 컨테이너 안의 디렉토리를 바라본다. 따라서 만약에 로그가 발생하는 컨테이너와 fluent bit 컨테이너를 분리했다면, 로그 발생 컨테이너의 디렉토리와 fluent bit 컨테이너 디렉토리를 연결해야 한다.

 

필자는 이를 docker -v 옵션을 통해 host 디렉토리를 중간 다리 역할을 하는 것으로 설정했다. docker-compose.yml을 살펴보자.

# docker-compose.yml

version: "3.7"

services:
  fluent-bit:
    image: fluent/fluent-bit
    ports:
      - "8888:8888"
    platform: linux/amd64
    volumes:
      - ./fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf
      - ./output:/output
  python-tick:
    image: tick:latest
    volumes:
      - ./output:/output

3초에 한번씩 메세지를 뱉는 python-tick 컨테이너와 fluent bit 컨테이너를 띄운다. python-tick에서 발생하는 로그는 호스트의 ./output 디렉토리와 연결되고 이는 다시 fluent bit 컨테이너의 /output 디렉토리와 연결된다.

 

아래는 python-tick 컨테이너를 빌드한 Dockerfile이다.

FROM python:3.8.15-alpine3.16
COPY . .
RUN mkdir -p /output
CMD ["tick.py"]
ENTRYPOINT ["python3"]

 

아래는 tick.py이다.

from datetime import datetime
import time

if __name__ == '__main__':
    time.sleep(10) # waiting for fluent bit...
    for _ in range(10):
        with open('/output/tick.txt', 'a') as f:
            f.write(f'Tick! Current time: {datetime.now()} \n')
        time.sleep(3)

이제 컨테이너를 띄워보자.

$ docker-compose up

python-tick 컨테이너에서 발생하는 로그를 fluent bit 컨테이너가 잘 받는 것을 확인할 수 있다.

 

'Engineering > Fluent Bit' 카테고리의 다른 글

[Fluent Bit] #1 Fluent Bit란? (feat. Fluentd 동생)  (2) 2022.11.20

댓글