본문 바로가기

DevOps/쿠버네티스

Elasticsearch와 Kibana, filebeat 를 활용한 쿠버네티스 로깅 아키텍쳐


Elasticsearch와 Kibana 그리고 filebeat를 활용하면 간단하고 효과적으로 쿠버네티스의 log를 수집하고 조회할 수 있다.


구성

  1. Log를 수집하여 데이터를 저장 및 조회하는 Elasticsearch pod
  2. 쿠버네티스의 각 node에서 daemonset으로 띄워져 log를 수집하여 elasticsearch로 전송하는 Filebeat pod
  3. 수집한 log를 visualize하여 확인할 Kibana pod

그림. Elasticsearch와 Kibana, filebeat를 사용한 kubernetes logging 아키텍쳐


elasticsearch.yaml

# 엘라스틱서치 image를 가져와서 pod으로 띄웁니다.
PVC를 사용하는 경우PVC를 사용하지 않는 경우로 사용할 수 있습니다.

1) PVC를 사용하지 않고 POD 자체를 저장소로 사용하는 경우(Temporary 사용 가능, pod이 사라지면 data 유실)
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  namespace: devops-tool
  labels:
    app: elasticsearch
spec:
  replicas: 1
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch
  spec:
  containers:
  - name: elasticsearch
    image: elasticsearch:latest
    ports:
    - containerPort: 9200
    imagePullPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: elasticsearch
spec:
  ports:
  - port: 9200
    targetPort: 9200
    protocol: TCP
    name: http
    nodePort: 30560
  selector:
    app: elasticsearch
  type: LoadBalancer

2) PVC를 사용하여 데이터가 유실되지 않게 elasticsearch pod을 띄우는 경우
 - 쿠버네티스 PV 및 PVC 설정은 Persistent Volumes 공식홈페이지 가이드 문서(바로가기)를 참고
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: elasticsearch
  namespace: devops-tool
  labels:
    app: elasticsearch
spec:
  replicas: 1
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      containers:
      - name: elasticsearch
        image: elasticsearch:latest
        ports:
        - containerPort: 9200
        imagePullPolicy: Always
        volumeMounts:
        - mountPath: /usr/share/elasticsearch/data
          name: elasticsearchdata
      volumes:
      - name: elasticsearchdata
        persistentVolumeClaim:
          claimName: elasrch-pv-claim
---
apiVersion: v1
kind: Service
metadata:
  namespace: devops-tool
  name: elasticsearch
spec:
  ports:
    - port: 9200
      targetPort: 9200
      protocol: TCP
      name: http
      nodePort: 30560
  selector:
    app: elasticsearch
  type: LoadBalancer
---

filebeat.yaml
# filebeat를 daemonset으로 deploy하여 log를 수집하여 elasticsearch로 전송.
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: filebeat-config
  namespace: kube-system
  labels:
    k8s-app: filebeat
data:
  filebeat.yml: |-
    filebeat.config:
      inputs:
        # Mounted `filebeat-inputs` configmap:
        path: ${path.config}/inputs.d/*.yml
        # Reload inputs configs as they change:
        reload.enabled: false
      modules:
        path: ${path.config}/modules.d/*.yml
        # Reload module configs as they change:
        reload.enabled: false
 
    # To enable hints based autodiscover, remove `filebeat.config.inputs` configuration and uncomment this:
    #filebeat.autodiscover:
    #  providers:
    #    - type: kubernetes
    #      hints.enabled: true
 
    processors:
      - add_cloud_metadata:
 
    cloud.id: ${ELASTIC_CLOUD_ID}
    cloud.auth: ${ELASTIC_CLOUD_AUTH}
 
    output.elasticsearch:
      hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
      username: ${ELASTICSEARCH_USERNAME}
      password: ${ELASTICSEARCH_PASSWORD}
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: filebeat-inputs
  namespace: kube-system
  labels:
    k8s-app: filebeat
data:
  kubernetes.yml: |-
    - type: docker
      containers.ids:
      - "*"
      processors:
        - add_kubernetes_metadata:
            in_cluster: true
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: filebeat
  namespace: kube-system
  labels:
    k8s-app: filebeat
spec:
  template:
    metadata:
      labels:
        k8s-app: filebeat
    spec:
      serviceAccountName: filebeat
      terminationGracePeriodSeconds: 30
      containers:
      - name: filebeat
        image: docker.elastic.co/beats/filebeat:7.0.0-alpha1
        args: [
          "-c", "/etc/filebeat.yml",
          "-e",
        ]
        env:
        - name: ELASTICSEARCH_HOST
          value: 엘라스틱서치호스트          #example) 172.28.123.32
        - name: ELASTICSEARCH_PORT
          value: "30560"
        - name: ELASTICSEARCH_USERNAME
          value: elastic
        - name: ELASTICSEARCH_PASSWORD
          value: changeme
        - name: ELASTIC_CLOUD_ID
          value:
        - name: ELASTIC_CLOUD_AUTH
          value:
        securityContext:
          runAsUser: 0
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 100Mi
        volumeMounts:
        - name: config
          mountPath: /etc/filebeat.yml
          readOnly: true
          subPath: filebeat.yml
        - name: inputs
          mountPath: /usr/share/filebeat/inputs.d
          readOnly: true
        - name: data
          mountPath: /usr/share/filebeat/data
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      volumes:
      - name: config
        configMap:
          defaultMode: 0600
          name: filebeat-config
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
      - name: inputs
        configMap:
          defaultMode: 0600
          name: filebeat-inputs
      # data folder stores a registry of read status for all files, so we don't send everything again on a Filebeat pod restart
      - name: data
        hostPath:
          path: /var/lib/filebeat-data
          type: DirectoryOrCreate
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: filebeat
subjects:
- kind: ServiceAccount
  name: filebeat
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: filebeat
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: filebeat
  labels:
    k8s-app: filebeat
rules:
- apiGroups: [""] # "" indicates the core API group
  resources:
  - namespaces
  - pods
  verbs:
  - get
  - watch
  - list
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: filebeat
  namespace: kube-system
  labels:
    k8s-app: filebeat
---

kibana.yaml
# elasticsearch의 데이터를 kibana에서 시각화, 검색 가능.
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kibana
  namespace: devops-tool
  labels:
    app: kibana
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kibana
  template:
    metadata:
      labels:
         app: kibana
  spec:
    containers:
    - name: kibana
      image: kibana:latest
      resources:
        limits:
          cpu: 1000m
        requests:
          cpu: 100m
      env:
      - name: ELASTICSEARCH_URL
        value: https://엘라스틱서치 호스트:30560
      - name: SERVER_BASEPATH
        value: /api/v1/namespaces/kube-system/services/kibana-logging/proxy
      ports:
      - containerPort: 5601
---
apiVersion: v1
kind: Service
metadata:
  name: kibana
spec:
  ports:
  - port: 5601
    targetPort: 5601
    protocol: TCP
    name: http
    nodePort: 30561
  selector:
    app: kibana
  type: LoadBalancer
---

결과물
# kibana url로 접속하면 로그 조회 가능

스크린샷. 키바나에서 로그 조회.



# filebeat로 부터 수집된 log metric들은 아래와 같음. metric별로 검색 및 조회, visualize가 가능.

  • _id
  • _index
  • _type
  • source
  • stream
  • message 
  • kubernetes.namespace
  • kubernetes.container.name
  • kubernetes.pod.name
  • kubernetes.node.name
  • kubernetes.labels.app
  • kubernetes.labels.cluster
  • kubernetes.labels.controller-revision-hash
  • kubernetes.labels.k8s-app
  • kubernetes.labels.pod-template-generation
  • kubernetes.labels.pod-template-hash
  • host.name
  • beat.name
  • beat.version
  • beat.hostname
  • input.type
  • prospector.type

결론 및 의견

  • 작은 규모의 쿠버네티스 환경에서 agile하게 구축할 수 있음.
  • 간단하고 작은 pod으로 이루어져 있어 관리가 쉬움.
  • elasticsearch와 kibana기반지식이 있다면 더욱 효과적으로 사용가능.

  • 대규모의 쿠버네티스 환경에서는 logging architecture을 위해서 추가적인 요소들이 필요함
    - kibana pod 혹은 elasticsearch pod이 속해 있는 쿠버네티스가 down 되었을 때 HA구성?
    - 과도한 로깅 데이터로 인해 elasticsearch의 과부하 대응방안?
    - etc...

참고문헌 및 사이트