Notice
Recent Posts
Recent Comments
Link
«   2025/12   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Archives
Today
Total
관리 메뉴

근묵자흑

Kubernetest Pattern: DaemonService 본문

k8s/kubernetes-pattern

Kubernetest Pattern: DaemonService

Luuuuu 2025. 9. 20. 19:35

쿠버네티스를 운영하다 보면 모든 노드에서 특정 작업을 수행해야 하는 경우가 있습니다. 로그 수집, 모니터링 에이전트, 네트워크 플러그인 등이 대표적인 예시입니다. 이런 요구사항을 해결하기 위해 쿠버네티스는 DaemonSet이라는 리소스를 제공합니다.

 

데몬서비스 패턴은 쿠버네티스 클러스터의 모든 노드 또는 특정 노드에서 단일 Pod를 실행하도록 보장하는 패턴입니다. 이는 운영체제의 데몬 프로세스와 유사한 개념으로, 인프라 관련 작업을 수행하는 Pod를 배치하고 관리하는 데 주로 사용됩니다.

데몬(Daemon)의 개념

  • 운영체제 수준: httpd, named, sshd 등 백그라운드에서 장시간 실행되는 자가 복구 프로그램
  • 애플리케이션 수준: JVM의 데몬 스레드처럼 가비지 컬렉션, 파이널라이제이션 등의 작업 수행
  • 쿠버네티스 수준: DaemonSet을 통해 클러스터 전체에 분산된 백그라운드 기능 제공

왜 DaemonSet이 필요한가?

전통적인 방식들의 한계:

  • Static Pods: Kubelet에 의해서만 관리되며 Kubernetes API로 관리 불가
  • Bare Pods: 노드 장애 시 재시작되지 않음
  • Init Scripts (systemd, upstartd): 서로 다른 도구체인 필요, Kubernetes 도구와 통합 불가

DaemonSet

DaemonSet은 ReplicaSet과 유사하지만, 사용자 부하가 아닌 노드 수에 따라 Pod 인스턴스를 실행합니다.

DaemonSet은 클러스터의 모든(또는 특정) 노드에서 Pod의 복사본을 실행하도록 보장하는 워크로드 리소스입니다. 새로운 노드가 클러스터에 추가되면 자동으로 Pod가 생성되고, 노드가 제거되면 해당 Pod도 함께 정리됩니다.

ReplicaSet vs DaemonSet

ReplicaSet: "3개의 Pod를 실행해주세요" → 어느 노드든 상관없음
DaemonSet: "모든 노드에 1개씩 Pod를 실행해주세요" → 노드 기반 배포

DaemonSet 배포 테스트

Test 1: 기본 DaemonSet 배포

가장 기본적인 로깅 에이전트 DaemonSet을 배포하여 동작을 확인했습니다.

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: logging-agent
spec:
  selector:
    matchLabels:
      name: logging-agent
  template:
    spec:
      tolerations:
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
      containers:
      - name: logging-agent
        image: busybox:1.36
        command: ["/bin/sh", "-c"]
        args:
        - |
          echo "Logging agent started on node $NODE_NAME"
          while true; do
            echo "[$(date)] Collecting logs from node: $NODE_NAME"
            sleep 30
          done

테스트 결과:

$ kubectl apply -f basic-daemonset.yaml
daemonset.apps/logging-agent created

$ kubectl get ds logging-agent
NAME            DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE
logging-agent   1         1         1       1            1

$ kubectl logs logging-agent-fkn7s --tail=3
[Sat Sep 20 10:12:24 UTC 2025] Collecting logs from node: minikube
[Sat Sep 20 10:12:24 UTC 2025] CPU Usage: cpu  3716 0 1607 49650 2104
[Sat Sep 20 10:12:24 UTC 2025] Memory Info: MemTotal: 8025424 kB

Control Plane 노드에서도 실행되도록 Toleration 설정이 중요합니다.

Toleration 설정 가이드

왜 Toleration이 필요한가?
기본적으로 Control Plane 노드는 Taint가 설정되어 있어 일반 Pod가 스케줄링되지 않습니다. DaemonSet이 모든 노드에서 실행되려면 이 Taint를 무시할 수 있는 Toleration이 필요합니다.

주요 Toleration 설정들:

tolerations:
# 1. Control Plane 노드 (Kubernetes 1.24+)
- key: node-role.kubernetes.io/control-plane
  operator: Exists
  effect: NoSchedule

# 2. Master 노드 (이전 버전 호환성)
- key: node-role.kubernetes.io/master
  operator: Exists
  effect: NoSchedule

# 3. 노드가 준비되지 않은 상태 허용
- key: node.kubernetes.io/not-ready
  operator: Exists
  effect: NoExecute
  tolerationSeconds: 300  # 5분 대기 후 eviction

# 4. 노드가 도달 불가능한 상태 허용
- key: node.kubernetes.io/unreachable
  operator: Exists
  effect: NoExecute
  tolerationSeconds: 300

# 5. 디스크 압력이 있는 노드에서도 실행 (신중히 사용)
- key: node.kubernetes.io/disk-pressure
  operator: Exists
  effect: NoSchedule

# 6. 메모리 압력이 있는 노드 (모니터링 에이전트에 유용)
- key: node.kubernetes.io/memory-pressure
  operator: Exists
  effect: NoSchedule

Operator 옵션 설명:

  • Exists: key만 일치하면 됨 (value 무시)
  • Equal: key와 value가 모두 일치해야 함

Effect 타입:

  • NoSchedule: Pod가 스케줄링되지 않음
  • PreferNoSchedule: 가능하면 스케줄링하지 않음 (soft)
  • NoExecute: 실행 중인 Pod도 제거 (tolerationSeconds로 유예 기간 설정 가능)

로깅이나 모니터링 DaemonSet의 경우 대부분의 Taint를 무시하도록 operator: Exists만 설정하는 것도 가능합니다:

tolerations:
- operator: Exists  # 모든 Taint 무시 (주의해서 사용)

Test 2: 노드 선택자로 특정 노드 타겟팅

특정 레이블이 있는 노드에서만 실행되도록 설정했습니다.

# 노드에 레이블 추가
$ kubectl label node minikube monitoring=enabled
node/minikube labeled

$ kubectl label node minikube node-type=worker
node/minikube labeled

# DaemonSet 배포
$ kubectl apply -f node-selector-daemonset.yaml
daemonset.apps/monitoring-agent created

# 확인
$ kubectl get ds monitoring-agent
NAME               DESIRED   CURRENT   READY   NODE SELECTOR
monitoring-agent   1         1         1       monitoring=enabled

고급 Node Affinity 설정:

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: node-type
          operator: In
          values: ["worker", "storage"]

NodeSelector는 단순 선택, NodeAffinity는 복잡한 규칙에 적합합니다.

Test 3: Rolling Update 전략 테스트 

Fluentd DaemonSet으로 무중단 업데이트를 테스트했습니다.

# 초기 배포
$ kubectl apply -f rolling-update-daemonset.yaml
daemonset.apps/fluentd-logging created

# 이미지 업데이트로 Rolling Update 트리거
$ kubectl set image ds/fluentd-logging \
  fluentd=fluent/fluentd-kubernetes-daemonset:v1.16-debian-elasticsearch8-2 \
  -n kube-system

# 업데이트 히스토리 확인
$ kubectl rollout history ds/fluentd-logging -n kube-system
REVISION  CHANGE-CAUSE
1         <none>
2         <none>

Rolling Update 설정:

updateStrategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 1  # 한 번에 1개씩만 업데이트

maxUnavailable을 조절하여 업데이트 속도와 안정성의 균형을 맞춥니다.

Test 4: MaxSurge를 이용한 무중단 업데이트 (K8s 1.25+)

Kubernetes 1.33에서 MaxSurge 기능을 테스트했습니다.

updateStrategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 0  # 다운타임 제로
    maxSurge: 1        # 임시로 추가 Pod 허용

테스트 결과:

# 업데이트 트리거
$ kubectl set env ds/network-monitor UPDATE_TIMESTAMP="$(date +%s)"

# Pod 수 모니터링 (업데이트 중 일시적으로 2개)
Pod count: 2  # 기존 Pod + 새 Pod
Pod count: 2  # 전환 중
Pod count: 1  # 업데이트 완료

hostPort를 사용하지 않을 때만 maxSurge가 가능합니다.

Test 5: 자동 복구 메커니즘

Pod 삭제 시 자동으로 재생성되는지 테스트했습니다.

# Pod 삭제
$ kubectl delete pod logging-agent-fkn7s
pod "logging-agent-fkn7s" deleted

# 5초 후 확인 - 새 Pod가 자동 생성됨
$ kubectl get pods -l name=logging-agent
NAME                  READY   STATUS    AGE
logging-agent-np74d   1/1     Running   9s

DaemonSet은 항상 원하는 상태를 유지하려고 합니다.

업데이트 전략 선택

  • 개발/테스트: OnDelete (수동 제어)
  • 프로덕션: RollingUpdate (maxUnavailable=1)
  • 크리티컬 시스템: RollingUpdate (maxSurge=1, maxUnavailable=0)

디버깅 명령어

# DaemonSet 상태 확인
kubectl describe ds <daemonset-name>

# Pod 배포 위치 확인
kubectl get pods -o wide -l <label-selector>

# 업데이트 진행 상황
kubectl rollout status ds/<daemonset-name>

# 이벤트 확인
kubectl get events --sort-by='.lastTimestamp'