본문 바로가기
Kubernetes

Kubernetes Workload Resources(Daemonset)

by journalctl 2023. 12. 3.
쿠버네티스의 대표적인 워크로드 리소스인 Daemonset(데몬셋)을 살펴보는 섹션입니다 :)

Daemonset - 데몬셋

 
먼저 쿠버네티스의 공식문서를 통해서 Daemonset의 정의를 살펴보겠습니다.
"데몬셋 은 모든(또는 일부) 노드가 파드의 사본을 실행하도록 한다. 노드가 클러스터에 추가되면 파드도 추가된다. 노드가 클러스터에서 제거되면 해당 파드는 가비지(garbage)로 수집된다. 데몬셋을 삭제하면 데몬셋이 생성한 파드들이 정리된다."
 
해당 내용을 살펴보면, 디플로이먼트(Deployment)와 스테이트풀셋(Statefulset)과 달리 노드별로 하나씩 동일한 파드를 구성하게 해주는 워크로드 리소스로 해석됩니다.
데몬셋(Daemonset)은 노드별로 하나의 파드가 배치되기 때문에 replicas를 설정하는 부분이 없으며, 만약 특정 노드가 삭제된다면 배포된 Pod가 다른 노드로 이동하는 것이 아닌 가비지(Garbage)로 수집됩니다.
 

데몬셋 사용

쿠버네티스 공식 문서에 따르면 일부 대표적인 용도로 다음과 같습니다.

  • 모든 노드에서 클러스터 스토리지 데몬 실행
  • 모든 노드에서 로그 수집 데몬 실행
  • 모든 노드에서 노드 모니터링 데몬 실행

데몬셋(Daemonset)은 주로 노드의 리소스 모니터링 어플리케이션, 로그 수집을 위한 어플리케이션 배포에 사용됩니다.
 

데몬셋 생성하기

쿠버네티스 공식 문서를 참고하여 yaml 파일을 생성합니다.
(https://kubernetes.io/ko/docs/concepts/workloads/controllers/daemonset/)

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: journalctl
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      # 이 톨러레이션(toleration)은 데몬셋이 컨트롤 플레인 노드에서 실행될 수 있도록 만든다.
      # 컨트롤 플레인 노드가 이 파드를 실행해서는 안 되는 경우, 이 톨러레이션을 제거한다.
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log

 

  • kind : DaemonSet 으로 설정해주세요 ! (대소문자 주의)
  • spec.template : Deployment, Statefulset과 마찬가지로 배포할 파드에 대해서 정의하는 부분입니다.
  • spec.template.spec.tolerations : 만약 특정 조건을 가진 노드에 DaemonSet Pod를 배포하고 싶을때 사용하는 부분입니다.
  • spec.template.spec.nodeSelector : 만약 특정 레이블을 가진 노드에 배포하고 싶을때 사용하는 항목입니다. 해당 yaml 설정에는 없지만 해당 위치에 추가하여 Node Label의 Key-Value에 맞춰서 선언하면 됩니다 !

spec.tolerations을 살펴보면 컨트롤 플레인(Control Plane) 노드에서 해당 파드를 실행하고 싶지 않을 경우 제거한다고 써져있습니다.
( 필자는 Control Plane(Master) 노드에서 실행하기를 원치 않기 때문에 해당 부분은 삭제하였습니다 ! )
metadata.namespace가 기본적으로 kube-system으로 설정되어 있는데 필자는 journalctl 네임스페이스에 배포하기 위해서 위와 같이 설정하였습니다 !
 

데몬셋 배포하기

$ kubectl apply -f daemonset.yaml -n journalctl
daemonset.apps/fluentd-elasticsearch created

 

데몬셋 상태 확인하기

$ kubectl get pod -n journalctl
NAME                          READY   STATUS    RESTARTS   AGE
fluentd-elasticsearch-2x7g9   1/1     Running   0          5m33s
fluentd-elasticsearch-h9fw4   1/1     Running   0          5m33s
fluentd-elasticsearch-mck94   1/1     Running   0          5m33s

$ kubectl get ds -n journalctl
NAME                    DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
fluentd-elasticsearch   3         3         3       3            3           <none>          5m39s

$ kubectl describr ds/fluentd-elasticsearch -n journalctl
Name:           fluentd-elasticsearch
Selector:       name=fluentd-elasticsearch
Node-Selector:  <none>
Labels:         k8s-app=fluentd-logging
Annotations:    deprecated.daemonset.template.generation: 1
Desired Number of Nodes Scheduled: 3
Current Number of Nodes Scheduled: 3
Number of Nodes Scheduled with Up-to-date Pods: 3
Number of Nodes Scheduled with Available Pods: 3
Number of Nodes Misscheduled: 0
Pods Status:  3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  name=fluentd-elasticsearch
  Containers:
   fluentd-elasticsearch:
    Image:      quay.io/fluentd_elasticsearch/fluentd:v2.5.2
    Port:       <none>
    Host Port:  <none>
    Limits:
      memory:  200Mi
    Requests:
      cpu:        100m
      memory:     200Mi
    Environment:  <none>
    Mounts:
      /var/log from varlog (rw)
  Volumes:
   varlog:
    Type:          HostPath (bare host directory volume)
    Path:          /var/log
    HostPathType:  
Events:
  Type    Reason            Age    From                  Message
  ----    ------            ----   ----                  -------
  Normal  SuccessfulCreate  5m51s  daemonset-controller  Created pod: fluentd-elasticsearch-mck94
  Normal  SuccessfulCreate  5m51s  daemonset-controller  Created pod: fluentd-elasticsearch-h9fw4
  Normal  SuccessfulCreate  5m51s  daemonset-controller  Created pod: fluentd-elasticsearch-2x7g9

 
배포된 Pod 명을 확인해보면 <daemonset-name>-<random-value> 값으로 설정됩니다. Deployment와 동일하게 네이밍 규칙을 가지는 것으로 확인되며 Deployment도 Pod를 배포할때 "deployment-coontroller"를 통해서 배포한다면 Daemonset은 "damonset-controller"를 통해서 배포되는것을 확인할 수 있습니다.
 
Daemonset의 특징으로 각 노드에 Pod가 배포된다고 언급하였습니다. 해당 내용을 확인하기 위해서 먼저 Node를 확인하고, 각 Pod가 Node별로 배포되었는지 확인해보겠습니다.
 

노드 확인하기

$ kubectl get nodes
NAME                                  STATUS   ROLES    AGE   VERSION
190.ap-northeast-2.compute.internal   Ready    <none>   12d   v1.26.10-eks-e71965b
112.ap-northeast-2.compute.internal   Ready    <none>   12d   v1.26.10-eks-e71965b
177.ap-northeast-2.compute.internal   Ready    <none>   12d   v1.26.10-eks-e71965b

 
현재 구성되어 있는 Worker Node는 총 3대로 구성되어 있습니다.

  • 112.ap-northeast-2.compute.internal
  • 190.ap-northeast-2.compute.internal
  • 177.ap-northeast-2.compute.internal

각 노드별로 Pod에 배포되었는지 확인하기 위해서 wide 옵션을 추가하여 확인해보겠습니다.
 

데몬셋 상태 확인하기

$ kubectl get pod -n journalctl -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP              NODE                                  NOMINATED NODE   READINESS GATES
fluentd-elasticsearch-2x7g9   1/1     Running   0          17m   192.168.3.35    177.ap-northeast-2.compute.internal   <none>           <none>
fluentd-elasticsearch-h9fw4   1/1     Running   0          17m   192.168.1.107   190.ap-northeast-2.compute.internal   <none>           <none>
fluentd-elasticsearch-mck94   1/1     Running   0          17m   192.168.2.85    112.ap-northeast-2.compute.internal   <none>           <none>

 
NODE 필드를 확인해보면 앞서 확인했던 Worker Node 별로 Pod 1개씩 배포되었음을 확인할 수 있습니다 !
 
다음으로 특정 노드에만 배포하도록 설정할 수 있는 방법 중 Node Label을 설정하여 배포해보겠습니다.
 

노드 레이블 설정하기

먼저 Node에 설정되어 있는 Label를 확인하는 명령어를 살펴보겠습니다. 노드 확인하기 섹션에서 사용한 명령어에서 "--show-labels" 옵션을 추가하면 Node에 설정되어 있는 Label을 확인할 수 있습니다.

$ kubectl get nodes --show-labels
NAME                                  STATUS   ROLES    AGE   VERSION                LABELS
190.ap-northeast-2.compute.internal   Ready    <none>   12d   v1.26.10-eks-e71965b   kubernetes.io/arch=amd64,kubernetes.io/hostname=190.ap-northeast-2.compute.internal,kubernetes.io/os=linux
112.ap-northeast-2.compute.internal   Ready    <none>   12d   v1.26.10-eks-e71965b   kubernetes.io/arch=amd64,kubernetes.io/hostname=112.ap-northeast-2.compute.internal,kubernetes.io/os=linux
177.ap-northeast-2.compute.internal   Ready    <none>   12d   v1.26.10-eks-e71965b   kubernetes.io/arch=amd64,kubernetes.io/hostname=177.ap-northeast-2.compute.internal,kubernetes.io/os=linux

 
다음으로 Node에 Label을 설정하겠습니다.
"kubectl label nodes <your-node-name> <Label-Key>=<Label-Value>" 명령어를 사용하여 설정하겠습니다.
( 데몬셋 실습을 위해서 2개의 노드에 대해서만 설정하겠습니다. )

$ kubectl label nodes 190.ap-northeast-2.compute.internal ns=journalctl
node/190.ap-northeast-2.compute.internal labeled

$ kubectl label nodes 112.ap-northeast-2.compute.internal ns=journalctl
node/112.ap-northeast-2.compute.internal labeled

$ kubectl get nodes --show-labels
NAME                                  STATUS   ROLES    AGE   VERSION                LABELS
190.ap-northeast-2.compute.internal   Ready    <none>   12d   v1.26.10-eks-e71965b   kubernetes.io/arch=amd64,kubernetes.io/hostname=190.ap-northeast-2.compute.internal,kubernetes.io/os=linux, ns=journalctl
112.ap-northeast-2.compute.internal   Ready    <none>   12d   v1.26.10-eks-e71965b   kubernetes.io/arch=amd64,kubernetes.io/hostname=112.ap-northeast-2.compute.internal,kubernetes.io/os=linux, ns=journalctl
177.ap-northeast-2.compute.internal   Ready    <none>   12d   v1.26.10-eks-e71965b   kubernetes.io/arch=amd64,kubernetes.io/hostname=177.ap-northeast-2.compute.internal,kubernetes.io/os=linux

 

데몬셋 생성하기 (NodeSelector)

앞서 데몬셋 생성하기에서 사용한 yaml 파일에서 spec.template.spec.nodeSelector를 추가하여 생성해보겠습니다.

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: journalctl
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      nodeSelector:
        ns: journalctl
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log

 
앞서 Node에 지정한 Label의 Key-Value로 nodeSelector에 설정해주었습니다. 다시 배포를 진행합니다.

$ kubectl apply -f daemonset.yaml -n journalctl
daemonset.apps/fluentd-elasticsearch configured

 

데몬셋 상태 확인하기 (NodeSelector)

앞서 확인했던 명렁어를 사용하여 상태를 확인해보겠습니다.

$ kubectl get pod -n journalctl -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP              NODE                                  NOMINATED NODE   READINESS GATES
fluentd-elasticsearch-cktn5   1/1     Running   0          55s   192.168.2.93    112.ap-northeast-2.compute.internal   <none>           <none>
fluentd-elasticsearch-k7tlp   1/1     Running   0          52s   192.168.1.114   190.ap-northeast-2.compute.internal   <none>           <none>

$ kubectl get ds -n journalctl
NAME                    DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
fluentd-elasticsearch   2         2         2       2            2           ns=journalctl   37m

$ kubectl describe ds/fluentd-elasticsearch -n journalctl
Name:           fluentd-elasticsearch
Selector:       name=fluentd-elasticsearch
Node-Selector:  ns=journalctl
Labels:         k8s-app=fluentd-logging
Annotations:    deprecated.daemonset.template.generation: 2
Desired Number of Nodes Scheduled: 2
Current Number of Nodes Scheduled: 2
Number of Nodes Scheduled with Up-to-date Pods: 2
Number of Nodes Scheduled with Available Pods: 2
Number of Nodes Misscheduled: 0
Pods Status:  2 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  name=fluentd-elasticsearch
  Containers:
   fluentd-elasticsearch:
    Image:      quay.io/fluentd_elasticsearch/fluentd:v2.5.2
    Port:       <none>
    Host Port:  <none>
    Limits:
      memory:  200Mi
    Requests:
      cpu:        100m
      memory:     200Mi
    Environment:  <none>
    Mounts:
      /var/log from varlog (rw)
  Volumes:
   varlog:
    Type:          HostPath (bare host directory volume)
    Path:          /var/log
    HostPathType:  
Events:
  Type    Reason            Age   From                  Message
  ----    ------            ----  ----                  -------
  Normal  SuccessfulCreate  38m   daemonset-controller  Created pod: fluentd-elasticsearch-mck94
  Normal  SuccessfulCreate  38m   daemonset-controller  Created pod: fluentd-elasticsearch-h9fw4
  Normal  SuccessfulCreate  38m   daemonset-controller  Created pod: fluentd-elasticsearch-2x7g9
  Normal  SuccessfulDelete  77s   daemonset-controller  Deleted pod: fluentd-elasticsearch-2x7g9
  Normal  SuccessfulDelete  75s   daemonset-controller  Deleted pod: fluentd-elasticsearch-mck94
  Normal  SuccessfulCreate  73s   daemonset-controller  Created pod: fluentd-elasticsearch-cktn5
  Normal  SuccessfulDelete  72s   daemonset-controller  Deleted pod: fluentd-elasticsearch-h9fw4
  Normal  SuccessfulCreate  69s   daemonset-controller  Created pod: fluentd-elasticsearch-k7tlp

 
먼저 배포된 Pod를 살펴보면 앞서 설정했던 2개의 노드에 대해서만 배포가 수행되었습니다.
Daemonset을 살펴보면 "NODE SELECTOR" 부분에 yaml 파일로 설정하였던 spec.template.spec.nodeSelector 값이 설정되어 있는것을 확인할 수 있습니다.
Daemonset의 "Events"를 살펴보면 앞서 배포되었던 3개의 파드는 모두 삭제되고 새로운 2개의 파드가 재배포 되었음을 확인할 수 있습니다.


다음 섹션은 REST 오브젝트인 Service에 대해서 살펴보겠습니다 :)