Kubernetes DaemonSet 으로 노드 서비스 배포하기

KubernetesBeginner
지금 연습하기

소개

일정한 복제본 수를 유지하는 대신, 적합한 모든 노드에서 하나씩 실행되어야 하는 소프트웨어가 있습니다. 로그 수집기, 모니터링 에이전트, 네트워킹 구성 요소는 이러한 노드 중심 배치에 DaemonSet 을 흔히 사용합니다.

이 실습에서는 준비된 노드에 레이블을 지정하고, 노드 리포터를 배포한 다음, 해당 Pod 의 소유 관계를 확인하고, 노드 적합성을 변경하고, 롤링 업데이트를 수행합니다. 단일 노드 실습 환경에서는 배치 규칙을 쉽게 관찰할 수 있으며, 더 큰 클러스터에서 사용되는 동일한 컨트롤러 동작도 그대로 확인할 수 있습니다.

이 실습에서 계속해서 확인할 핵심 질문은“복제본을 몇 개 실행해야 하는가?”가 아니라“어떤 노드가 적합한가?”입니다. DaemonSet 은 이 질문에 지속적으로 답하면서 조건에 맞는 각 노드에 하나의 Pod 를 생성합니다. 이 환경에는 노드가 하나뿐이므로, 적합성의 변화가 하나에서 0 으로 또는 0 에서 하나로 바뀌는 결과를 명확하게 보여 줍니다.

적합한 노드 표시하기

이 단계에서는 노드에 특정 용도의 레이블을 추가합니다. 레이블은 컨트롤러가 선택할 수 있는 노드의 속성을 나타냅니다.

먼저 노드와 현재 설정된 레이블을 확인합니다. 출력 내용이 길기 때문에 모두 외울 필요는 없습니다. 레이블이 Node 객체에 연결된 키 - 값 형식의 정보라는 점만 확인하면 됩니다.

cd /home/labex/project/daemonset-workloads
kubectl get nodes --show-labels

새 레이블을 추가합니다. 설정 과정에서 기존 값을 제거했으므로 여기서는 --overwrite 옵션이 필요하지 않습니다. 다만 충돌하는 값이 이미 있으면 kubectl label이 이를 알려 줍니다.

kubectl label node labex-v135 practice-tier=operations
kubectl get node labex-v135 -L practice-tier

-L practice-tier는 해당 레이블을 표의 열로 추가합니다. 이제 이 노드는 실습용 운영 에이전트를 배치할 수 있는 노드임을 나타냅니다.

두 번째 명령은 매우 긴 --show-labels 출력 대신 필요한 정보만 간결하게 보여 줍니다.

NAME         STATUS   ROLES           VERSION   PRACTICE-TIER
labex-v135   Ready    control-plane   v1.35.5   operations

PRACTICE-TIER=operations가 필요한 근거입니다. 레이블만으로는 아무 작업도 실행되지 않으며, 다음 단계에서 워크로드가 이 레이블을 선택할 때 의미를 갖게 됩니다.

DaemonSet 배포하기

이 단계에서는 새 레이블이 지정된 노드를 대상으로 하는 DaemonSet 을 생성합니다.

매니페스트를 입력하기 전에 서로 연결된 세 가지 설정으로 나누어 살펴보세요. 선택자와 Pod 레이블이 모두 app: node-reporter를 사용하므로 컨트롤러가 자신이 관리하는 Pod 를 식별할 수 있습니다. 이어서 nodeSelector가 practice-tier=operations 레이블이 있는 노드만 배치 대상이 되도록 제한합니다. 마지막으로 Downward API 가 선택된 Pod 의 spec.nodeName을 컨테이너 내부의 NODE_NAME 환경 변수로 전달합니다.

반복 실행되는 루프는 데모 에이전트가 계속 실행되도록 합니다. 실제 DaemonSet 에서는 로그 수집기나 모니터링 에이전트가 이 역할을 대신할 수 있습니다.

cat <<'EOF' > node-reporter.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-reporter
  namespace: practice-daemon
spec:
  selector:
    matchLabels:
      app: node-reporter
  template:
    metadata:
      labels:
        app: node-reporter
    spec:
      nodeSelector:
        practice-tier: operations
      containers:
        - name: reporter
          image: busybox:1.36
          imagePullPolicy: IfNotPresent
          command: ["sh", "-c", "while true; do echo node=${NODE_NAME} version=v1; sleep 15; done"]
          env:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
EOF

네임스페이스를 생성하고 파일을 적용한 뒤 DaemonSet 롤아웃이 완료될 때까지 기다립니다.

kubectl create namespace practice-daemon
kubectl apply -f node-reporter.yaml
kubectl rollout status daemonset/node-reporter -n practice-daemon --timeout=60s
kubectl get daemonset,pods -n practice-daemon -o wide

Downward API 의 fieldRef는 노드 이름을 매니페스트에 직접 입력하지 않고도 스케줄링된 노드의 이름을 전달합니다. 이 단일 노드 클러스터에서는 원하는 수, 현재 수, 준비된 수가 모두 1 이어야 합니다.

Pod 이름에는 자동으로 생성된 접미사가 포함되지만 NODE 열에는 labex-v135가 표시되어야 합니다. 이는 노드 적합성 규칙과 실제 스케줄링 결과가 일치한다는 직접적인 증거입니다.

단일 노드 테스트 클러스터에서 주요 열은 다음과 같이 표시됩니다.

NAME            DESIRED   CURRENT   READY   NODE SELECTOR
node-reporter   1         1         1       practice-tier=operations

NAME                  READY   STATUS    NODE
node-reporter-...      1/1     Running   labex-v135

첫 번째 행을 왼쪽에서 오른쪽으로 읽어 보세요. 선택자와 일치하는 노드가 하나이고, Pod 가 하나 생성되었으며, 해당 Pod 가 준비 상태라는 뜻입니다. 더 큰 클러스터에서는 적합한 노드 수에 따라 이 값들이 증가합니다.

적합성과 소유 관계 확인하기

이 단계에서는 복제본 설정이 아니라 노드 적합성이 DaemonSet Pod 수를 결정한다는 점을 확인합니다.

먼저 정상 상태의 기준 정보를 수집합니다. 사용자 지정 열을 사용하면 자동 생성된 Pod 를 해당 DaemonSet 과 연결해 볼 수 있고, 로그를 통해 Downward API 가 노드 이름을 전달했는지도 확인할 수 있습니다.

kubectl get pods -n practice-daemon -l app=node-reporter -o custom-columns='POD:.metadata.name,NODE:.spec.nodeName,OWNER:.metadata.ownerReferences[0].kind,READY:.status.containerStatuses[0].ready'
kubectl logs -n practice-daemon -l app=node-reporter --tail=3

소유 관계 표와 로그는 다음과 비슷하게 표시되어야 합니다.

POD                   NODE         OWNER       READY
node-reporter-...     labex-v135   DaemonSet   true
node=labex-v135 version=v1

OWNER 필드는 이 Pod 가 컨트롤러에 의해 관리되고 있음을 보여 줍니다. 로그는 NODE_NAME이 하드코딩된 값이 아니라 Pod 의 실제 spec.nodeName에서 전달되었음을 증명합니다.

레이블을 일시적으로 제거하고 Pod 가 사라지는 모습을 확인합니다.

kubectl label node labex-v135 practice-tier-
kubectl get daemonset node-reporter -n practice-daemon
kubectl wait --for=delete pod -n practice-daemon -l app=node-reporter --timeout=60s

끝에 -를 붙이면 해당 레이블 키가 제거됩니다. 이제 적합성을 복원하고 컨트롤러가 대체 Pod 를 생성할 때까지 기다립니다.

레이블을 제거한 직후 DaemonSet 은 다음과 같은 안정적인 상태를 잠시 보여 줍니다.

NAME            DESIRED   CURRENT   READY
node-reporter   0         0         0

이는 오류가 아니라 노드 적합성이 변경되었을 때 나타나는 정상적인 반응입니다. 현재 DaemonSet 의 nodeSelector와 일치하는 노드가 없으므로 올바른 원하는 수는 0 입니다.

kubectl label node labex-v135 practice-tier=operations
kubectl rollout status daemonset/node-reporter -n practice-daemon --timeout=60s

레이블을 변경하기 전과 후의 Pod 이름을 비교해 보세요. 대체된 Pod 는 새로운 Pod 식별자를 가지지만, DaemonSet 이름과 원하는 동작은 그대로 유지됩니다. 이것이 바로 조정 작업이 실제로 수행되는 모습입니다.

DaemonSet 업데이트 롤아웃하기

이 단계에서는 저장된 매니페스트를 업데이트하고 DaemonSet 이 기존 노드 에이전트를 교체하는 과정을 확인합니다. 파일과 실제 클러스터 객체를 일치시켜 두면 원하는 상태를 반복해서 재현할 수 있습니다.

먼저 cp를 사용해 작업용 복사본을 만듭니다. 그런 다음 Kubernetes 입문 과정에서 소개한 것과 같은 간단한 텍스트 편집 방식을 사용합니다. sed -i 's/old/new/' file은 파일에서 일치하는 텍스트를 직접 바꾸고, grep -n은 일치하는 줄을 줄 번호와 함께 출력하므로 적용하기 전에 변경 결과를 확인할 수 있습니다.

cp node-reporter.yaml node-reporter-v2.yaml
sed -i 's/version=v1/version=v2/' node-reporter-v2.yaml
grep -n 'version=' node-reporter-v2.yaml
kubectl apply -f node-reporter-v2.yaml
kubectl rollout status daemonset/node-reporter -n practice-daemon --timeout=60s
kubectl rollout history daemonset/node-reporter -n practice-daemon
kubectl logs -n practice-daemon -l app=node-reporter --tail=3

복사한 파일에는 비교를 위해 기존 v1 예제가 그대로 남아 있습니다. 한 번의 치환으로 컨테이너 명령 안에 있는 버전 텍스트만 변경됩니다. 업데이트된 파일을 적용하면 Pod 템플릿이 변경되고, 새로운 컨트롤러 리비전과 대체 Pod 가 생성됩니다. 이제 로그에는 version=v2가 포함되어야 합니다.

rollout history는 Kubernetes 가 새 리비전을 기록했음을 확인해 줍니다. 따라서 DaemonSet 도 Deployment 와 마찬가지로 템플릿을 제어된 방식으로 업데이트할 수 있습니다. 다만 대체 작업은 복제본 수가 아니라 적합한 노드를 기준으로 진행됩니다.

테스트 결과에는 두 개의 리비전과 새로운 로그 메시지가 포함되어 있었습니다.

REVISION  CHANGE-CAUSE
1         <none>
2         <none>

node=labex-v135 version=v2

CHANGE-CAUSE=<none>은 사람이 읽을 수 있는 변경 사유 주석이 기록되지 않았다는 뜻일 뿐입니다. 리비전 2가 생성되었고 대체 Pod 의 로그에 version=v2가 나타난다는 사실이 롤아웃이 완료되었다는 유용한 증거입니다.

요약

노드 레이블을 사용해 DaemonSet 의 배치 적합성을 제어하고, 적합한 노드마다 하나의 Pod 가 조정되는 과정을 관찰했으며, 컨트롤러 소유 관계를 확인하고 노드 에이전트 업데이트를 롤아웃했습니다. 이제 DaemonSet 을 복제본 중심의 Deployment 및 작업 완료 중심의 Job 과 비교해 이해할 수 있습니다.