ノードは3台あるのに、Pod の行き場がない
한국어 원문으로 표시합니다.
목표
테인트/톨러레이션, nodeSelector, 노드 어피니티가 파드의 배치를 각각 어떻게 바꾸는지 직접 걸어 보고,
같은 Pending 이라도 원인(테인트를 못 견딤 / 라벨이 안 맞음 / 맞는 존이 없음)이 다르다는 것을 관찰합니다.
왜 중요한가
쿠버네티스에서 "파드가 어느 노드에서 도는가" 는 우연이 아니라 스케줄러의 계산 결과입니다.
kube-scheduler 는 배정되지 않은 파드를 지켜보다가, 노드마다 테인트·라벨·자원·어피니티를 따져
통과하는 노드를 고르고 spec.nodeName 을 채웁니다. 이 결정이 왜 그렇게 났는지 읽지 못하면,
Pending 하나를 두고 "자원이 없나?" "노드가 죽었나?" 하고 헤매게 됩니다.
테인트는 노드가 "나는 아무나 받지 않는다" 고 선언하는 것이고, 톨러레이션은 파드가 "나는 그걸 견딘다" 고
답하는 것입니다. nodeSelector 와 노드 어피니티는 반대로 파드가 "나는 이런 노드가 좋다/필수다" 라고
요구하는 것입니다. 둘은 방향이 반대라 함께 걸릴 때가 많고, 그래서 하나만 봐서는 배치를 설명하지 못합니다.
단계
- 네임스페이스
kcna-sched를 만들고 노드 이름과 존 라벨을 파일로 뽑습니다. - 세 노드 모두에
tier=reserved:NoSchedule테인트를 겁니다. - 톨러레이션 없는 파드
plain이 Pending 에 멈추는 것을 확인합니다. - 테인트를 견디는 톨러레이션을 준 파드
tolerant가 배정되는 것을 확인합니다. lab-node-0에disktype=ssd라벨을 붙이고nodeSelector로 그 노드에만 앉는 파드를 만듭니다.- 노드 어피니티로
zone-1·zone-2노드에만 앉는 파드를 만듭니다. - 없는 라벨(
disktype=nvme)을 요구해 Pending 에 멈추는 파드를 만듭니다. - 각 파드의 결과를
/root/kcna-sched/report.txt에 장부로 남깁니다.
참고
kubectl describe pod <이름> -n kcna-sched의 Events 와PodScheduled조건의 reason 이 "왜 못 갔는지" 를 알려 줍니다.- 테인트를 못 견뎌 막히는 것과 셀렉터가 안 맞아 막히는 것은 증상이 같으니, describe 로 원인을 구분하세요.
- 공식 문서: 테인트와 톨러레이션 · 노드에 파드 배정하기 · kube-scheduler.
작업 네임스페이스와 노드 지도 만들기
네임스페이스 kcna-sched 를 만들고, 노드 이름과 각 노드의 topology.kubernetes.io/zone 라벨을 한 줄에 하나씩 이름=존 형식으로 /root/kcna-sched/nodes.txt 에 저장합니다.
스케줄러가 볼 수 있는 세상은 노드 오브젝트뿐입니다. kubectl get nodes -L <라벨키> 또는 -o jsonpath 로 이름과 존 라벨을 함께 뽑을 수 있습니다. 네임스페이스는 create 를 --dry-run=client 로 만들어 apply 하면 여러 번 돌려도 안전합니다.
세 노드를 모두 예약 표시로 잠그기
세 노드 모두에 tier=reserved:NoSchedule 테인트를 붙여, 톨러레이션이 없는 파드는 어디에도 못 들어가게 만듭니다.
NoSchedule 테인트는 그 테인트를 견디도록(toleration) 선언하지 않은 파드를 노드에서 밀어냅니다. kubectl taint node <이름> key=value:NoSchedule 을 세 노드에 겁니다. 이미 걸려 있어도 다시 걸 수 있게 --overwrite 를 붙이세요.
갈 곳 없는 파드가 Pending 에 멈추다
네임스페이스 kcna-sched 에 톨러레이션·셀렉터가 전혀 없는 파드 plain(이미지 nginx:1.27-alpine)을 만듭니다. 이 파드는 스케줄되지 못하고 Pending 에 머물러야 합니다.
세 노드가 모두 NoSchedule 테인트로 잠겨 있으니, 아무 톨러레이션도 없는 평범한 파드는 어느 노드에도 배정되지 못합니다. kubectl get pod plain -o wide 와 describe 로 PodScheduled 조건의 reason 을 확인하세요.
예약 표시를 견디는 파드는 들어간다
네임스페이스 kcna-sched 에 파드 tolerant(이미지 nginx:1.27-alpine)를 만들되, tier=reserved NoSchedule 테인트를 견디는 톨러레이션을 선언해 실제로 노드에 배정되게 합니다.
톨러레이션은 key·operator·value·effect 로 테인트와 짝을 맞춥니다. operator 는 Equal 로 value 를 명시하거나 Exists 로 키만 맞출 수 있습니다. 배정되면 spec.nodeName 이 채워지고 kwok 이 Running 으로 만들어 줍니다.
SSD 노드에만 앉히기
노드 lab-node-0 에 라벨 disktype=ssd 를 붙이고, 네임스페이스 kcna-sched 에 파드 pinned-ssd(이미지 nginx:1.27-alpine)를 만듭니다. 이 파드는 예약 테인트를 견디면서 nodeSelector 로 disktype=ssd 인 노드에만 앉아야 하며, 결과적으로 lab-node-0 에 배정돼야 합니다.
nodeSelector 는 그 라벨을 가진 노드로 후보를 좁힙니다. 테인트가 아직 살아 있으니 톨러레이션도 함께 필요합니다. 라벨을 한 노드에만 붙이면 nodeSelector 가 그 노드 하나로 배정을 몰아 줍니다.
특정 존으로만 보내는 노드 어피니티
네임스페이스 kcna-sched 에 파드 zoned(이미지 nginx:1.27-alpine)를 만듭니다. 예약 테인트를 견디면서 requiredDuringSchedulingIgnoredDuringExecution 노드 어피니티로 topology.kubernetes.io/zone 이 zone-1 또는 zone-2 인 노드에만 앉게 하세요. 결과 노드는 lab-node-1 또는 lab-node-2 여야 합니다.
노드 어피니티는 nodeSelector 보다 표현력이 큽니다. In 연산자에 값 목록을 주면 그중 하나면 됩니다. 1단계에서 뽑은 존 라벨을 보고 어떤 노드가 후보인지 미리 확인하세요. required 규칙은 맞는 노드가 없으면 파드를 Pending 으로 둡니다.
아무 노드도 만족하지 못하는 요구
네임스페이스 kcna-sched 에 파드 nowhere(이미지 nginx:1.27-alpine)를 만듭니다. 예약 테인트는 견디되 nodeSelector 로 disktype=nvme 를 요구하게 하세요. 그런 노드가 없으므로 이 파드는 Pending 에 머물러야 합니다.
톨러레이션이 있어도 셀렉터가 맞는 노드를 못 찾으면 스케줄되지 않습니다. 테인트를 못 견뎌 막히는 것과 라벨이 안 맞아 막히는 것은 원인이 다르지만 증상은 똑같이 Pending 입니다. describe 의 Events 에서 무엇이 부족한지 읽어 보세요.
무엇이 배치를 정했는지 장부로 남기기
각 파드가 어떻게 됐는지 /root/kcna-sched/report.txt 에 네 줄로 적습니다 — plain=pending, tolerant=scheduled, pinned-ssd=lab-node-0, nowhere=pending. 값은 실제 클러스터 상태와 일치해야 합니다(Pending 인 파드는 pending, 배정된 파드는 그 노드 이름).
채점기는 이 파일의 네 줄을 실제 클러스터 상태와 대조합니다. 배정된 파드는 spec.nodeName 을, Pending 인 파드는 pending 을 적으세요. 추측으로 적지 말고 kubectl get pods -n kcna-sched -o wide 로 확인한 값을 옮기세요.