본문 바로가기
쿠버네티스

ELK 구축하기

by DarrenH 2024. 7. 16.
반응형

오늘은 쿠버네티스에 ELK를 구축하는 방법을 포스팅하려고한다.

ELK는 3개의 tool을 합친거다

Elasticsearch + Logstash + Kibana 를 합친 용어로 ELK라 부르며 또 다른 조합으로는 EFK가있다.

나는 단순히 ELK로 서버의 Metric 데이터를 수집하고 모니터링을 진행하는 것으로 구축하였다.

Elasticsearch

  • 분산 검색 및 분석 엔진
  • 고성능의 분산 시스템으로, 대용량 데이터도 빠르게 처리

Logstash

  • 로그와 이벤트 데이터를 수집, 처리, 변환하는 파이프라인 도구
  • 다양한 입력 플러그인을 통해 여러 소스로부터 데이터를 수집하고, 필터 플러그인을 통해 데이터를 변환 및 정제하며, 출력 플러그인을 통해 데이터를 다양한 목적지로 보낼 수 있음

Kibana

  • Elasticsearch 데이터를 시각화하고 분석하는 데 사용되는 도구
  • 대시보드를 생성하여 데이터를 시각적으로 표현하고, 검색 및 분석 쿼리를 실행 가능

자 제일 좋은 맨땅에 해딩이다. ES 부터 설치법 바로 실행하겠다!

elasticsearch-config.yaml

# elasticsearch-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: elasticsearch-config
data:
  elasticsearch.yml: |
    cluster.name: "my-single-node-cluster"
    node.name: "node-1"
    network.host: "0.0.0.0"
    discovery.type: "single-node"

    # X-Pack 보안 비활성화
    xpack.security.enabled: false

    # HTTP 및 Transport 프로토콜의 SSL 비활성화
    xpack.security.transport.ssl.enabled: false
    xpack.security.http.ssl.enabled: false

일단 Deployment, Service, StatefulSet, DaemonSet, Ingress, ConfigMap등에 대해 공부해보면 참 좋다.

먼저 컨피그맵을 작성해서 엘라스틱서치의 설정파일을 yaml 수준으로 관리한다.

해당 파일을 작성한 후에

kubectl create -f /path/to/elasticsearch-config.yaml

그 다음에 본체인 ES를 띄워주겠다.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: elasticsearch
  labels:
    app: elasticsearch
spec:
  replicas: 1
  selector:
    matchLabels:
      app: elasticsearch
  serviceName: "elasticsearch" 
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      containers:
      - name: elasticsearch
        image: docker.elastic.co/elasticsearch/elasticsearch:8.13.1
        resources:
          requests:
            memory: "2Gi"
            cpu: "1000m"
          limits:
            memory: "4Gi"
            cpu: "2000m"
        ports:
        - containerPort: 9200
          name: http
        - containerPort: 9300
          name: transport
        volumeMounts:
        - name: config
          mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
          subPath: elasticsearch.yml
      volumes:
      - name: config
        configMap:
          name: elasticsearch-config
kubectl create -f /path/to/elasticsearch-statfulset.yaml

elasticsearch를 deployment로 띄우지 않고 statefulset으로 띄우는 이유는 파드의 상태를 모든 노드에서 공유해야하기 떄문 (like DB)와 비슷한 이유 따라서 statefulSet으로 띄우는게 일반적이다.

ES를 8버전을 채택했고, 8버전 부터는 xpack 옵션이 자동활성화 이기 떄문에 configMap에 사용한것처럼 xpack을 해제해줘야한다. 안그러면 SSL/TLS설정의 늪에 빠지게 된다...

이제 서비스를 띄워주면 실제 ElasticSearch에 접근이 가능한데, 다음과 같이 작성하면 된다.

apiVersion: v1
kind: Service
metadata:
  labels:
    app: elasticsearch-svc
  name: elasticsearch-svc
spec:
  type: NodePort
  ports:
  - name: http
    port: 9200
    protocol: TCP
    targetPort: 9200
    nodePort: 30007
  - name: transport
    port: 9300
    protocol: TCP
    targetPort: 9300
    nodePort: 30008
  selector:
    app: elasticsearch

서비스의 종류는 NodePort, ClusterIp, LoadBalancer 이렇게 3개가 있는데

  1. ClusterIp
  • 기본 서비스 유형입니다.
  • 클러스터 내부에서만 접근할 수 있도록 내부 IP 주소를 할당합니다.
  • 외부에서 직접 접근할 수 없습니다.
  1. NodePort
  • 클러스터의 각 노드에서 고정된 포트를 할당하여 외부에서 접근할 수 있게 합니다.
  • 할당된 포트(30000-32767 범위)를 통해 클러스터 외부에서 노드의 IP 주소와 포트를 사용하여 서비스에 접근할 수 있습니다.
  • NodePort 서비스는 ClusterIP 서비스도 자동으로 생성하여 클러스터 내부에서도 접근이 가능합니다.
  1. LoadBalancer
  • 클라우드 서비스 제공자(AWS, GCP, Azure 등)에서 외부 로드 밸런서를 생성하여 외부 트래픽을 클러스터 내부의 서비스로 분산 처리.
  • 외부 IP 주소를 할당받아 인터넷을 통해 접근 가능.

이러한 특징이 있는데 나는 NodePort로 개방을 진행하였다.

kubetctl create -f /path/to/elasticsearch-svc.yaml

이제 클러스터ip:30007로 접속하면 elasticsearch가 뜨는 것을 확인 가능하다.

logstash, kibana모두 동일하게 작업하면 되는데 다른 특징으로는 이 두개는 Deployment로 띄워도 충분히다. 굳이 상태를 공유할 필요가없이 모니터링 툴, 로그수집용이기 떄문에 1개씩만 띄워주도록하겠다.

위에서처럼 각 파일을 나눠서 띄워도되지만 하나의 파일로 작성도 가능하다. 나머지 2개는 하나의 파일로 작성하도록 하겠다

Logstash 설정

apiVersion: v1
kind: ConfigMap
metadata:
  name: logstash-config
data:
  logstash.conf: |
    input {
      beats {
        port => 5044
      }
    }
    filter {
      json {
        source => "message"
      }
      mutate {
        remove_field => ["@version"]
      }
    }
    output {
      elasticsearch {
        hosts => ["http://elasticsearch-svc:9200"]
        manage_template => false
        ssl_certificate_verification => false
        index => "server-metric"
        user => "elastic"
        password => "elasticstack"
      }
    }
  logstash.yml: |
    http.host: "0.0.0.0"
    xpack.monitoring.elasticsearch.hosts: [ "http://elasticsearch-svc:9200" ]
    path.config: /usr/share/logstash/pipeline
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: logstash
  labels:
    app: logstash
spec:
  replicas: 1
  selector:
    matchLabels:
      app: logstash
  template:
    metadata:
      labels:
        app: logstash
    spec:
      containers:
      - name: logstash
        image: docker.elastic.co/logstash/logstash:8.13.1
        resources:
          limits:
            cpu: 500m
            memory: 4Gi
          requests:
            cpu: 300m
            memory: 2Gi
        ports:
        - containerPort: 5044
          name: beats
        volumeMounts:
        - name: logstash-config-volume
          mountPath: /usr/share/logstash/config
        - name: logstash-pipeline-volume
          mountPath: /usr/share/logstash/pipeline
      volumes:
      - name: logstash-config-volume
        configMap:
          name: logstash-config
          items:
            - key: logstash.yml
              path: logstash.yml
      - name: logstash-pipeline-volume
        configMap:
          name: logstash-config
          items:
            - key: logstash.conf
              path: logstash.conf
---
apiVersion: v1
kind: Service
metadata:
  name: logstash
spec:
  type: NodePort
  ports:
    - protocol: TCP
      port: 5044
      targetPort: 5044
      nodePort: 31000
  selector:
    app: logstash

Kibana

apiVersion: v1
kind: ConfigMap
metadata:
  name: kibana-config
data:
  kibana.yml: |
    server.host: "0.0.0.0"
    xpack.security.encryptionKey: "2398d48d8058eae6229f42c8126cb030"
    xpack.encryptedSavedObjects.encryptionKey: "59a98b2b48ae79fbd6ec0064f53e12f5"
    xpack.reporting.encryptionKey: "f84aa37099a3a65b010ab20e6fc4b0df"
---
# 키바나 yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kibana
  labels:
    app: kibana
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kibana
  template:
    metadata:
      labels:
        app: kibana
    spec:
      initContainers:
      - name: copy-config
        image: docker.elastic.co/kibana/kibana:8.13.1
        command: ['sh', '-c', 'cp /tmp/kibana.yml /usr/share/kibana/config/kibana.yml && chmod 0660 /usr/share/kibana/config/kibana.yml && chown 1000:1000 /usr/share/kibana/config/kibana.yml']
        volumeMounts:
        - name: kibana-config
          mountPath: /tmp/kibana.yml
          subPath: kibana.yml
        - name: kibana-config-dir
          mountPath: /usr/share/kibana/config
      containers:
      - name: kibana
        image: docker.elastic.co/kibana/kibana:8.13.1
        ports:
        - containerPort: 5601
        env:
        - name: SERVER_HOST
          value: "0.0.0.0"  
        - name: ELASTICSEARCH_HOSTS
          value: "http://10.0.3.254:30007"
        volumeMounts:
        - name: kibana-config
          mountPath: /usr/share/kibana/config/kibana.yml
          subPath: kibana.yml
      volumes:
      - name: kibana-config
        configMap:
          name: kibana-config
      - name: kibana-config-dir
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: kibana
  labels:
    app: kibana
spec:
  type: NodePort  # NodePort를 사용하여 외부에서 접근 가능하게 설정
  ports:
  - name: kibana
    nodePort: 30000
    port: 5601
    protocol: TCP
    targetPort: 5601
  selector:
    app: kibana

Elasticsearch랑 다른점은 서비스 명이 elasticsearch만 -svc를 붙였다 이거는 다른 서비스에서 엘라스틱서치를 바라볼때 같은 클러스터 내부에 띄우는거기때문에 IP로 접근하하고 저렇게 서비스명으로 접근가능 한것을 보여주기 위해서 따로 svc 키워드를 붙였고, 보통은 deploy랑 이름을 맞춰서 띄운다 나의 경우는

이렇게 다 설치해보고 Elasticsearch도 들어가보고 kibana도 들어가보고 logstash도 들어가보고
하지만 logstash는 안들어가질것이다. 나도 들어가질줄 알았는데 안들어가지더라,,ㅋㅋㅋㅋㅋ 그냥 실제 서버에서 메트릭데이터를 쏠때만 쓰면 된다.

현재나는 클러스터에 elasticsearch랑 kibana를 띄운것이도 실제 메트릭데이터는 단순히 Linux 서버의 메트릭데이터를 쿠버네티스 클러스터로 전송하려고한다.

따라서 elasticsearch의 플러그인인 metricbeat를 각 리눅스에 설치하고 로그스테이시로 전송하면 된다.

쿠버네티스 설정은 끝이났고 로그를 쏠 리눅스에 접속한뒤 다음 명령어로 입력해준다.

curl -L -O https://artifacts.elastic.co/downloads/beats/metricbeat/metricbeat-8.13.1-amd64.deb
sudo dpkg -i metricbeat-8.13.1-amd64.deb

sudo vi /etc/metric/metric.yml

# 편집기에서 해당 부분을 수정해준다.
# 해당 부분 수정하기 전에 elasticsearch 관련 설정은 주석처리를 해준다.
output.logstash:
  # The Logstash hosts
  hosts: ["control plane의 IP:31000"]

processors:
  - add_host_metadata: ~
  - add_cloud_metadata: ~
  - add_docker_metadata: ~
  - add_kubernetes_metadata: ~

fields:
  server_name: "서버이름 (나는 IP로 했음)"
fields_under_root: true
sudo metricbeat modules enable logstash

sudo service metricbeat start

 

### 구성도

이런 구조로 구축했다. 이때 나의 경우는 그냥 Ubuntu가 깔린 곳이랑 클러스터가 깔린 곳의 네트워크는 분리되어있어서 logstash를 둘다 드나들수 있도록 설정해주었다.

다 끝이나면 메트릭데이터로 키바나 대시보드를 커스텀하면 된다!

아래는 내가 커스텀한건데 조금 더 해야한다,,

 

### 대시보드 커스텀화

반응형

'쿠버네티스' 카테고리의 다른 글

쿠버네티스 구축하기 Ubuntu 22.04 & K8S 1.29  (0) 2024.07.16
쿠버네티스 이해하기  (0) 2024.07.16