Kubernetes, EFK (ElasticSearch, Fluent-bit, Kibana) 구성
도입 이유
쿠버네티스는 시스템을 유지하기 위해 자체적으로 오류를 감지하고 복구하는 메커니즘을 가지고 있습니다. (self-healing기능) 예를 들어 컨테이너가 비정상적으로 종료되거나 반응이 없을 때, 해당 Pod를 자동으로 재시작 합니다. Pod가 재시작되면 해당 Pod가 사용하던 컨테이너 인스턴스는 제거되고, 새로운 컨테이너와 인스턴스가 생성되는 과정에 기존 컨테이너 로컬 저장소에 있던 로그 파일들은 삭제가 됩니다. Pod안에 임시 볼륨이 삭제되고 새로운 파일 시스템이 생성되기 때문입니다. 하지만 운영을 하는 입장에서 왜 Pod가 재시작이 되었는지 알아야 되기 때문에 컨테이너가 살아있을때 외부 로그 저장소에 로그를 수집,저장,분석하여 서비스의 안정성 및 로그 관리를 위해 EFK를 도입 했습니다.
개념
클러스터 내의 모든 노드에서 로그를 수집하기 위해 Fluent Bit을 DaemonSet으로 배포하여 로그를 수집하여 중앙의 Elasticsearch로 전달 합니다. Elasticsearch는 전달받은 로그에 대해 저장 및 검색 기능을 제공하며 Kibana는 이 로그들을 쿼리하고 시각화 할수 있게 해줍니다. 이 세가지 컴포넌트가 함께 작동하여 로그 관리 및 분석 파이프라인을 구성합니다.
설치 과정
Elasticsearch 최신버전은 helm을 통해 설치해주자
helm repo add elastic https://helm.elastic.co
helm install elasticsearch elastic/elasticsearch
설치가 완료되었으면 설치된 모든 오브젝트를 확인하자 서비스에 elasticsearch-master 가 있어야 한다. 그리고 모든 pods 가 running 으로 전환되는 것을 확인하자.
kubectl get all
port-forward 를 하고, index 리스트를 조회해서 정상적으로 동작하는지 확인하자.
포트포워딩을 하고 인덱스를 조회할 때 8. 이후 버전부터 보안이 강화되어 helm차트에서 다운받을때 자동으로 생성되는 패스워드와 기본 아이디값을 입력해줘야된다.
# 자동으로 생성된 패스워드 조회
kubectl get secret elasticsearch-master-credentials -o go-template='{{.data.password | base64decode}}'
# 고정 아이디 값은 elastic 이지만 조회하는 명령어이다.
kubectl get secret elasticsearch-master-credentials -o go-template='{{.data.username | base64decode}}'
-k 옵션을 줘서 cURL 인증서 검증을 무시하고 -u 명령어를 통해 아이디와 패스워드를 입력하여 조회하자
# -k 옵션을 줘서 cURL에 인증서 검증을 무시
curl -k -u elastic:vpyBZSyphcx1fjiG https://localhost:30000/_cat/indices\?v
성공적으로 조회가 되었다.
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
다음으로 Kibana를 설치하자
helm install kibana elastic/kibana
마찬가지로 포트포워딩을 하여 Kibana에 접속해보자
다음은 Fluent-bit을 설치해보자
Fluent-bit은 helm차트가 아닌 yaml파일로 구성하였다.
fluentbit-serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: fluent-bit
namespace: monitoring
fluentbit-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: fluent-bit-read
rules:
- apiGroups: [""]
resources:
- namespaces
- pods
verbs: ["get", "list", "watch"]
fluentbit-rolebinding.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: monitoring
fluentbit-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
namespace: monitoring
labels:
k8s-app: fluent-bit
data:
fluent-bit.conf: |
[SERVICE]
Flush 1
Log_Level info
Daemon off
Parsers_File parsers.conf
@INCLUDE filter-kubernetes.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
filter-kubernetes.conf: |
[FILTER]
Name kubernetes
Match kube.*
Kube_URL https://kubernetes.default.svc
Merge_Log On
Keep_Log Off
K8S-Logging.Parser On
K8S-Logging.Exclude Off
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
HTTP_User elastic
HTTP_Passwd vpyBZSyphcx1fjiG
tls on
tls.verify off
Suppress_Type_Name On
parsers.conf: |
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
fluentbit-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
namespace: monitoring
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:latest
imagePullPolicy: Always
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: "elasticsearch-master"
- name: FLUENT_ELASTICSEARCH_PORT
value: "9200"
- name: FLUENT_ELASTICSEARCH_HTTPS
value: "on"
- name: FLUENT_ELASTICSEARCH_USER
value: "elastic"
- name: FLUENT_ELASTICSEARCH_PASSWORD
value: "S77RMGFWQo2geB1O"
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
모든 설정을 apply 해주고 kibana에 접속해 Management → Stack Management → Data views 에서 Create data view에서 fluent-bit- Index pattern 추가해주고 Discover에서 확인하면 끝이 난다!
다음은 Kibana dashboard 설정하는 방법을 정리할 예정이다.