DaemonSet
DaemonSet
DaemonSet은 모든(또는 일부) 노드가 파드의 사본을 실행하도록 보장해요. 노드가 클러스터에 추가되면 파드가 그 노드에 추가되고, 노드가 클러스터에서 제거되면 그 파드들은 가비지 컬렉션돼요. DaemonSet을 삭제하면 그것이 만든 파드들이 정리돼요.
DaemonSet의 몇 가지 일반적인 용도는 다음과 같아요.
- 모든 노드에서 클러스터 저장소 데몬 실행
- 모든 노드에서 로그 수집 데몬 실행
- 모든 노드에서 노드 모니터링 데몬 실행
간단한 경우에는 모든 노드를 다루는 하나의 DaemonSet을 각 유형의 데몬에 사용해요. 더 복잡한 설정은 한 유형의 데몬에 여러 DaemonSet을 사용할 수 있는데, 하드웨어 유형에 따라 다른 플래그 및/또는 다른 메모리·CPU 요청을 사용할 수 있어요.
출처: 문서
본문
DaemonSet 스펙 작성하기
DaemonSet 만들기
DaemonSet을 YAML 파일로 설명할 수 있어요. 예를 들어 아래 daemonset.yaml 파일은 fluentd-elasticsearch Docker 이미지를 실행하는 DaemonSet을 설명해요.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
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:v5.0.1
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
# DaemonSet 파드가 실행 중인 파드를 선점하도록 하려면
# 높은 priority class를 설정하는 것이 좋을 수 있습니다.
# priorityClassName: important
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
YAML 파일에 기반해 DaemonSet을 만들어요.
kubectl apply -f https://k8s.io/examples/controllers/daemonset.yaml
필수 필드 (Required Fields)
다른 모든 쿠버네티스 구성과 마찬가지로 DaemonSet은 apiVersion, kind, metadata 필드가 필요해요. 구성 파일 작업에 대한 일반 정보는 '상태 없는 애플리케이션 실행'과 'kubectl로 객체 관리'를 참고하세요.
DaemonSet 객체의 이름은 유효한 DNS 하위 도메인 이름이어야 해요.
DaemonSet에는 .spec 섹션도 필요해요.
파드 템플릿 (Pod Template)
.spec.template은 .spec의 필수 필드 중 하나예요.
.spec.template은 파드 템플릿(pod template)이에요. 파드(Pod)와 정확히 같은 스키마를 가지지만, 중첩되어 있고 apiVersion이나 kind가 없어요.
파드의 필수 필드 외에도, DaemonSet의 파드 템플릿은 적절한 라벨을 지정해야 해요(파드 셀렉터 참조).
DaemonSet의 파드 템플릿은 RestartPolicy가 Always와 같거나, 지정되지 않아야 하며(기본값은 Always), 그렇게 됩니다.
파드 셀렉터 (Pod Selector)
.spec.selector 필드는 파드 셀렉터예요. Job의 .spec.selector와 같은 방식으로 동작해요.
.spec.template의 라벨과 일치하는 파드 셀렉터를 지정해야 해요. 또한, 일단 DaemonSet이 생성되면 .spec.selector는 변경될 수 없어요. 파드 셀렉터를 변경하면 파드가 의도치 않게 고아(orphan)가 될 수 있고, 사용자에게 혼란스러운 것으로 밝혀졌어요.
.spec.selector는 두 필드로 구성된 객체예요.
matchLabels- ReplicationController의.spec.selector와 같은 방식으로 동작해요.matchExpressions- 키, 값 목록, 키와 값을 연결하는 연산자(operator)를 지정해 더 정교한 셀렉터를 만들 수 있게 해줘요.
둘 다 지정되면 결과는 AND가 돼요.
.spec.selector는 .spec.template.metadata.labels와 일치해야 해요. 이 둘이 일치하지 않는 구성은 API가 거부해요.
선택된 노드에서 파드 실행하기
.spec.template.spec.nodeSelector를 지정하면 DaemonSet 컨트롤러는 그 노드 셀렉터와 일치하는 노드에 파드를 만들어요. 마찬가지로 .spec.template.spec.affinity를 지정하면 DaemonSet 컨트롤러는 그 노드 어피니티와 일치하는 노드에 파드를 만들어요. 둘 다 지정하지 않으면 DaemonSet 컨트롤러는 모든 노드에 파드를 만들어요.
데몬 파드가 스케줄링되는 방법
DaemonSet은 모든 적격 노드가 파드의 사본을 실행하도록 보장하는 데 사용될 수 있어요. DaemonSet 컨트롤러는 각 적격 노드에 대해 파드를 만들고, 대상 호스트와 일치하도록 파드의 spec.affinity.nodeAffinity 필드를 추가해요. 파드가 생성된 후에는 보통 기본 스케줄러가 그 일을 이어받아 .spec.nodeName 필드를 설정해 파드를 대상 호스트에 바인딩해요. 새 파드가 노드에 들어갈 수 없다면, 기본 스케줄러는 새 파드의 우선순위에 기반해 기존 파드 중 일부를 선점(축출)할 수 있어요.
참고:
사용자는 DaemonSet의 .spec.template.spec.schedulerName 필드를 설정해 DaemonSet 파드에 다른 스케줄러를 지정할 수 있어요.
.spec.template.spec.affinity.nodeAffinity 필드에 지정된 원래 노드 어피니티(지정된 경우)는 DaemonSet 컨트롤러가 적격 노드를 평가할 때 고려되지만, 생성된 파드에서는 적격 노드의 이름과 일치하는 노드 어피니티로 교체돼요.
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchFields:
- key: metadata.name
operator: In
values:
- target-host-name
테인트와 톨러레이션 (Taints and tolerations)
DaemonSet 컨트롤러는 DaemonSet 파드에 톨러레이션 집합을 자동으로 추가해요.
| 톨러레이션 키 | 효과 | 세부 사항 |
|---|---|---|
| node.kubernetes.io/not-ready | NoExecute | DaemonSet 파드는 파드를 받기에 건강하지 않거나 준비되지 않은 노드에 스케줄링될 수 있음. 그러한 노드에서 실행 중인 DaemonSet 파드는 축출되지 않음. |
| node.kubernetes.io/unreachable | NoExecute | DaemonSet 파드는 노드 컨트롤러에서 도달할 수 없는 노드에 스케줄링될 수 있음. 그러한 노드에서 실행 중인 DaemonSet 파드는 축출되지 않음. |
| node.kubernetes.io/disk-pressure | NoSchedule | DaemonSet 파드는 디스크 압력 문제가 있는 노드에 스케줄링될 수 있음. |
| node.kubernetes.io/memory-pressure | NoSchedule | DaemonSet 파드는 메모리 압력 문제가 있는 노드에 스케줄링될 수 있음. |
| node.kubernetes.io/pid-pressure | NoSchedule | DaemonSet 파드는 프로세스 압력 문제가 있는 노드에 스케줄링될 수 있음. |
| node.kubernetes.io/unschedulable | NoSchedule | DaemonSet 파드는 스케줄 불가능한 노드에 스케줄링될 수 있음. |
| node.kubernetes.io/network-unavailable | NoSchedule | 호스트 네트워킹(spec.hostNetwork: true인 파드)을 요청하는 DaemonSet 파드에만 추가됨. 그러한 DaemonSet 파드는 네트워크를 사용할 수 없는 노드에 스케줄링될 수 있음. |
DaemonSet의 파드 템플릿에 정의해 DaemonSet 파드에 자신만의 톨러레이션을 추가할 수도 있어요.
DaemonSet 컨트롤러가 node.kubernetes.io/unschedulable:NoSchedule 톨러레이션을 자동으로 설정하기 때문에, 쿠버네티스는 스케줄 불가능으로 표시된 노드에서도 DaemonSet 파드를 실행할 수 있어요.
클러스터 네트워킹 같은 중요한 노드 수준 기능을 제공하는 데 DaemonSet을 사용한다면, 쿠버네티스가 노드가 준비되기 전에 DaemonSet 파드를 그 노드에 배치하는 것이 도움이 돼요. 예를 들어 그 특수한 톨러레이션 없이는, 네트워크 플러그인이 그 노드에서 실행되지 않아 노드가 준비된 것으로 표시되지 않고, 동시에 노드가 아직 준비되지 않아 네트워크 플러그인이 그 노드에서 실행되지 않는 교착 상태에 빠질 수 있어요.
데몬 파드와 통신하기
DaemonSet의 파드와 통신하는 몇 가지 가능한 패턴은 다음과 같아요.
- Push: DaemonSet의 파드는 통계 데이터베이스 같은 다른 서비스에 업데이트를 보내도록 구성돼요. 이들은 클라이언트가 없어요.
- NodeIP와 알려진 포트: DaemonSet의 파드는
hostPort를 사용해 노드 IP로 도달할 수 있게 할 수 있어요. 클라이언트는 어떤 식으로든 노드 IP 목록을 알고, 관례로 포트를 알아요. - DNS: 같은 파드 셀렉터로 헤드리스 서비스를 만들고, endpoints 리소스를 사용해 DaemonSet을 발견하거나 DNS에서 여러 A 레코드를 검색해요.
- Service: 같은 파드 셀렉터로 서비스를 만들고, 그 서비스를 사용해 임의의 노드의 데몬에 도달해요. 서비스 내부 트래픽 정책(Service Internal Traffic Policy)을 사용해 같은 노드의 파드로 제한할 수 있어요.
DaemonSet 업데이트하기
노드 라벨이 변경되면 DaemonSet은 새로 일치하는 노드에 파드를 즉시 추가하고, 새로 일치하지 않는 노드에서 파드를 삭제해요.
DaemonSet이 만드는 파드를 수정할 수 있어요. 하지만 파드는 모든 필드가 업데이트되도록 허용하지는 않아요. 또한 DaemonSet 컨트롤러는 다음에 (같은 이름이더라도) 노드가 생성될 때 원래 템플릿을 사용해요.
DaemonSet을 삭제할 수 있어요. kubectl로 --cascade=orphan을 지정하면 파드가 노드에 남아 있어요. 그 후 같은 셀렉터로 새 DaemonSet을 만들면, 새 DaemonSet이 기존 파드를 채택해요. 교체할 파드가 있다면 DaemonSet이 자신의 updateStrategy에 따라 교체해요.
DaemonSet에 대해 롤링 업데이트를 수행할 수 있어요.
DaemonSet의 대안 (Alternatives to DaemonSet)
초기화 스크립트 (Init scripts)
노드에서 데몬 프로세스를 직접 시작해(예: init, upstartd, systemd 사용) 실행하는 것은 확실히 가능해요. 이것도 완벽히 괜찮아요. 하지만 DaemonSet을 통해 그러한 프로세스를 실행하는 것에는 몇 가지 장점이 있어요.
- 애플리케이션과 같은 방식으로 데몬의 로그를 모니터링하고 관리할 수 있는 능력.
- 데몬과 애플리케이션에 대해 같은 구성 언어와 도구(예: Pod 템플릿, kubectl) 사용.
- 컨테이너에서 리소스 한도와 함께 데몬을 실행하면 앱 컨테이너와 데몬 간의 격리가 증가해요. 하지만 이것은 데몬을 컨테이너에서 실행하되 파드에서는 실행하지 않는 것으로도 이룰 수 있어요.
베어 파드 (Bare Pods)
특정 노드에서 실행하도록 지정하는 파드를 직접 만들 수 있어요. 하지만 DaemonSet은 노드 실패나 커널 업그레이드 같은 파괴적인 노드 유지보수 같은 어떤 이유로든 삭제되거나 종료된 파드를 교체해요. 이런 이유로 개별 파드를 만드는 것보다 DaemonSet을 사용해야 해요.
정적 파드 (Static Pods)
kubelet이 감시하는 특정 디렉터리에 파일을 써서 파드를 만드는 것이 가능해요. 이를 정적 파드(static pods)라고 해요. DaemonSet과 달리 정적 파드는 kubectl이나 다른 쿠버네티스 API 클라이언트로 관리할 수 없어요. 정적 파드는 apiserver에 의존하지 않아 클러스터 부트스트래핑 경우에 유용해요. 또한 정적 파드는 미래에 폐기될 수 있어요.
Deployment
DaemonSet은 Deployment와 모두 파드를 만들고, 그 파드의 프로세스가 종료될 것으로 예상되지 않는다는 점에서(예: 웹 서버, 저장소 서버) 유사해요.
프런트엔드 같은 상태 없는 서비스에는 Deployment를 사용해요. 여기서는 레플리카 수를 늘리거나 줄이고 롤링 업데이트를 내보내는 것이 파드가 실행될 정확한 호스트를 제어하는 것보다 더 중요해요. 파드의 사본이 항상 모든 또는 특정 호스트에서 실행되는 것이 중요하고, DaemonSet이 다른 파드가 특정 노드에서 올바르게 실행되게 하는 노드 수준 기능을 제공한다면 DaemonSet을 사용해요.
예를 들어 네트워크 플러그인은 종종 DaemonSet으로 실행되는 구성 요소를 포함해요. DaemonSet 구성 요소는 실행 중인 노드에 동작하는 클러스터 네트워킹이 있도록 보장해요.
더 알아보기 (Learn more)
- 파드(Pods)에 대해 배워 보세요.
- 정적 파드에 대해 배워 보세요. 쿠버네티스 제어 플레인 구성 요소를 실행하는 데 유용해요.
- DaemonSet 사용 방법 알아보기: DaemonSet에서 롤링 업데이트 수행 / DaemonSet 롤백 수행.
- 쿠버네티스가 파드를 노드에 어떻게 할당하는지 이해하기.
- 종종 DaemonSet으로 실행되는 장치 플러그인과 애드온에 대해 배워 보세요.
- DaemonSet은 쿠버네티스 REST API의 최상위 리소스예요. 데몬셋의 API를 이해하려면 DaemonSet 객체 정의를 읽어 보세요.