Kubernetes 에서 EFK (ElasticSearch/FluentBit/Kibana) stack 설치하기

Jung-taek Lim
10 min readJan 1, 2021

--

역시 마찬가지로 디테일은 없다. 디테일은 레퍼런스 문서를 참고하자.

설치 순서는 ES -> Kibana -> FluentBit 순이다. Fluentd 를 먼저 시도했는데 ES 로 데이터가 유입되지 않았다. 유저 불량으로 보이긴 하는데 아무런 오류 메시지도 보여주지 않아서 원인 확인이 어려웠다. FluentBit 은 매끄럽게 바로 동작했다.

ES 와 Kibana 는 Helm chart 로 설치한다.

먼저 ES.

helm repo add elastic https://helm.elastic.co
kubectl create namespace elastic
helm install elasticsearch elastic/elasticsearch -n elastic

잠깐 테스트하고 뺄 예정이었어서 기본값으로 설치했는데, Minikube 에 작은 사이즈로 설치하려면 아래 명령으로 helm install 을 해주자.

curl -O https://raw.githubusercontent.com/elastic/Helm-charts/master/elasticsearch/examples/minikube/values.yaml
helm install --name elasticsearch elastic/elasticsearch -f ./values.yaml

설치가 완료되었으면

kubectl get all -n elastickubectl get pods --namespace=elastic -l app=elasticsearch-master -w

으로 설치된 object 들을 확인하자. 서비스에 elasticsearch-master 가 있어야 한다. 그리고 모든 pods 가 running 으로 전환되는 것을 확인하자.

서비스에 대해 port-forward 를 하고, index 리스트를 조회해서 정상적으로 동작하는지 확인하자.

kubectl port-forward -n elastic svc/elasticsearch-master 9200curl http://localhost:9200/_cat/indices

정상적으로 동작한다면 Kibana 설치로 넘어가자.

helm install kibana elastic/kibana -n elastic

kibana-kibana 가 deployment 에 등록되어 있을 것이다. 같은 이름으로 서비스도 등록되어 있다. port-forwarding 하고 브라우저에서 열어서 Kibana 페이지가 정상적으로 열리는지 확인하자.

kubectl port-forward deployment/kibana-kibana 5601

이제 ES 와 Kibana 는 설치되었다. FluentBit 을 설치해 보자.

FluentBit 은 helm chart 를 사용하지 않고 daemonset 을 직접 등록한다.

1) service account (service-account.yaml)

apiVersion: v1
kind: ServiceAccount
metadata:
name: fluent-bit
namespace: elastic

2) role (role.yaml)

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: fluent-bit-read
rules:
- apiGroups: [""]
resources:
- namespaces
- pods
verbs: ["get", "list", "watch"]

3) cluster role binding (role-binding.yaml)

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: fluent-bit-read
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: fluent-bit-read
subjects:
- kind: ServiceAccount
name: fluent-bit
namespace: elastic

4) configmap (configmap-1.yaml)

apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
namespace: elastic
labels:
k8s-app: fluent-bit
data:
fluent-bit.conf: |
[SERVICE]
Flush 1
Log_Level info
Daemon off
Parsers_File parsers.conf
@INCLUDE input-kubernetes.conf
@INCLUDE output-elasticsearch.conf
input-kubernetes.conf: |
[INPUT]
Name tail
Tag kube.*
Path /var/log/containers/*.log
Parser docker
DB /var/log/flb_kube.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
output-elasticsearch.conf: |
[OUTPUT]
Name es
Match *
Host ${FLUENT_ELASTICSEARCH_HOST}
Port ${FLUENT_ELASTICSEARCH_PORT}
Logstash_Format On
Logstash_Prefix fluent-bit
Retry_Limit False
parsers.conf: |
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On

읽을 파일 경로, 파서 규칙, 기록할 위치 등을 변경할 때 여길 변경하면 되겠다. 기본 설정은 모든 container 가 기록하는 로그 파일을 읽어들이도록 되어 있다. (/var/log/containers 아래 container 의 stdout/stderr 출력이 파일로 기록됨.)

5) daemonset (daemonset.yaml)

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
namespace: elastic
spec:
selector:
matchLabels:
k8s-app: fluent-bit-logging
template:
metadata:
labels:
k8s-app: fluent-bit-logging
spec:
containers:
- name: fluent-bit
image: fluent/fluent-bit:1.3.8
imagePullPolicy: Always
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: "elasticsearch-master"
- name: FLUENT_ELASTICSEARCH_PORT
value: "9200"
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: journal
mountPath: /journal
readOnly: true
- name: fluent-bit-config
mountPath: /fluent-bit/etc/
terminationGracePeriodSeconds: 10
volumes:
- name: varlog
hostPath:
path: /var/log
- name: journal
hostPath:
path: /var/log/journal
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: fluent-bit-config
configMap:
name: fluent-bit-config
serviceAccountName: fluent-bit
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule

fluent-bit-config 라는 이름으로 위의 config map 을 참조하고 있음을 알 수 있다.

순서대로 반영하자.

kubectl apply -f service-account.yaml
kubectl apply -f role.yaml
kubectl apply -f role-binding.yaml
kubectl apply -f configmap-1.yaml
kubectl apply -f daemonset.yaml

정상적으로 반영되었다면 각 node 별로 fluent-bit-* 이라는 pod 이 실행되고 있을 것이다. running 상태인지 한 번 확인해 주고, ES 의 index 를 다시 조회해 보자.

curl http://localhost:9200/_cat/indices

결과 라인 중 green open fluent-bit-날짜 … 가 있다면 성공이다.

이제 Kibana 페이지를 열어서, Management -> Stack Management -> Kibana -> Index Patterns 를 선택한다.

페이지에서 우측 상단의 Create index patterns 버튼을 누르고, 다음 페이지에서 index pattern name 에 “fluent-bit-*” 을 입력하면 아래 pattern 에 맞는 인덱스 리스트가 나타난다. (현재는 하나일 테고 날짜에 따라 계속 쌓이게 되겠다.) 원하는 결과가 나왔다면 Next Step 버튼을 눌러준다.

다음 페이지에서 Time field 에 @timestamp 를 선택하고, Create index pattern 버튼을 눌러 완성한다.

Kibana -> Discover 페이지로 돌아가면, 왼쪽 상단 index pattern 에 fluent-bit-* 로 나오고 필드 리스트가 나타날 것이다. 오른쪽에는 유입이 진행되고 있다면 메시지들이 업데이트 되고 있을 것이다. 혹시 메시지가 업데이트 되지 않는다면 Spark 어플리케이션 하나 제출해서 실행하면 업데이트 될 것이다.

References

--

--