[EFK] 쿠버네티스 환경 내 Fluent-Bit 사이드카로 엘라스틱 서치 로깅
이전 글에서는 로그 수집기의 종류와 아키텍처를 알아보았다.
이번 글에서는 Fluent-Bit을 쿠버네티스 파드 내에서 사이드카 형식으로 구축을 하고, 수집한 로그 정보를 엘라스틱 서치로 바로 전송하는 과정을 알아볼 것이다.
사이드카란
사이드카란 이륜차 옆에 좌석을 설치하여, 두 사람이 함께 같이 탈 수 있게 한 유형의 이륜차를 의미한다.
아래 사진을 참고하면 좀 더 쉽게 이해할 수 있을 것이다.
이를 쿠버네티스 환경에 개념적으로 도입한다는 것인데, 쿠버네티스 파드는 일반적으로 한 개 이상의 컨테이너로 구성되어 있는데, 두 개 이상의 멀티 컨테이너 방식으로 운용하는 것을 사이드카 패턴이라고 한다.
기본적으로 파드 내부의 컨테이너 간 네트워크는 공유가 되지만, 파일 시스템은 공유가 되지 않기 때문에, 로그가 저장되는 디렉터리를 각 컨테이너에 마운트 하여 애플리케이션에서 발생시키는 로그를 로그 수집기가 이용할 수 있도록 만들어줘야 한다.
파드 내 구조를 보자면 아래와 같이 나타낼 수 있다.
쿠버네티스 Docs에서도 로깅 아키텍처에 대하여 다루고 있는 부분이 존재한다.
https://kubernetes.io/ko/docs/concepts/cluster-administration/logging/
위 사이트에서는 크게 두 가지 방식으로 수집하는 것을 확인할 수 있다.
특정 노드에 띄워진 파드가 노드 내에 로그를 남기고, 노드에 Daemonset으로 존재하는 Agent가 이를 수집하는 노드 로깅 방식과,
특정 파드 내에서 생성되는 로그를 사이드카 형식으로 동일한 파드 내에서 Agent가 Logging Backend로 전송하는 사이드카 로깅 방식을 볼 수 있다.
+ 사이드카 방식은 리소스 낭비(Agent의 단일 파드에 대한 활용)로 이어질 수 있고, kubelet에서 로그를 제어할 수 없는 단점이 존재한다.
실습
다음은 Deployment의 객체에서 하나의 파드에서 아래 두 개의 컨테이너가 동작하게끔 만든 yaml이다.
1. 로그를 남기는 ubuntu 컨테이너
2. 로그를 수집할 Fluent-bit의 컨테이너
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-log-deploy
labels:
deployment: test-log-deploy
spec:
replicas: 1
selector:
matchLabels:
app: test-log-app
template:
metadata:
labels:
app: test-log-app
microservice: logger
project: test
spec:
containers:
- name: test-log-container
image: ubuntu:latest
volumeMounts:
- name: log-volume
mountPath: /logs
command: ["/bin/sh", "-c"]
args:
- |
while true; do echo $(date +"%Y-%m-%dT%H:%M:%S.%9N") [INFO] log message >> /logs/current_time.log; sleep 1; done
- name: fluent-bit-sidecar
image: fluent/fluent-bit:3.1.3
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_UID
valueFrom:
fieldRef:
fieldPath: metadata.uid
- name: APP_NAME
valueFrom:
fieldRef:
fieldPath: metadata.labels['app']
- name: MICRO_SERVICE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.labels['microservice']
- name: PROJECT_NAME
valueFrom:
fieldRef:
fieldPath: metadata.labels['project']
volumeMounts:
- name: log-volume
mountPath: /logs
- name: fluent-bit-sidecar-config
mountPath: /fluent-bit/etc/
volumes:
- name: log-volume
emptyDir:
sizeLimit: 2Gi
- name: fluent-bit-sidecar-config
configMap:
name: test-fluent-config
ubuntu의 컨테이너에서 /logs 하위에 사진과 같은 로그를 남기고 해당 디렉터리를 Fluent-bit 컨테이너에 마운트 시켜 수집해갈 수 있도록 만든 것이다.
다음은 Fluent-bit 컨테이너에서 사용할 config파일의 Configmap이다.
apiVersion: v1
kind: ConfigMap
metadata:
name: test-fluent-config
data:
parsers.conf: |
[PARSER]
Name parser
Format Regex
Regex /^(?<time>[0-9-T]*[^ ]*) (?<level>[\Sa-zA-Z]*[^ ]) (?<log>[.]*)?$/
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
fluent-bit.conf: |
[SERVICE]
Parsers_File parsers.conf
[INPUT]
Name tail
Path /logs/*.log
Parser parser
Tag <date>
Tag_Regex /logs/(?<date>[\S]+).log
Refresh_Interval 10
Mem_Buf_Limit 50MB
Skip_Long_Lines On
[FILTER]
name parser
Match *
Parser parser
Key_Name parser
[FILTER]
name modify
Match *
Add microservice ${MICRO_SERVICE_NAME}
[OUTPUT]
Name es
Match *
Host [엘라스틱 서치 HOST]
Port [엘라스틱 서치 PORT]
HTTP_USER [엘라스틱 서치 유저]
HTTP_Passwd [엘라스틱 서치 비밀번호]
tls Off
tls.verify Off
Logstash_Prefix ${PROJECT_NAME}-${MICRO_SERVICE_NAME}
Logstash_Format On
Retry_Limit False
Buffer_Size 256KB
Time_Key time
옵션에 대하여 간단하게 설명하자면, Fluent-bit에서 로그를 읽고 기입된 정규식 표현에 따라 파싱 하고, 환경 변수 등을 넘겨받고 추가한 데이터를 엘라스틱 서치로 전송하는 내용이다.
위 Deployment 및 Configmap의 작성 후 오브젝트를 생성하고, 키바나에 접속하여 엘라스틱 서치에 저장되는 데이터를 확인하려면 다음과 같이 접속하여 해당 인덱스의 패턴을 만들어 줘야 한다.
1. Management -> Stack Management 접속
2. Kibana -> Index Patterns 접속
3. Create index pattern 접속
위 과정을 정상적으로 따라온다면 아래와 같은 정보를 볼 수 있다.
하위에 Fluent-bit의 Config에서 설정한 양식으로 인덱스가 생성됐다는 것을 볼 수 있다.
이 인덱스를 활용하기 위해 인덱스 패턴을 등록해 준다.
4. Index-name 설정 및 패턴 등록
패턴으로는 생성된 index명과 뒤에는 정규식으로 모든 하위 모든 패턴을 등록해 준다는 *(Asterisk)로 입력한다.
그리고 Next step으로 넘어가면 Time으로 어떤 field를 사용할지 선택하는 부분이 나온다.
Fluent-bit의 Config에서 정규식으로 파싱 해서 얻은 time이라는 Key를 이용한다고 설정했으므로 time으로 선택 후 패턴을 생성한다.
5. 데이터 확인 (Analytics -> Discover 접속)
인덱스 패턴을 만들면 인덱싱 된 패턴으로 데이터를 확인할 수 있다.
좌측 상단에서 인덱스 패턴을 선택한다.
그러면 다음과 같이 실시간으로 저장되고 있는 데이터를 확인할 수 있다.
참고
아래는 데이터에 정규식 표현을 대입하여 어떻게 파싱이 되는지 미리 확인해 볼 수 있는 사이트다.
+ 실습에서는 App이 남기는 로그 파일에 대하여 데이터를 읽고 전송하는 방식으로 구현을 했었는데, 이를 stdout과 stderr을 활용하여 구축한다면 더 효율적인 아키텍처가 될 것이다.