쿠버네티스를 운영하다 보면 "어? 이게 왜 여기 뜨지?" 하는 순간들이 찾아옵니다. 가장 대표적인 오해가 바로 "파드는 노드에 골고루(Round-Robin) 배포될 것"이라는 믿음입니다.
오늘은 제가 직접 겪은 '파드 쏠림 현상'을 통해 쿠버네티스 스케줄러가 실제로 어떻게 점수를 매기고 노드를 선택하는지, 그 보이지 않는 로직을 파헤쳐 보겠습니다. 🚀

0. 문제 상황: "분명히 노드는 여러 개인데..."
테스트를 위해 MySQL, Nginx, 그리고 httpd 파드를 순서대로 생성했습니다. 우리의 기대는 당연히 "1번 노드, 2번 노드, 3번 노드... 이렇게 사이좋게 나눠지겠지?" 였습니다.
하지만 현실은 달랐습니다.
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
mysql 1/1 Running 0 66m 10.16.2.12 gke-cluster-1-default-pool-rr03 <none>
nx 1/1 Running 0 16m 10.16.2.13 gke-cluster-1-default-pool-rr03 <none>
nx1 1/1 Running 0 6s 10.16.2.14 gke-cluster-1-default-pool-rr03 <none>
httpd 1/1 Running 0 4s 10.16.2.15 gke-cluster-1-default-pool-rr03 <none>
보시다시피 mysql, nx, 심지어 다른 이미지인 httpd까지 모두 rr03이라는 하나의 노드에만 주구장창 생성되었습니다. 다른 노드들은 텅텅 비어있는데 말이죠! 😱
이유가 무엇일까요? 스케줄러가 고장 난 걸까요?
1. 오해 풀기: 스케줄러는 ABC 순서를 모른다 ❌
많은 분들이 스케줄러가 '라운드 로빈(Round-Robin)' 방식을 쓴다고 해서, 노드 이름 순서(A->B->C)대로 배포할 거라 생각합니다. 하지만 쿠버네티스 스케줄러는 철저하게 '점수(Score)' 기반으로 움직입니다.
- Filtering: 조건에 안 맞는 노드 탈락
- Scoring: 남은 노드에 점수 매기기 (0~100점)
- Ranking: 1등 노드 선택
즉, rr03 노드가 계속 선택된 이유는 순서 때문이 아니라, 스케줄러 눈에 rr03이 계속 "1등 신랑감"으로 보였기 때문입니다.
2. 범인 분석: 왜 꽉 찬 노드가 1등이 되었을까? 🤔
텅 빈 노드를 두고, 이미 파드가 3개나 있는 노드가 1등을 한 이유는 두 가지 설정의 합작품입니다.
① 리소스 요청(Requests) 미설정 = "투명 인간" 취급
저는 파드를 생성할 때 resources.requests (CPU/Memory 요청량)를 설정하지 않았습니다.
- 스케줄러의 시선: "이 파드는 CPU 0, 메모리 0을 쓰네?"
- 판단: rr03 노드에 파드가 100개가 있든 1000개가 있든, Request가 설정되지 않은 파드들만 있다면 스케줄러 입장에서 해당 노드의 사용률은 여전히 '0%'입니다.
- 결과: "빈 노드나, rr03이나 어차피 둘 다 널널한 건 똑같네? (리소스 점수 동점)"
② 결정타: 이미지 지역성 (Image Locality) & 레이어 공유
여기서 의문이 생깁니다. "점수가 동점이면 랜덤으로 가야지, 왜 굳이 rr03으로 갔을까?"
범인은 ImageLocality 가산점입니다.
- Nginx 배포 시: mysql 때문에 이미지가 다운로드된 노드에 가면 빠르니까 rr03 선택 (이해 가능)
- Httpd 배포 시: "어? 이건 새로운 이미지인데?"
- 하지만 도커 이미지는 레이어(Layer) 구조입니다.
- mysql, nginx, httpd는 서로 다르지만, 기저에 깔린 Base Image(Debian, Alpine 등)나 공통 라이브러리 레이어를 공유할 확률이 매우 높습니다.
- 최종 판정:
- 빈 노드: "가서 베이스 레이어부터 다 새로 받아야 함" -> 가산점 없음
- rr03 노드: "어? 옆에 애들이 쓰던 베이스 레이어가 이미 있네? 개이득!" -> 가산점 부여 (+)
결국 리소스 점수는 동점(0점 영향)인데, 이미지 캐싱 점수에서 rr03이 미세하게 앞서면서 계속해서 파드를 빨아들이는 블랙홀이 된 것입니다. 🕳️
3. 해결 방법: 파드를 흩어지게 하려면? 🛠️
이 현상을 막고 클러스터 전체에 골고루 파드를 분산시키려면 어떻게 해야 할까요?
✅ 방법 1: 리소스 요청(Requests) 명시하기 (권장)
파드에 "나 덩치 이만큼 있어!"라고 명찰을 달아주세요.
resources:
requests:
cpu: "200m" # 0.2 코어 요청
이렇게 하면 스케줄러가 "앗, rr03은 이미 꽉 찼구나. 빈 노드로 보내야지!"라고 정상적으로 판단하여 부하 분산(Least Allocated) 로직이 작동합니다.
✅ 방법 2: 안티 어피니티(Anti-Affinity) 설정
"나랑 똑같은 애 있는 곳은 싫어!"라고 강제로 설정하는 방법입니다.
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector: ...
이 옵션을 쓰면 점수 계산과 상관없이 무조건 겹치지 않게 배치됩니다.
4. 결론 📝
- 쿠버네티스 스케줄러는 ABC 순서로 배포하지 않는다.
- requests를 설정하지 않으면 스케줄러는 파드의 크기를 '0'으로 본다.
- 이 경우, 이미지 레이어가 조금이라도 남아있는 노드가 가산점을 받아 파드가 한곳에 쏠릴 수 있다.
- 안정적인 운영을 위해 Resource Requests 설정은 선택이 아닌 필수다!
오늘의 삽질 끝! 콧대 높은 스케줄러의 마음을 이해하는 데 도움이 되셨길 바랍니다. 👋
'클라우드 > 쿠버네티스' 카테고리의 다른 글
| [Kubernetes] "내 파드의 신분증이 바뀌었다?" Service Account와 Projected Volume 완벽 해부 🆔 (0) | 2025.12.19 |
|---|---|
| [클라우드/Network] GKE의 34.x 대역과 EKS의 100.64.x 대역, 도대체 정체가 뭘까? 🕵️♂️☁️ (0) | 2025.12.19 |
| 🏗️ [쿠버네티스] 파드에 디스크를 직접 연결하면 안 되는 이유 (PV, PVC, SC의 필요성) (0) | 2025.12.11 |
| 📦 그림 한 장으로 끝내는 쿠버네티스 볼륨(Volume) 구조와 원리 (0) | 2025.12.11 |
| 📦 쿠버네티스 스토리지의 가벼운 혁명: Rancher Local Path Provisioner 완벽 해부 (0) | 2025.12.11 |