DaemonSet

개요

A DaemonSet defines Pods that provide node-local facilities. These might be fundamental to the operation of your cluster, such as a networking helper tool, or be part of an add-on.[1]

데몬셋은 노드와 관련된 기능을 담당하는 파드를 정의한다.
애드온, 혹은 네트워킹 툴 등 클러스터를 운영하는데 필요한 기능들을 위해 쓰인다.

데몬셋은 모든 노드에 파드가 돌아가는 것을 보장하는 워크로드이다.
만약 새로운 노드가 추가된다면 데몬셋은 알아서 그 노드에 자신의 파드를 추가한다.
노드가 지워진다면 당연히 그쪽에 배치된 파드 역시 정리되도록 한다.

기능

데몬셋은 스토리지, 로그 수집, 모니터링 등각 노드와 관련된 기능을 하는 파드가 있을 때 사용한다.
그래서 데몬셋에 사용될 만한 파드는 대체로 다음과 같은 특징을 가진다.


kube-system 네임스페이스에서 돌아가는 데몬셋들은 보면, CalicoCSI 플러그인들이 데몬셋으로 설정된 것을 볼 수 있다.
이렇듯 노드를 운영하기 위해서 기본적으로 세팅해야 하는 것들에 대해서 흔히 사용된다.
한편으로, 클러스터 운영 관점에서 필요한 것들이다보니 대체로 만들어진 툴을 사용하는 실무자들은 많이 만질 일은 없는 오브젝트라고 봐도 될 것 같긴 하다.

기본적으로는 모든 노드에 같은 양식으로 만들어지지만 조금 더 복잡하게 세팅하여 사용하는 게 가능하다.
가령 하드웨어 타입에 따라 다른 정도의 리소스를 둔다던가, 그래도 특정 노드에만 배치한다던가.

동작 원리

데몬셋의 핵심은 파드가 모든 노드에 각각 스케줄링되도록 하는 것이다.

이때 데몬셋은 모든 파드에 각각 노드 Affinity를 부여하여 각 노드에 스케줄링되도록 만든다.
스케줄러는 이후에 nodeName 필드에 각각 타겟 노드를 기입하여 결과적으로 모든 노드에 파드가 배치된다.
관리자가 직접 스펙에 어피니티를 작성할 수도 있다.
이 경우 데몬셋 컨트롤러는 이를 고려하여 적격한 노드를 먼저 찾고, 이후에 파드를 생성하여 해당 파드에 각 노드에 해당하는 어피니티를 부여해준다.

참고로 그냥 파드 스펙에 nodeName을 쓰거나 하는 것도 다 가능하다.
그러면 당연히 하나의 파드만 하나의 노드에 실행될 것이다.

톨러레이션 부여

기본적으로 데몬셋은 다음의 테인트, 톨러레이션을 파드에 부여해준다.
다음의 테인트 키들은 앞에 node.kubernetes.io/가 붙어 있는데 내가 가독성을 위해 뺀 것이다.
또, 이것들은 기본적으로 설정돼있는 테인트 키들이라 대충 알아두면 좋다.

필요성(대안 비교)

이 친구는 아무래도 당장 떠올릴 수 있는 대안이 많은데, 다른 놈들과 비교해보면서 왜 데몬셋이 좋은지 가늠해보자.

초기화 스크립트

그냥 처음에 노드 세팅할 때 그냥 필요한 설정들을 스크립트로 짜서 관리하면 안 되긋나?
이에 대해 데몬셋은 다음의 이점을 가진다.

기본 파드

그냥 직접 파드를 만들어서 하면 안 되냐?
그럴 거면 워크로드는 왜 쓰냐? 넘어간다.

정적 파드

정적 파드는 노드에 양식을 작성해두면 kubelet이 직접 실행해주니 확실히 대안이 될 만하다.
또한 이 놈은 양식을 바꾸면 알아서 kubelet이 재실행까지 해주니 좋은 선택지가 될 수는 있다.
다만 이놈은 kubectl로 다룰 수도 없고 각 노드에 직접 접근해서 건드려줘야 하는 불편함이 있다.
또한, 정적 파드는 미래에 제거될 수도 있는 방식이다(이 이야기 파드 문서에선 없었는데..?)

디플로이먼트

이것도 충분히 가능한 선택지다.
그러나 목적이 조금 다르달까, 디플로이먼트는 개수를 유지하고 버전을 관리해야 하는 stateless한 어플리케이션에 어울린다.
노드 레벨에서 돌아가야만 하는 프로세스에 대해서 디플로이먼트는 불안한 측면이 없잖아 있다.
물론 스펙을 잘 작성해서 모든 노드에 실행되게 할 수는 있겠지만, 엄청 귀찮은 일이 될 것이다.

양식 작성법

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      - 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
      priorityClassName: important
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log

이게 문서의 예시로, 테인트, 톨러레이션 세팅을 통해 컨트롤 플레인에도 생성되도록 허용했다.
다른 워크로드 양식과 크게 다를 건 없는 것이 보인다.
예시에서 몇 가지 짚자면, 일단 원래는 kube-system 네임스페이스에 만들어지도록 되어있었는데 굳이? 싶어서 내가 옮겼다.
대체로 노드 관련 운영 작업을 수행해야 하니 가급적 우선순위를 높이 설정하라고 충고하고 있다.

그래도 몇 가지 차이가 있는 것들을 짚고자 한다.

replica

데몬셋은 레플리카가 없다.
각 노드에 하나만 배치되는 것을 기본으로 하기 때문에 그렇다.

selector

다른 워크로드의 라벨 셀렉터는 보통 변화를 줄 수 있지만, 데몬셋은 엄격하게 금지된다.
이것은 의도하지 않은 고아 파드를 만들어낼 가능성이 있기 때문이다.

updateStrategy

이놈도 업데이트는 가능하다!
방식은 스테이트풀셋 업데이트 전략과 동일하다.

데몬셋 파드의 양식을 업데이트할 순 있지만 지양하는 게 좋다.
문서에는 정확히 안 나오나.. 어떤 필드는 바꾸더라도 기존 양식에 있던 값을 그대로 쓴다고 하는데 내가 제대로 해석한 건지 모르겠다.

기타

데몬셋으로서 고려할 만한 여러 요소들을 살펴보자.

통신

데몬 파드들에 통신하는 방법들은 이런 방법들이 있다.

노드 라벨 업데이트

기본적으로 데몬셋은 항상 노드들을 체크하기에, 노드 라벨에 변경이 생기면 이를 추적해서 파드를 추가하거나 제거할 노드를 찾아낸다.

관련 문서

이름 noteType created
T- 데몬셋은 드레인된 노드에도 파드를 배치하나 topic/temp 2024-12-27

참고


  1. https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/ ↩︎