[k8s] DaemonSet ㅡ 이해하기
DaemonSet
모든 노드에 Pod를 1개씩 자동 배포하는 방법
DaemonSet이란?
Deployment는 원하는 수(replicas)만큼 Pod를 배포한다. 어느 노드에 올라갈지는 스케줄러가 결정한다. DaemonSet은 다르다. 클러스터의 모든 노드에 Pod를 반드시 1개씩 배포한다. 노드가 새로 추가되면 거기에도 자동으로 Pod가 생기고, 노드가 삭제되면 Pod도 함께 사라진다.
모든 서버에서 동일한 작업이 필요할 때 쓴다.
| 용도 | 대표 서비스 | 설명 |
|---|---|---|
| 메트릭 수집 | node-exporter | 노드별 CPU/메모리/디스크 수집 |
| 로그 수집 | fluentd, filebeat | 노드별 로그 수집 후 중앙 저장소로 전송 |
| 네트워크 처리 | kube-proxy, flannel | 노드 네트워크 트래픽 라우팅 및 CNI |
| 보안 에이전트 | falco, datadog-agent | 노드별 보안 이벤트 감지 |
Deployment vs DaemonSet 비교
| Deployment | DaemonSet | |
|---|---|---|
| Pod 수 | replicas로 지정 | 노드 수 = Pod 수 (자동) |
| 배치 위치 | 스케줄러가 결정 | 모든 노드에 반드시 1개 |
| 노드 추가 시 | replicas 수 유지 (자동 배포 없음) | 새 노드에 자동으로 Pod 생성 |
| yaml 차이 | replicas 항목 있음 | replicas 항목 없음 |
클러스터에서 DaemonSet 확인
kubectl get daemonset -A
NAMESPACE NAME DESIRED CURRENT READY
kube-flannel kube-flannel-ds 2 2 2
kube-system kube-proxy 2 2 2
monitoring node-exporter 2 2 2
노드가 2개이므로 DESIRED가 모두 2다. 노드가 3대로 늘어나면 자동으로 DESIRED 3이 된다.
$ kubectl get daemonset -A
NAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
dev nginx-daemonset 1 1 1 1 1 <none> 133m
kube-flannel kube-flannel-ds 2 2 2 2 2 <none> 69d
kube-system kube-proxy 2 2 2 2 2 kubernetes.io/os=linux 69d
monitoring node-exporter 2 2 2 2 2 <none> 68d
DaemonSet yaml 만들기
DaemonSet은 kubectl create daemonset 명령어가 없다. yaml 파일을 직접 작성해야 한다.
명령어로 생성할 수 없는 이유는 DaemonSet이 단순히 "몇 개 띄워줘" 수준이 아니기 때문이다. DaemonSet은 노드 선택 조건(nodeSelector), Taint 허용(tolerations), 호스트 네트워크 공유(hostNetwork) 등 노드 환경에 밀접하게 연관된 복잡한 설정이 필요하다. 이런 설정들은 명령어 옵션 몇 개로 표현하기 어렵기 때문에 처음부터 yaml로만 작성하도록 설계되어 있다.
참고로 kubectl create 명령어가 지원되는 오브젝트와 아닌 것을 구분하면 아래와 같다.
| kubectl create 가능 | yaml만 가능 |
|---|---|
| deployment, configmap, secret, service, namespace | daemonset, statefulset, pv, pvc, ingress |
가장 실용적인 방법은 클러스터에 이미 있는 DaemonSet yaml을 뽑아서 수정하는 것이다. 여기서는 node-exporter DaemonSet을 기반으로 nginx DaemonSet을 만든다.
1단계 — 기존 DaemonSet yaml 추출
# node-exporter DaemonSet yaml을 파일로 저장
kubectl get daemonset node-exporter -n monitoring -o yaml > /k8s/nginx-daemonset.yaml
2단계 — vi로 열어서 치환
vi /k8s/nginx-daemonset.yaml
# vi 안에서 아래 치환 명령어 실행
:%s/node-exporter/nginx-daemonset/g
:%s/monitoring/dev/g
:%s/prom\/node-exporter:v1.7.0/nginx:1.27/g
vi에서 :%s/찾을값/바꿀값/g 는 파일 전체에서 치환하는 명령어다. /가 포함된 경로는 앞에 \를 붙여서 이스케이프해야 한다.
3단계 — 불필요한 항목 삭제
node-exporter는 노드 메트릭 수집용이라 불필요한 항목이 많다. 아래 항목들을 vi에서 dd(줄 삭제), Ndd(N줄 삭제)로 제거한다.
| 삭제 항목 | 이유 |
|---|---|
| annotations 블록 | 기존 오브젝트 메타데이터, 새 오브젝트에 불필요 |
| creationTimestamp, resourceVersion, uid | k8s가 자동 부여하는 값, 직접 지정하면 충돌 |
| args 블록 | node-exporter 전용 실행 인자 |
| ports, volumeMounts, volumes 블록 | node-exporter 전용 포트/마운트 설정 |
| hostNetwork, hostPID | node-exporter 전용 호스트 네트워크/PID 공유 설정 |
| tolerations 블록 | 마스터 노드 배포 허용 설정 (테스트용이므로 제거) |
| status 블록 | 현재 상태값, apply 시 k8s가 자동 관리 |
4단계 — 최종 yaml
정리가 완료되면 아래와 같은 구조가 된다.
DaemonSet yaml 구조
Deployment yaml과 구조가 거의 동일하다. kind: DaemonSet으로 바꾸고 replicas를 제거하면 된다.
apiVersion: apps/v1
kind: DaemonSet # Deployment → DaemonSet
metadata:
name: nginx-daemonset
namespace: dev
spec:
# replicas 항목 없음
selector:
matchLabels:
app: nginx-daemonset
template:
metadata:
labels:
app: nginx-daemonset
spec:
containers:
- image: nginx:1.27
name: nginx-daemonset
resources: {}
updateStrategy:
type: RollingUpdate # 업데이트 시 노드별로 순서대로 교체
rollingUpdate:
maxUnavailable: 1 # 한 번에 1개씩 교체
kubectl apply -f nginx-daemonset.yaml
kubectl get daemonset -n dev
17:30:16 [root@k8s-worker-jwc:/k8s]$ kubectl get daemonset -n dev
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
nginx-daemonset 1 1 1 1 1 <none> 132m
마스터 노드에 배포되지 않는 이유 — Taint와 Toleration
노드가 2개(마스터 + 워커)인데 DESIRED가 1인 경우가 있다. 마스터 노드에는 Taint가 기본으로 설정되어 있어서 일반 Pod 배포를 막는다.
| 개념 | 역할 | 비유 |
|---|---|---|
| Taint | 노드에 설정하는 "출입 제한" 표시 | 출입 금지 표지판 |
| Toleration | Pod에 설정하는 "나는 들어갈 수 있어" 설정 | 출입증 |
node-exporter처럼 마스터에도 반드시 배포해야 하는 경우 tolerations를 추가하면 된다.
spec:
tolerations:
- operator: Exists # 모든 Taint를 무시하고 배포 허용
다음 파트는 StatefulSet — 순서와 고정 이름이 필요한 DB 같은 서비스를 관리하는 방법을 다룬다.