- Published on
EKS에서 kubectl top이 0%일 때 Metrics API 점검
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서버/파드 리소스를 보려 kubectl top nodes, kubectl top pods를 실행했는데 값이 전부 0% 또는 0Mi로만 나오거나, 아예 Metrics API not available 류의 메시지가 뜨는 경우가 있습니다. EKS에서는 대개 metrics-server가 데이터를 못 가져오거나, kubelet(10250) 접근/인증이 깨져서 발생합니다. 이 글은 “왜 0으로 보이는지”를 원인별로 분해하고, 어디부터 어떤 명령으로 확인해야 하는지를 실전 체크리스트로 정리합니다.
> 참고로 서비스가 503인 케이스처럼 “리소스는 정상인데 관측만 깨진” 상황은 디버깅 포인트가 비슷합니다. 필요하면 EKS에서 Pod는 Running인데 503가 뜰 때 점검도 함께 보시면 좋습니다.
증상 패턴 먼저 분류하기
kubectl top 문제가 전부 같은 원인은 아닙니다. 아래 중 어디에 해당하는지 먼저 분류하면 시간을 크게 줄일 수 있습니다.
A. 아예 Metrics API가 없다고 나옴
error: Metrics API not availablethe server could not find the requested resource (get pods.metrics.k8s.io)
→ metrics-server 미설치/비정상 또는 APIService 등록 실패 가능성이 큽니다.
B. API는 응답하지만 값이 0 또는 비정상적으로 작음
- 노드/파드 CPU, 메모리가 모두 0에 가깝게 표시
- 특정 노드/특정 네임스페이스만 0
→ metrics-server가 kubelet에서 metrics를 못 긁어오거나, 일부 노드만 접근 불가일 가능성이 큽니다.
C. 간헐적으로만 0 또는 timeout
- 피크 타임에만
kubectl top이 느리거나 실패
→ metrics-server 리소스 부족, 네트워크/보안그룹, kubelet 응답 지연 등 성능/연결성 이슈를 의심합니다.
1단계: Metrics API 리소스가 존재하는지 확인
먼저 Kubernetes에 metrics API가 등록되어 있는지 확인합니다.
kubectl get apiservice | grep metrics
# 기대: v1beta1.metrics.k8s.io True
kubectl get --raw "/apis/metrics.k8s.io/v1beta1" | head
# 기대: APIGroup 디스커버리 JSON
apiservice가 없거나False라면 metrics-server 쪽부터 봐야 합니다.
APIService가 False일 때 바로 보는 곳
kubectl describe apiservice v1beta1.metrics.k8s.io
여기서 자주 보이는 문제:
FailedDiscoveryCheck(서비스 엔드포인트/인증 문제)x509인증서 관련 오류no endpoints available for service "metrics-server"
2단계: metrics-server 설치/상태 점검
EKS에서 metrics-server는 보통 kube-system에 설치합니다.
kubectl -n kube-system get deploy,svc,pods | grep -E "metrics-server|NAME"
kubectl -n kube-system logs deploy/metrics-server --tail=200
로그에서 자주 나오는 핵심 에러와 의미
(1) kubelet 연결 실패 (timeout/connection refused)
Get "https://<node-ip>:10250/...": dial tcp ... i/o timeout
의미:
- metrics-server → 노드 kubelet(10250)로 접근이 막혔거나 라우팅이 안 됨
(2) 인증/인가 실패 (401/403)
Unauthorized/Forbidden
의미:
- metrics-server의 RBAC/인증 체인이 깨졌거나, kubelet auth 설정과 충돌
- 인증 문제 전반은 Kubernetes 401 Unauthorized 원인별 해결 가이드에서 패턴을 확장해 볼 수 있습니다.
(3) 인증서 검증 실패 (x509)
x509: cannot validate certificate for <ip> because it doesn't contain any IP SANs
의미:
- kubelet 인증서 SAN 문제로, metrics-server가 strict TLS 검증을 통과 못함
EKS/Managed Node Group 환경에서는 보통 metrics-server에 다음 옵션을 넣어 우회하는 경우가 많습니다(보안 트레이드오프 존재).
# (예시) metrics-server Deployment args
- --kubelet-insecure-tls
- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
> --kubelet-insecure-tls는 “문제를 해결하기 위한 빠른 우회”로는 유효하지만, 가능하면 kubelet 인증서/구성을 정상화하는 방향을 우선 고려하세요.
3단계: kubelet(10250) 접근성 — 네트워크/보안그룹/네트워크폴리시
metrics-server는 각 노드의 kubelet 엔드포인트(기본 10250)로 접근해야 합니다. EKS에서 흔한 함정은 노드 보안그룹(Security Group) 혹은 CNI/네트워크 경로 때문에 kubelet 접근이 막히는 경우입니다.
metrics-server Pod가 어느 노드에서 뜨는지 확인
kubectl -n kube-system get pod -l k8s-app=metrics-server -o wide
metrics-server Pod에서 kubelet 포트 테스트
클러스터에 디버깅용 Pod(예: curl) 하나를 띄우고 노드 IP로 10250 접근을 시도합니다.
# 디버그 파드 실행(권장: ephemeral, 삭제 전제)
kubectl run -it --rm netdebug \
--image=curlimages/curl:8.5.0 \
--restart=Never -- sh
# (파드 내부) 노드 InternalIP로 kubelet 포트 접근
curl -k https://<NODE_INTERNAL_IP>:10250/healthz
timeout이면 네트워크/SG/NACL/라우팅 문제 가능성이 큽니다.401이면 “연결은 되는데 인증이 안 됨”입니다(다음 단계로).
> EKS 네트워킹 이슈는 NodePort/보안그룹/CNI에서 같이 터지는 경우가 많습니다. 유사한 네트워크 점검 흐름은 EKS에서 NodePort만 안 열릴 때 CNI·SG 점검도 참고하세요.
보안그룹 체크 포인트(핵심)
- 노드 SG 인바운드에 “노드 자신/클러스터에서 10250 허용”이 필요한 구조인지 확인
- metrics-server가 노드로 나가는 아웃바운드가 막혀 있지 않은지 확인
- 노드가 여러 SG를 물고 있을 때 “의도치 않은 제한 SG”가 붙어 있지 않은지 확인
EKS는 구성에 따라 control-plane ↔ node 통신 규칙이 자동 구성되지만, 커스텀 SG/추가 SG/사내 보안 정책이 끼면 10250이 막히는 일이 흔합니다.
4단계: RBAC 및 Aggregated API 인증 체인 확인
metrics-server는 aggregated API 형태로 동작합니다.
metrics-server Service/Endpoints 확인
kubectl -n kube-system get svc metrics-server
kubectl -n kube-system get endpoints metrics-server
- endpoints가 비어 있으면 selector/labels 불일치 또는 readiness 문제입니다.
APIService가 metrics-server를 제대로 바라보는지 확인
kubectl get apiservice v1beta1.metrics.k8s.io -o yaml | sed -n '1,120p'
확인할 필드:
spec.service.name: metrics-serverspec.service.namespace: kube-systemstatus.conditions의 메시지
최소 RBAC 점검
설치 매니페스트에 따라 다르지만, 일반적으로 아래가 있어야 합니다.
ClusterRole/ClusterRoleBinding(metrics-server)RoleBinding(kube-system)
빠르게 존재 여부만 확인:
kubectl get clusterrole | grep metrics-server
kubectl get clusterrolebinding | grep metrics-server
RBAC이 깨졌다면 재설치(Helm/manifest 적용)가 가장 빠릅니다.
5단계: 값이 0으로만 보일 때 — “수집은 되는데 표시가 0” 케이스
kubectl top이 0으로만 보이면 다음 가능성이 큽니다.
(1) metrics-server가 일부 노드만 수집 실패
노드별로 수집 상태가 갈리면 kubectl top nodes에서 특정 노드만 0 또는 누락될 수 있습니다.
kubectl top nodes
kubectl describe node <NODE_NAME> | sed -n '1,120p'
이때 metrics-server 로그에 “특정 노드 IP로 timeout”이 찍히는지 확인하세요.
(2) 스케일/부하로 인해 metrics-server가 지연
클러스터가 커지거나(노드/파드 수 증가), metrics-server 리소스가 작으면 간헐적으로 0/timeout이 발생할 수 있습니다.
kubectl -n kube-system top pod -l k8s-app=metrics-server
kubectl -n kube-system describe deploy metrics-server | sed -n '1,200p'
대응:
- metrics-server replica 증가
- CPU/메모리 requests/limits 상향
- (가능하다면) 노드 수/파드 수 대비 적정 sizing 적용
(3) 짧은 실행 파드(Job/CronJob) 특성
아주 짧게 실행되고 끝나는 파드는 metrics가 수집되기 전에 종료되어 top에서 0 또는 미표시처럼 보일 수 있습니다. 이건 장애가 아니라 관측 윈도우의 한계입니다.
6단계: EKS/Bottlerocket 등 노드 접근이 어려울 때의 대안
노드 레벨에서 kubelet 상태/로그를 보고 싶지만, EKS에서 Bottlerocket을 쓰거나 SSH가 막혀 있으면 접근이 난감합니다. 이때는 SSM 기반 접근이 유용합니다.
- Bottlerocket 운영/디버깅 흐름은 EKS Bottlerocket 노드 SSH 없이 SSM으로 접속·디버깅 참고
노드에서 확인하고 싶은 것(가능할 때):
- kubelet 프로세스 상태
- kubelet 인증서/인증 설정
- 노드의 방화벽/iptables 정책(배포 방식에 따라)
7단계: 재설치/정상화 가이드(Helm 예시)
이미 설치돼 있는데 꼬였거나, 옵션 조정이 필요하면 Helm 재적용이 실전에서 가장 안전합니다(버전/옵션 관리가 쉬움).
> 아래는 예시입니다. 실제로는 클러스터 버전과 조직 보안 정책에 맞춰 values를 조정하세요.
helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/
helm repo update
helm upgrade --install metrics-server metrics-server/metrics-server \
-n kube-system \
--set args={--kubelet-preferred-address-types=InternalIP\,Hostname\,InternalDNS\,ExternalDNS\,ExternalIP,--kubelet-insecure-tls}
kubectl -n kube-system rollout status deploy/metrics-server
kubectl get apiservice v1beta1.metrics.k8s.io
kubectl top nodes
--kubelet-preferred-address-types는 노드 주소 선택 이슈(예: ExternalIP로 잡혀서 접근 불가)를 줄이는 데 효과가 큽니다.--kubelet-insecure-tls는 x509 SAN 이슈에서 빠른 해결책이지만, 장기적으로는 TLS 체인을 정상화하는 것이 바람직합니다.
8단계: 최종 체크리스트(원인 → 확인 명령 → 조치)
Metrics API 자체가 없음
- 확인:
kubectl get apiservice | grep metrics,kubectl get --raw "/apis/metrics.k8s.io/v1beta1" - 조치: metrics-server 설치/재설치
APIService가 False
- 확인:
kubectl describe apiservice v1beta1.metrics.k8s.io - 조치: metrics-server Service/Endpoints/인증서 문제 해결
kubelet 접근 불가(10250 timeout)
- 확인: 디버그 파드에서
curl -k https://<node-ip>:10250/healthz - 조치: 노드 SG/NACL/라우팅/CNI 점검
kubelet 인증서(x509) 문제
- 확인: metrics-server 로그의 x509 메시지
- 조치: (단기)
--kubelet-insecure-tls, (장기) kubelet 인증서 SAN 정상화
인증/인가(401/403)
- 확인: metrics-server 로그, RBAC 리소스 존재 여부
- 조치: RBAC/설치 매니페스트 재적용, 인증 체인 점검
수집 지연/리소스 부족
- 확인:
kubectl -n kube-system top pod -l k8s-app=metrics-server - 조치: replica/requests/limits 상향
마무리
EKS에서 kubectl top이 0으로만 보일 때는 “kubectl이 고장”이 아니라, 대부분 metrics-server → kubelet(10250) 수집 경로가 끊겼거나(네트워크/SG), 인증서/인증 체인이 맞지 않거나, metrics-server 자체가 불안정한 경우입니다.
가장 빠른 진단 루트는 아래 3줄입니다.
kubectl get apiservice | grep metrics
kubectl -n kube-system logs deploy/metrics-server --tail=200
kubectl run -it --rm netdebug --image=curlimages/curl:8.5.0 --restart=Never -- sh
여기서 나온 에러 메시지(Timeout vs 401 vs x509)에 따라 네트워크/인증/설치 상태로 가지를 치면, “0%의 원인”을 짧은 시간 안에 확정할 수 있습니다.