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
네임스페이스에서 돌아가는 데몬셋들은 보면, Calico와 CSI 플러그인들이 데몬셋으로 설정된 것을 볼 수 있다.
이렇듯 노드를 운영하기 위해서 기본적으로 세팅해야 하는 것들에 대해서 흔히 사용된다.
한편으로, 클러스터 운영 관점에서 필요한 것들이다보니 대체로 만들어진 툴을 사용하는 실무자들은 많이 만질 일은 없는 오브젝트라고 봐도 될 것 같긴 하다.
기본적으로는 모든 노드에 같은 양식으로 만들어지지만 조금 더 복잡하게 세팅하여 사용하는 게 가능하다.
가령 하드웨어 타입에 따라 다른 정도의 리소스를 둔다던가, 그래도 특정 노드에만 배치한다던가.
동작 원리
데몬셋의 핵심은 파드가 모든 노드에 각각 스케줄링되도록 하는 것이다.
이때 데몬셋은 모든 파드에 각각 노드 Affinity를 부여하여 각 노드에 스케줄링되도록 만든다.
스케줄러는 이후에 nodeName
필드에 각각 타겟 노드를 기입하여 결과적으로 모든 노드에 파드가 배치된다.
관리자가 직접 스펙에 어피니티를 작성할 수도 있다.
이 경우 데몬셋 컨트롤러는 이를 고려하여 적격한 노드를 먼저 찾고, 이후에 파드를 생성하여 해당 파드에 각 노드에 해당하는 어피니티를 부여해준다.
참고로 그냥 파드 스펙에 nodeName을 쓰거나 하는 것도 다 가능하다.
그러면 당연히 하나의 파드만 하나의 노드에 실행될 것이다.
톨러레이션 부여
기본적으로 데몬셋은 다음의 테인트, 톨러레이션을 파드에 부여해준다.
다음의 테인트 키들은 앞에 node.kubernetes.io/
가 붙어 있는데 내가 가독성을 위해 뺀 것이다.
또, 이것들은 기본적으로 설정돼있는 테인트 키들이라 대충 알아두면 좋다.
- not-ready = NoExecute
- 파드를 받을 준비 안 된 건강하지 않은 노드에도 배치된다.
- 어떤 노드든 연결만 돼있으면 일단 뚫고 들어간다는 것..
- 그래서 그냥 드레인을 걸면 데몬셋 파드가 뻐탱기는 거다..
- 파드를 받을 준비 안 된 건강하지 않은 노드에도 배치된다.
- unreachable = NoExecute
- 노드 컨트롤러에서 접근못하는 노드에도 배치된다.
- disk-pressure = NoSchedule
- memory-pressure = NoSchedule
- pid-pressure = NoSchedule
- 디스크, 메모리, 프로세스 개수가 어떤 상태던 상관 없이 배치된다.
- unschedulable = NoSchedule
- 스케줄할 수 없다고 박아놓은(cordon) 노드도 뚫는다!
- T- 데몬셋은 드레인된 노드에도 파드를 배치하나
- network-unavailable = NoSchedule
- 이건 좀 특별한데,
spec.hostNetwork: True
인 파드에 대해서만 부여된다. - 고성능의 네트워크가 필요한 경우 파드에 호스트 네트워크를 사용하도록 하는 경우가 있다.
- CNI 플러그인들이 대표적일 것이다.
이것은 칼리코 파드인데, hostNetwork가 true라서 이렇게 파드 ip와 호스트 ip가 일치한다.
- 이건 좀 특별한데,
필요성(대안 비교)
이 친구는 아무래도 당장 떠올릴 수 있는 대안이 많은데, 다른 놈들과 비교해보면서 왜 데몬셋이 좋은지 가늠해보자.
초기화 스크립트
그냥 처음에 노드 세팅할 때 그냥 필요한 설정들을 스크립트로 짜서 관리하면 안 되긋나?
이에 대해 데몬셋은 다음의 이점을 가진다.
- 쿠버네티스라는 한 툴로 세팅까지 관리할 수 있어 복잡성이 줄어든다.
- 이건 강력하게 동의하는 바이다.
- 자바를 하는 사람은 모든 개발은 자바로 진행하고 싶어하듯이 가급적이면 하나의 툴로 모든 것을 관리하는 것이 인간에게는 편한 게 당연하다.
- 물론 쿠버가 없던 시절의 사람들에게 설득력이 있지는 않을 것 같다.
- 모니터링과 로깅 등을 어플리케이션처럼 다룰 수 있게 된다.
Running daemons in containers with resource limits increases isolation between daemons from app containers. However, this can also be accomplished by running the daemons in a container but not in a Pod.
- 이 말은 무슨 말인지 잘 이해가 안 돼서 원문을 넣었다.
- 자원 제약을 걸어 컨테이너에 데몬을 돌리면 앱 컨테이너와의 격리가 강화되나, 이건 파드가 아닌 채로 컨테이너를 돌리며 달성할 수 있기도 하다.
- 그러니까.. 이게 왜 초기화 스크립트와의 비교점이 되는 거지..?
기본 파드
그냥 직접 파드를 만들어서 하면 안 되냐?
그럴 거면 워크로드는 왜 쓰냐? 넘어간다.
정적 파드
정적 파드는 노드에 양식을 작성해두면 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
이놈도 업데이트는 가능하다!
방식은 스테이트풀셋 업데이트 전략과 동일하다.
데몬셋 파드의 양식을 업데이트할 순 있지만 지양하는 게 좋다.
문서에는 정확히 안 나오나.. 어떤 필드는 바꾸더라도 기존 양식에 있던 값을 그대로 쓴다고 하는데 내가 제대로 해석한 건지 모르겠다.
기타
데몬셋으로서 고려할 만한 여러 요소들을 살펴보자.
통신
데몬 파드들에 통신하는 방법들은 이런 방법들이 있다.
- push
- 데몬셋 파드는 대체로 데이터베이스에 알아서 정보들을 보내도록 세팅돼 있으니 이걸 받는다.
- 노드 ip, 포트
- 데몬셋 파드는
hostPort
를 사용하니, 이걸로 연결한다.
- 데몬셋 파드는
- DNS
- headless Service를 만들어서 엔드포인트만 확인하거나, dns를 거친다.
- 서비스
- 그냥 서비스로 만들면, 무작위 노드에 있는 데몬셋 파드와 통신할 수 있을 것이다.
노드 라벨 업데이트
기본적으로 데몬셋은 항상 노드들을 체크하기에, 노드 라벨에 변경이 생기면 이를 추적해서 파드를 추가하거나 제거할 노드를 찾아낸다.
관련 문서
이름 | noteType | created |
---|---|---|
T- 데몬셋은 드레인된 노드에도 파드를 배치하나 | topic/temp | 2024-12-27 |