Fluent bit이란?
Fluent Bit은 다양한 로그 및 메트릭 데이터를 수집하고 처리하기 위한 경량의 오픈 소스 데이터 수집 및 전송 솔루션이다.
Fluent Bit은 다양한 플러그인 아키텍처를 제공하여 Prometheus 및 OpenTelemetry와 같은 다른 에코시스템과 통합할 수 있다.
또한, 최적의 성능을 제공하기 위해 설계되었다. 경량의 디자인과 최소한의 리소스 사용을 지향하여 대규모 환경에서도 효율적으로 동작한다. 작은 메모리와 CPU 리소스를 사용하여 데이터 수집 및 처리를 수행하므로, 시스템 부하를 최소화하면서도 높은 성능을 유지할 수 있다.
아래는 Fluentd와 Fluent Bit을 비교한 내용이다.
Text | Fluentd | Flunet Bit |
범위
|
컨테이너/서버
|
임베디드 Linux/컨테이너/서버
|
언어
|
C & Ruby
|
C
|
메모리
|
> 60MB
|
~1MB
|
성능
|
중간 성능
|
고성능
|
종속성
|
Ruby Gem으로 제작되어 일정 수의 gems이 필요.
|
일부 특수 플러그인이 요구하지 않는 한 종속성 없음.
|
플러그인
|
1000개 이상의 외부 플러그인 사용 가능
|
100개 이상의 내장 플러그인 사용 가능
|
특허
|
Apache License v2.0 |
Apache License v2.0
|
Fluent Bit은 아래와 같은 데이터 파이프라인 방식으로 동작한다.
- 입력(Input) : 다양한 데이터 소스로부터 로그 및 메트릭 데이터를 수집하기 위해 입력(Input) 플러그인을 제공한다. 파일 시스템 로그, 컨테이너 로그, 메시징 시스템 등 다양한 소스에서 데이터를 읽을 수 있다.
- 파서(Parser) : 수집한 데이터를 이해 가능한 형식으로 파싱 하여 처리하기 위해 파싱(Parsing) 단계를 거친다. 데이터를 구조화된 형태로 변환하고 필요한 필드를 추출한다.
- 필터(Filter) : 필터(Filter) 플러그인을 사용하여 데이터를 필터링하고 변형할 수 있다. 필터는 특정 조건에 따라 데이터를 걸러내거나 변형하는 기능을 제공한다. 예를 들어, 특정 로그 메시지를 포함하는 데이터만 선택하거나 필드 값을 변경하는 등의 작업을 수행할 수 있다.
- 버퍼(Buffer) : 데이터를 일시적으로 저장하는 공간이다. 버퍼는 데이터의 안정적인 전송을 보장하고 일시적인 네트워크 지연 또는 대상 시스템의 부하로 인한 지연을 관리하는 데 사용된다.
- 라우팅(Routing) : 목적지로 데이터를 라우팅 할 수 있는 기능이다. 데이터가 입력(Input) 플러그인에 의해 생성되면 데이터 소스를 식별할 수 있는 Tag가 제공되고, 출력(Output) 플러그인의 Match를 사용하여 Tag와 Match의 규칙을 읽어 라우팅 한다.
- 출력(Output) : 처리된 데이터를 원하는 대상으로 전송하기 위해 출력(Output) 플러그인을 사용한다. 출력 대상은 Elasticsearch, InfluxDB, Kafka, Amazon CloudWatch 등과 같은 데이터 저장소로 데이터를 전송할 수 있다.
Fluent Bit에서 중요한 개념 중 하나가 Buffering 기능이다.
Fluent Bit은 로그 데이터를 수집하고 CloudWatch와 같은 원격 대상으로 데이터를 전송하는 경우, 데이터 전송 중 네트워크 문제나 서버 문제 등으로 전송이 실패할 수 있다.
이러한 상황을 대비하여 Fluent Bit은 메모리 기반의 임시 버퍼링을 기본적으로 사용하지만, 필요한 경우 파일 시스템 기반의 영속적인 버퍼링 메커니즘을 활성화할 수 있다. 이를 통해 로그 데이터를 안전하게 저장하고 재전송이 필요한 경우에도 데이터 유실 없이 다시 전송할 수 있다.
영속적인 버퍼링을 사용하는 경우, Fluent Bit은 임시 저장소 디렉토리에 로그 데이터를 기록한다. 이 디렉토리는 보통 디스크 기반의 영속성을 제공하는 로컬 파일 시스템을 사용한다. 이렇게 함으로써 Fluent Bit이 비정상적으로 종료되거나 재시작되더라도 이미 수집된 로그 데이터를 유지하고 전송이 가능하다.
본 글에서는 아래 그림과 같이 쿠버네티스(EKS)에 Fluent bit을 설치하고 Pod 로그를 Amazon CloudWatch Log Group으로 보내는 실습을 다루고 이루어지는 동작에 대한 내용을 확인한다.
실습
전제 조건
- AWS EKS 클러스터
설치 환경
- AWS EKS v1.22
설치 버전
- Fluent Bit 1.9.10
1. 설치
Fluent Bit agnt가 CloudWatch에 접근할 수 있게 EKS Node의 iam role에 CloudWatchAgentServerPolicy 라는 이름의 정책을 연결시켜 권한을 부여한다.
정책 내용은 아래와 같다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudwatch:PutMetricData",
"ec2:DescribeVolumes",
"ec2:DescribeTags",
"logs:PutLogEvents",
"logs:DescribeLogStreams",
"logs:DescribeLogGroups",
"logs:CreateLogStream",
"logs:CreateLogGroup"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ssm:GetParameter"
],
"Resource": "arn:aws:ssm:*:*:parameter/AmazonCloudWatch-*"
}
]
}
Fluent BIt을 배포할 때 사용할 변수값을 fluent-bit-cluster-info 이름의 configmap으로 생성한다.
$ kubectl create ns amazon-cloudwatch # namespace 생성
$ ClusterName={cluster-name} # 클러스터 이름
$ RegionName={cluster-region} # 클러스터 리전
$ FluentBitHttpPort='2020' # fluentBit 메트릭 모니터링용 HTTP 서버 포트
$ FluentBitReadFromHead='Off' # tail Input 플러그인에서 파일을 처음부터 읽을지 여부
$ [[ ${FluentBitReadFromHead} = 'On' ]] && FluentBitReadFromTail='Off'|| FluentBitReadFromTail='On' # systemd Input 플러그인에서 파일을 끝부터 읽을지 여부
$ [[ -z ${FluentBitHttpPort} ]] && FluentBitHttpServer='Off' || FluentBitHttpServer='On' # fluentbit HTTP 서버 활성화
$ kubectl create configmap fluent-bit-cluster-info \
--from-literal=cluster.name=${ClusterName} \
--from-literal=http.server=${FluentBitHttpServer} \
--from-literal=http.port=${FluentBitHttpPort} \
--from-literal=read.head=${FluentBitReadFromHead} \
--from-literal=read.tail=${FluentBitReadFromTail} \
--from-literal=logs.region=${RegionName} -n amazon-cloudwatch
- 위 값은 EKS 클러스터 이름, 리전 정보, 메트릭 모니터링을 위한 HTTP 서버 활성화, tail과 systemd Input 플러그인에서 파일을 끝에서부터 읽게 하는 설정이다.
- HTTP 서버를 활성화 하면 Prometheus로 Fluent Bit 메트릭을 스크랩하여 Fluent Bit의 Input, output byte, fail count 등의 보다 자세한 정보를 확인할 수 있다.
실제로 위에서 지정한 값으로 생성되었는지 확인한다.
$ kubectl get cm -n amazon-cloudwatch fluent-bit-cluster-info -oyaml
apiVersion: v1
data:
cluster.name: wlsdn-eks
http.port: "2020"
http.server: "On"
logs.region: ap-northeast-2
read.head: "Off"
read.tail: "On"
kind: ConfigMap
metadata:
name: fluent-bit-cluster-info
namespace: amazon-cloudwatch
다음으로 aws에서 제공하는 fluent-bit.yaml 파일을 사용하여 배포한다.
$ kubectl apply -f https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/fluent-bit/fluent-bit.yaml
AWS에 CloudWatch Log group을 확인하면 아래와 같이 생성된 걸 확인할 수 있다.
2. 설정 내용 확인
위 로그 그룹이 어떤 식으로 생성되는지 확인해 보려면 배포한 fluent-bit.yaml의 ConfigMap [INPUT], [OUTPUT] 내용을 확인하면 된다.
application-log.conf: |
[INPUT]
Name tail
Tag application.*
Exclude_Path /var/log/containers/cloudwatch-agent*, /var/log/containers/fluent-bit*, /var/log/containers/aws-node*, /var/log/containers/kube-proxy*
Path /var/log/containers/*.log
multiline.parser docker, cri
DB /var/fluent-bit/state/flb_container.db
Mem_Buf_Limit 50MB
Skip_Long_Lines On
Refresh_Interval 10
Rotate_Wait 30
storage.type filesystem
Read_from_Head ${READ_FROM_HEAD}
[INPUT]
Name tail
Tag application.*
Path /var/log/containers/fluent-bit*
multiline.parser docker, cri
DB /var/fluent-bit/state/flb_log.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
Read_from_Head ${READ_FROM_HEAD}
[INPUT]
Name tail
Tag application.*
Path /var/log/containers/cloudwatch-agent*
multiline.parser docker, cri
DB /var/fluent-bit/state/flb_cwagent.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
Read_from_Head ${READ_FROM_HEAD}
[OUTPUT]
Name cloudwatch_logs
Match application.*
region ${AWS_REGION}
log_group_name /aws/containerinsights/${CLUSTER_NAME}/application
log_stream_prefix ${HOST_NAME}-
auto_create_group true
extra_user_agent container-insights
dataplane-log.conf: |
[INPUT]
Name systemd
Tag dataplane.systemd.*
Systemd_Filter _SYSTEMD_UNIT=docker.service
Systemd_Filter _SYSTEMD_UNIT=containerd.service
Systemd_Filter _SYSTEMD_UNIT=kubelet.service
DB /var/fluent-bit/state/systemd.db
Path /var/log/journal
Read_From_Tail ${READ_FROM_TAIL}
[INPUT]
Name tail
Tag dataplane.tail.*
Path /var/log/containers/aws-node*, /var/log/containers/kube-proxy*
multiline.parser docker, cri
DB /var/fluent-bit/state/flb_dataplane_tail.db
Mem_Buf_Limit 50MB
Skip_Long_Lines On
Refresh_Interval 10
Rotate_Wait 30
storage.type filesystem
Read_from_Head ${READ_FROM_HEAD}
[OUTPUT]
Name cloudwatch_logs
Match dataplane.*
region ${AWS_REGION}
log_group_name /aws/containerinsights/${CLUSTER_NAME}/dataplane
log_stream_prefix ${HOST_NAME}-
auto_create_group true
extra_user_agent container-insights
host-log.conf: |
[INPUT]
Name tail
Tag host.dmesg
Path /var/log/dmesg
Key message
DB /var/fluent-bit/state/flb_dmesg.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
Read_from_Head ${READ_FROM_HEAD}
[INPUT]
Name tail
Tag host.messages
Path /var/log/messages
Parser syslog
DB /var/fluent-bit/state/flb_messages.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
Read_from_Head ${READ_FROM_HEAD}
[OUTPUT]
Name cloudwatch_logs
Match host.*
region ${AWS_REGION}
log_group_name /aws/containerinsights/${CLUSTER_NAME}/host
log_stream_prefix ${HOST_NAME}.
auto_create_group true
extra_user_agent container-insights
- application-log.conf에서 전체 컨테이너 로그 중 "aws-node, kube-proxy"를 제외한 파드를 수집 대상으로 지정하고 해당 로그를 "/aws/containerinsights/${CLUSTER_NAME}/application" 로그 그룹으로 보낸다.
- dataplane-log.conf에서 워커노드의 "docker, containerd, kubelet" systemd 서비스와 "aws-node, kube-proxy" 파드를 수집 대상으로 지정하고 해당 로그를 "/aws/containerinsights/${CLUSTER_NAME}/dataplane" 로그 그룹으로 보낸다.
- host-log.conf에서 워커노드의 "/var/log/dmesg, messages, secure"를 수집 대상으로 지정하고 해당 로그를 "/aws/containerinsights/${CLUSTER_NAME}/host" 로그 그룹으로 보낸다.
각 로그 그룹에 들어가서 확인해 보면 아래와 같은 형식으로 로그 스트림이 생성되는 걸 확인할 수 있다.
- application
- ${HOST_NAME}-{Tag}.{docker_log_location}
- 예시 : ip-192-168-7-99.ap-northeast-2.compute.internal-application.var.log.containers.kubecost-grafana-75cbf968c7-lhbr2_kubecost_grafana-6ed3cb0c07fb5e6e3276d58c67fae35a21a2bafceba7bbead6cbb7f610547e64.log
- ${HOST_NAME}-{Tag}.{docker_log_location}
- dataplane
- systemd : ${HOST_NAME}-{Tag}.{systemd.service}
- 예시 : ip-192-168-7-99.ap-northeast-2.compute.internal-dataplane.systemd.containerd.service
- Pod : ${HOST_NAME}-{Tag}.{docker_log_location}
- 예시 : ip-192-168-7-99.ap-northeast-2.compute.internal-dataplane.tail.var.log.containers.kube-proxy-44jw2_kube-system_kube-proxy-ab0ce640e0f23d2cfe204d96380df6c93a8aa342284845ab728357da2188246d.log
- systemd : ${HOST_NAME}-{Tag}.{systemd.service}
- host
- ${HOST_NAME}-{Tag}
- 예시 : ip-192-168-7-99.ap-northeast-2.compute.internal.host.messages
- ${HOST_NAME}-{Tag}
3. Buffering 설정 확인
위에서 배포한 fluent-bit.yaml의 ConfigMap설정에서 Filesystem 기반 버퍼링 메커니즘이 설정되어 있다.
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
namespace: amazon-cloudwatch
labels:
k8s-app: fluent-bit
data:
fluent-bit.conf: |
[SERVICE]
...
storage.path /var/fluent-bit/state/flb-storage/
storage.sync normal
storage.checksum off
storage.backlog.mem_limit 5M
...
application-log.conf: |
[INPUT]
Name tail
Tag application.*
Exclude_Path /var/log/containers/cloudwatch-agent*, /var/log/containers/fluent-bit*, /var/log/containers/aws-node*, /var/log/containers/kube-proxy*
Path /var/log/containers/*.log
multiline.parser docker, cri
DB /var/fluent-bit/state/flb_container.db
Mem_Buf_Limit 50MB
Skip_Long_Lines On
Refresh_Interval 10
Rotate_Wait 30
storage.type filesystem
Read_from_Head ${READ_FROM_HEAD}
위 설정은 워커노드의 /var/fluent-bit/state/flb-storage/ 위치에 filesystem(storage.type) 형식으로 버퍼 하고 파일 사이즈는 최대 5M까지 쌓는데 5M가 넘어가면 다른 파일에 쌓는다. 이후 CloudWatch로 데이터를 보내게 되면 버퍼 하고 있는 파일은 삭제한다.
예를 들어 예기치 못한 상황에 의해 Fluent Bit이 중지되어 로그 데이터를 [OUTPUT]으로 보내지 못하면 해당 데이터를 storage.path 경로에 데이터 청크를 저장하는 backlog가 생성된다. 이후 Fluent Bit이 재시작되면 storage.path에 있는 backlog 데이터를 확인하고 메모리 사용 제한에 따라 데이터를 메모리로 가져와서 OUTPUT으로 전송하게 된다.
'Observability > Fluent Bit' 카테고리의 다른 글
Fluent Bit을 사용하여 Amazon S3로 로그 전송하기 (8) | 2023.07.22 |
---|
댓글