[Kubernetes] Kubernetes Elasticsearch operator
쿠버네티스를 운영하는데 있어서 모니터링은 이제 필수적인 요소가 되었다.
이러한 모니터링 툴에 있어서 다양한 툴이 존재하고 각각의 서비스는 필요에 따라서 사용되는 경우가 많았다. ( Datadog, elasticsearch 등등 )
본 글에서는 다양한 모니터링 툴중 Operator 패턴을 사용한 Elasticsearch 를 다룰 것이다.
Elasticsearch 에 대한 개론적인 이야기를 원한다면
위 링크에서 더 자세히 알아 볼 수 있다.
Elastic 가이드 북 - Elastic 가이드북
7. 인덱스 설정과 매핑 - Settings & Mappings
esbook.kimjmin.net
우선 Operator 패턴이 무엇인지 그리고 Elasticsearch 가 무엇인지 그리고 Elasticsearch Operator 패턴은 어떻게 운영되는지 알아 볼것이다.
1. Operator 패턴
쿠버네티스에서 Operator 는 사용자 정의 리소스 ( CRD ) 를 사용하여서 애플리케이션 및 해당 컴포넌트를 관리하는 쿠버네티스의 소프트웨어 익스텐션이다. 오피레이터는 쿠버네티스 원칙 특히 컨트롤 루프를 따른다. [1]
위 문장이 쿠버네티스 공식 홈페이지에서 공식적으로 정의하고 있는 Operator 패턴에 대한 이야기 이다.
실제로 사용해본 사람의 입장에서 조금더 간추리자면 하나의 오퍼레이터가 pod 형태 ( deployment ) 로 있고 해당 오퍼레이터에서 사용자의 요구 사항에 따라서 여러 요소들을 실행 시키거나 요구한 요청대로 실행되고 있지 않을 경우 요청 사항 대로 상태를 만들어주기 위해서 동작시키게 된다.
2. Elasticsearch
Elasticsearch 는 텍스트, 숫자, 위치 기반 정보, 정형 및 비정형 데이터 등 모든 유형의 데이터를 무료 검색 및 분석 엔진으로 분산형과 개방형을 특징으로 합니다. Elasticsearch는 Apache Lucene을 기반으로 구축되었으며, Elasticsearch N.V.(현재 명칭 Elastic)가 2010년에 최초로 출시했습니다. 간단한 REST API, 분산형 특징, 속도, 확장성으로 유명한 Elasticsearch는 데이터 수집, 보강, 저장, 분석, 시각화를 위한 무료 개방형 도구 모음인 Elastic Stack의 핵심 구성 요소입니다. 보통 ELK Stack(Elasticsearch, Logstash, Kibana의 머리글자)이라고 하는 Elastic Stack에는 이제 데이터를 Elasticsearch로 전송하기 위한 경량의 다양한 데이터 수집 에이전트인 Beats가 포함되어 있습니다. [2]
위 정의에서 말하듯이 Elasticsearch 의 경우 다양한 데이터를 모으고 이러한 데이터를 빠르게 검색 및 요청을 통해서 받아오기 위한 툴이라고 보면 될것이다.
Elasticsearch 는 기본적으로 beat 를 기본 형태의 데이터로 Elasticsearch cluster 에 수집하게 된다.
본 글에서는
* Elasticsearch
* Kibana
* metricbeat
* filebeat
* heartbeat
정도를 Operator 에서 사용하는 법을 알아 볼것이다.
3. Elasticsearch Operator 패턴
우선 쿠버네티스 클러스터가 있다는 가정하에 yml 파일을 통해서 Operator 의 기본 CRD 를 정의 해주고 Operator 를 배포할 것이다.
3.1. Deploy ECK [3]
kubectl create -f https://download.elastic.co/downloads/eck/2.2.0/crds.yaml
해당 명령어를 입력하면 기본적인 CRD 들에 대해서 정의하게 된다. CRD 를 정의하게 되면 이제 실제 Operator 를 실행 시킬수 있는 기본적인 준비가 된것이다.
kubectl apply -f https://download.elastic.co/downloads/eck/2.2.0/operator.yaml
명령어를 사용하고 나면 클러스터 내부에 operator 가 실행되고 있음을 알 수 있다. Operator 는 이제 사용자의 요청에 따라서 elasticsearch, beat 계열에 관련된 object 들의 생성을 관리할 것이다.
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: elasticsearch
namespace: elasticsearch
spec:
version: 7.17.3
http:
tls:
selfSignedCertificate:
disabled: true
nodeSets:
- name: default
count: 3
podTemplate:
metadata:
annotations:
traffic.sidecar.istio.io/includeInboundPorts: "*"
traffic.sidecar.istio.io/excludeOutboundPorts: "9300"
traffic.sidecar.istio.io/excludeInboundPorts: "9300"
spec:
automountServiceAccountToken: true
config:
node.master: true
node.data: true
node.ingest: true
node.store.allow_mmap: false
volumeClaimTemplates:
- metadata:
name: elasticsearch-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 64Gi
본 yaml 파일을 배포하면 해당 설정에 따라서 7.17.3 버전의 3개 elasticsearch 를 배포하게 된다.
이 과정에서 Operator 에서 crd state 를 인지하게 되고 생성하게 된다. 3개의 elasticsearch 중 하나가 소실되게 되어도 다시 복원할 수 있게 된다.
본 yaml 파일만 봤을 때는 Operator 패턴의 장점을 찾아 보기 어렵지만 beats 를 배포할 때 편리함이 커진다.
3.3 Kibana
우선 Elasticsearch 에서 취합한 데이터를 볼 수 있는 Kibana 에 대한 배포를 진행하고자 한다.
kibana 의 CRD 경우 operator 의 CRD 를 배포할 때 같이 해주었기 때문에 kibana yaml 파일을 바로 배포하면 된다.
apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
name: kibana
spec:
version: 7.17.3
http:
tls:
selfSignedCertificate:
disabled: true
count: 1
podTemplate:
spec:
automountServiceAccountToken: true
elasticsearchRef:
name: elasticsearch
버전은 최대한 Elasticsearch 와 맞추는 것이 좋다.
elasticsearchRef 를 통해서 kibana 가 elasticsearch 와 연결할 수 있도록 operator 가 도와준다.
3.4 Metricbeat
이제 데이터를 취합할 elasticsearch 와 데이터를 보여주는 Kibana 를 배포 하였으니 이제는 노드의 제일 기본이 되는 metric 들을 수집 해보겠다.
kubectl apply -f https://raw.githubusercontent.com/elastic/cloud-on-k8s/2.2/config/recipes/beats/metricbeat_hosts.yaml
해당 yml 파일에는 metricbeat 에 대한 CRD, SA 등이 정의 되어 있고 해당 파일을 통해서 간편하게 배포를 진행할 수 있다.
본 필자의 경우 해당 yaml 파일을 다운 받은 다음 데이터를 수집하고자 하는 elasticsearch 로 주소를 변경만 해주어서 데이터를 취합하는데 용이하게 하였다.
[metricbeat.yml]
apiVersion: beat.k8s.elastic.co/v1beta1
kind: Beat
metadata:
name: metricbeat
namespace: elasticsearch
spec:
type: metricbeat
version: 7.17.3
secureSettings:
- secretName: elasticsearch-secret
config:
tags: ["test_cluster"]
metricbeat:
autodiscover:
providers:
- hints:
default_config: {}
enabled: "true"
host: ${NODE_NAME}
type: kubernetes
modules:
- module: system
period: 10s
metricsets:
- cpu
- load
- memory
- network
- process
- process_summary
process:
include_top_n:
by_cpu: 5
by_memory: 5
processes:
- .*
- module: system
period: 1m
metricsets:
- filesystem
- fsstat
processors:
- drop_event:
when:
regexp:
system:
filesystem:
mount_point: ^/(sys|cgroup|proc|dev|etc|host|lib|opt)($|/)
- module: kubernetes
period: 10s
host: ${NODE_NAME}
hosts:
- https://${NODE_NAME}:10250
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
ssl:
verification_mode: none
metricsets:
- node
- system
- pod
- container
- volume
- event
processors:
- add_cloud_metadata: {}
- add_host_metadata: {}
output:
elasticsearch:
enabled: true
hosts:
- ${ELASTICSEARCH_ADDRESS}:9200
protocol: https
ssl:
enabled: true
verification_mode: none
username: "${ELASTICSEARCH_USERNAME}"
password: "${ELASTICSEARCH_PASSWORD}"
daemonSet:
podTemplate:
spec:
serviceAccountName: metricbeat
automountServiceAccountToken: true
containers:
- args:
- -e
- -c
- /etc/beat.yml
- -system.hostfs=/hostfs
name: metricbeat
resources:
requests:
memory: 300Mi
cpu: 0.2
limits:
memory: 500Mi
cpu: 0.2
volumeMounts:
- mountPath: /hostfs/sys/fs/cgroup
name: cgroup
- mountPath: /var/run/docker.sock
name: dockersock
- mountPath: /hostfs/proc
name: proc
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: ELASTICSEARCH_ADDRESS
valueFrom:
secretKeyRef:
name: elasticsearch-secret
key: ELASTICSEARCH_ADDRESS
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true
securityContext:
runAsUser: 0
terminationGracePeriodSeconds: 30
volumes:
- hostPath:
path: /sys/fs/cgroup
name: cgroup
- hostPath:
path: /var/run/docker.sock
name: dockersock
- hostPath:
path: /proc
name: proc
[metricbeat crd ]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: metricbeat
rules:
- apiGroups:
- ""
resources:
- nodes
- namespaces
- events
- pods
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
resources:
- replicasets
verbs:
- get
- list
- watch
- apiGroups:
- apps
resources:
- statefulsets
- deployments
- replicasets
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- nodes/stats
verbs:
- get
- nonResourceURLs:
- /metrics
verbs:
- get
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: metricbeat
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: metricbeat
subjects:
- kind: ServiceAccount
name: metricbeat
roleRef:
kind: ClusterRole
name: metricbeat
apiGroup: rbac.authorization.k8s.io
해당 배포를 통해서 Host 의 CPU, memory, network, file system 에 대한 정보 및 Kubernetes 의 Nodes, Pods, Containers ,Volumes 에 대한 정보를 가지고 올 수 있다.
해당 데이터는 Kibana -> Observability -> Metrics 에서 간편하게 확인할 수 있고 데이터가 어떻게 들어오는지를 보기 위해서는
Kibana -> analytics -> discover 에서어떻게 들어오는지에 대해서 확인이 가능하다. 차후 heartbeat, filebeat 또한 비슷하게 작동한다.
3.5 Filebeat
apiVersion: beat.k8s.elastic.co/v1beta1
kind: Beat
metadata:
name: filebeat
namespace: elasticsearch
spec:
type: filebeat
version: 7.17.3
secureSettings:
- secretName: elasticsearch-secret
config:
output:
elasticsearch:
enabled: true
hosts:
- ${ELASTICSEARCH_ADDRESS}:9200
protocol: https
ssl:
enabled: true
verification_mode: none
username: "${ELASTICSEARCH_USERNAME}"
password: "${ELASTICSEARCH_PASSWORD}"
filebeat:
autodiscover:
providers:
- type: kubernetes
node: ${NODE_NAME}
hints:
enabled: true
default_config:
type: container
paths:
- /var/log/containers/*${data.kubernetes.container.id}.log
processors:
- add_cloud_metadata: {}
- add_host_metadata: {}
- add_tags:
tags: ["test_cluster"]
target: "cluster.name"
daemonSet:
podTemplate:
spec:
serviceAccountName: filebeat
automountServiceAccountToken: true
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true # Allows to provide richer host metadata
securityContext:
runAsUser: 0
containers:
- name: filebeat
volumeMounts:
- name: varlogcontainers
mountPath: /var/log/containers
- name: varlogpods
mountPath: /var/log/pods
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
volumes:
- name: varlogcontainers
hostPath:
path: /var/log/containers
- name: varlogpods
hostPath:
path: /var/log/pods
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: filebeat
rules:
- apiGroups: [""] # "" indicates the core API group
resources:
- namespaces
- pods
- nodes
verbs:
- get
- watch
- list
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: filebeat
namespace: elasticsearch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: filebeat
subjects:
- kind: ServiceAccount
name: filebeat
namespace: elasticsearch
roleRef:
kind: ClusterRole
name: filebeat
apiGroup: rbac.authorization.k8s.io
---
filebeat 의 경우 쿠버네티스 위에서 작동하고 있는 어플리케이션들에 대한 로그를 가지고 올 수 있다.
이를 통해서 개발자들이 어플리케이션의 로그를 Kibana 에서 확인할 수 있다.
3.6 Heartbeat
Heartbeat 의 경우 서비스에 http, tcp 요청을 보내서 실제 서비스가 작동하는지 확인하는 유용한 beats 이다.
apiVersion: beat.k8s.elastic.co/v1beta1
kind: Beat
metadata:
name: heartbeat
namespace: elasticsearch
spec:
type: heartbeat
version: 7.17.3
elasticsearchRef:
name: elasticsearch
config:
heartbeat.monitors:
- type: tcp
schedule: '@every 5s'
hosts: ["elasticsearch-es-http.default.svc:9200"]
- type: tcp
schedule: '@every 5s'
hosts: ["kibana-kb-http.default.svc:5601"]
deployment:
replicas: 1
podTemplate:
spec:
securityContext:
runAsUser: 0
요청을 얼마나 많이 보낼지와 어떠한 요청을 보낼지에 대한 정의를 할 수 있게 된다.
4. Operator 를 사용했을 때 이점 및 사용에 있어서 현실적인 제약
실제로 Operator 를 사용했을 때의 이점은 yaml 파일들에서 확인할 수 있다.
기존의 Operator 를 사용하지 않은 경우 Config 에 대한 정의를 파일에 따로 하고 해당 파일을 마운트 및 확인 해야 하지만 CRD 로 정의되어 있는 Operator 를 통해서 배포시 yaml 파일에 설정을 다 넣을 수 있고 daemonset 설정 또한 지정할 수 있고 elasticsearch 의 가장 큰 장점중 하나인 auto discover 를 사용해서 많이 사용되는 쿠버네티스의 경우 filebeat 를 통해서 간단하게 앱의 로그를 불러 올 수 있다.
하지만 이제 현실적인 이야기를 해야할 시간이다.
Elasticsearch 의 가장 큰 장점중 하나는 무료이다 라는 문구 이지만 실제 모니터링을 사용하는 이유는 모니터링을 통해서 이상이 발생하면 alert 를 보내야 한다는 것이다. 하지만 이러한 alert 를 보내기 위해서는 license 가 필요하거나 클라우드를 사용해야 한다. Elasticsearch 의 경우 Operator 를 클라우드에서 사용시 라이센스 비용이 매우 비싸며 이 때문에 설치형으로 사용하는 경우가 많았다. 하지만 설치형에 대한 지원 또한 줄여가고 있다. Elasticsearch 8 버전을 넘어가면서 이러한 설치형에 대한 지원 또한 줄여가고 있는 상황이다. ( 골드 라이센스의 경우 이미 만료 되었다. )
그렇기에 편리한 Operator 이지만 현실적인 이유로 사용자가 맞게 사용을 해야 한다.
[참고 문헌]
[1] https://kubernetes.io/ko/docs/concepts/extend-kubernetes/operator/
오퍼레이터(operator) 패턴
오퍼레이터(Operator)는 사용자 정의 리소스를 사용하여 애플리케이션 및 해당 컴포넌트를 관리하는 쿠버네티스의 소프트웨어 익스텐션이다. 오퍼레이터는 쿠버네티스 원칙, 특히 컨트롤 루프를
kubernetes.io
[2] https://www.elastic.co/kr/what-is/elasticsearch
Elasticsearch란?
Elasticsearch 시작하기: 무료 개방형 Elastic Stack으로 저장, 검색 및 분석. 동영상 보기 ELK 소개: Kibana에서 로그, 메트릭, 데이터 수집 및 사용자 정의 가상화 시작하기. 동영상 보기 Elastic Cloud 시작하
www.elastic.co
[3]https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-deploy-eck.html
Deploy ECK in your Kubernetes cluster | Elastic Cloud on Kubernetes [2.2] | Elastic
The ECK operator runs by default in the elastic-system namespace. It is recommended that you choose a dedicated namespace for your workloads, rather than using the elastic-system or the default namespace.
www.elastic.co
Resilience in small clusters | Elasticsearch Guide [8.2] | Elastic
Resilience in small clustersedit In smaller clusters, it is most important to be resilient to single-node failures. This section gives some guidance on making your cluster as resilient as possible to the failure of an individual node. If your cluster consi
www.elastic.co
[5] https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-beat-configuration-examples.html