DevOps 잡다구리/Kubernetes Stuff

[Kubernetes] Kubernetes Elasticsearch operator

WhiteGoblin 2022. 6. 6. 15:16
반응형

쿠버네티스를 운영하는데 있어서 모니터링은 이제 필수적인 요소가 되었다. 

 

이러한 모니터링 툴에 있어서 다양한 툴이 존재하고 각각의 서비스는 필요에 따라서 사용되는 경우가 많았다. ( Datadog, elasticsearch 등등 )

 

본 글에서는 다양한 모니터링 툴중 Operator 패턴을 사용한 Elasticsearch 를 다룰 것이다. 

 

Elasticsearch 에 대한 개론적인 이야기를 원한다면 

 

https://esbook.kimjmin.net/

 

위 링크에서 더 자세히 알아 볼 수 있다. 

 

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
 필자의 경우 1.8 버전을 많이 사용했었지만 최근에 업데이트가 2.2.0 버전이었기 때문에 글을 작성하는 겸 새로운 버전으로 배포 해보고자 했다. 

 명령어를 사용하고 나면 클러스터 내부에 operator 가 실행되고 있음을 알 수 있다. Operator 는 이제 사용자의 요청에 따라서 elasticsearch, beat 계열에 관련된 object 들의 생성을 관리할 것이다. 

3.2 Deploy Elasticsearch
 우선 데이터를 취합할 Elasticsearch 클러스터를 배포해볼것이다.  HA ( High Availability ) 를 제공해주기 위해서 elasticsearch 3개를 만드는것이 권장된다.  [4]
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

[4]https://www.elastic.co/guide/en/elasticsearch/reference/current/high-availability-cluster-small-clusters.html

 

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

반응형