Kubernetes 클러스터에서 이상이 있는 Pod 확인하기
운영 중인 클러스터에서 Error, Pending, CrashLoopBackOff, Init:0/1 같은 비정상 Pod만 빠르게 걸러내는 kubectl 명령어를 정리한다. 핵심 명령어는 Completed 포함과 비포함 두 가지로 제공한다.
[01] STATUS 컬럼의 구성
kubectl get pods의 STATUS 컬럼에는 두 종류의 값이 섞여 있다. 이 차이를 모르면 필터가 의도와 다르게 동작한다.
1-1. phase와 컨테이너 reason
| STATUS 표시 | 실제 정체 |
--field-selector로 잡히나? |
|---|---|---|
Pending |
phase | ✅ |
Running |
phase | ✅ |
Completed |
phase = Succeeded
|
✅ |
Error |
phase = Failed
|
✅ |
CrashLoopBackOff |
컨테이너 reason | ❌ (phase는 Running) |
Init:0/1 |
컨테이너 reason | ❌ (phase는 Pending) |
ImagePullBackOff |
컨테이너 reason | ❌ |
Terminating |
deletionTimestamp 존재 | ❌ |
CrashLoopBackOff, Init:0/1, ImagePullBackOff는 phase가 아니라 컨테이너 reason이다. 그래서 --field-selector=status.phase!=Running으로는 걸러지지 않는다. 가장 흔한 착오다.
이 때문에 텍스트 기반 grep 방식이 실무에서 더 안전하다. 아래에서 두 방법을 모두 다룬다.
[02] 전체 Pod 보기 (기준점)
먼저 모든 네임스페이스의 모든 Pod를 본다.
1
2
# 모든 네임스페이스의 모든 Pod (노드/IP 등 추가 정보 포함)
kubectl get pods -A -o wide
| 옵션 | 의미 |
|---|---|
-A |
--all-namespaces — 전체 네임스페이스 |
-o wide |
NODE, IP, NOMINATED NODE 등 추가 컬럼 표시 |
--sort-by는 정렬만 하고 필터링은 하지 않는다. kubectl get pods -A --sort-by='.status.phase'는 Running을 포함한 모든 Pod를 그대로 보여준다. 문제 Pod만 보려면 아래의 필터링이 필요하다.
[03] 비정상 Pod만 걸러내기
3-1. 케이스 A: Completed 비포함 (정상으로 간주)
CronJob/Job이 정상적으로 끝낸 Completed Pod까지 제외하고 문제 Pod만 보고 싶을 때 쓴다.
1
2
# Running, Completed 둘 다 제외 → 나머지(문제 Pod)만
kubectl get pods -A -o wide | grep -v -E 'Running|Completed'
-
grep -v: 매칭되는 줄을 제외한다 -
Running(정상 동작) +Completed(정상 완료)를 모두 빼므로 →Error,Pending,CrashLoopBackOff,Init,ImagePullBackOff등만 남는다.
단점: -v는 헤더(NAMESPACE NAME ...)줄도 같이 지운다. 헤더를 살리려면 아래 “헤더 보존 버전”을 쓴다.
헤더 보존 + Completed 비포함:
1
2
# 헤더(NAMESPACE)는 남기고, Running/Completed만 제외
kubectl get pods -A -o wide | grep -E 'NAMESPACE|Error|CrashLoopBackOff|Pending|Init|ImagePullBackOff|Terminating|OOMKilled|ErrImagePull'
→ 허용 목록 방식. 헤더인 NAMESPACE와 문제 상태만 통과시킨다. Completed는 목록에 없으므로 제외된다.
3-2. 케이스 B: Completed 포함 (점검 대상)
Completed까지 포함해서 “Running이 아닌 모든 Pod”를 보고 싶을 때 쓴다. 예를 들어 Deployment의 Pod가 Completed로 빠진 비정상 상황까지 잡아내려면 이 방식이 필요하다. [05]를 참고한다.
1
2
# Running만 제외 → Completed 포함 나머지 전부
kubectl get pods -A -o wide | grep -v 'Running'
헤더 보존 + Completed 포함:
1
2
# 헤더는 남기고 Running만 제외
kubectl get pods -A -o wide | grep -v -w 'Running' | grep -E 'NAMESPACE|[A-Za-z]'
또는 더 단순하게, field-selector로 phase 필터:
1
2
# phase가 Running이 아닌 Pod (Completed=Succeeded, Error=Failed, Pending 포함)
kubectl get pods -A -o wide --field-selector=status.phase!=Running
이 field-selector는 phase가 Running인 CrashLoopBackOff를 걸러내지 못한다. 정확히 잡으려면 grep 케이스 B를 쓴다.
[04] 특정 상태만 골라 보기
1
2
3
4
5
6
kubectl get pods -A -o wide | grep CrashLoopBackOff
kubectl get pods -A -o wide | grep -E 'Error|CrashLoopBackOff|ImagePullBackOff'
kubectl get pods -A -o wide | grep Pending
kubectl get pods -A -o wide | grep Init # Init:0/1 등 초기화 멈춤
kubectl get pods -A -o wide | grep Terminating # 종료 안 되고 매달린 Pod
kubectl get pods -A -o wide | grep Completed
phase 기준(정확한 필터):
1
2
3
kubectl get pods -A --field-selector=status.phase=Pending -o wide
kubectl get pods -A --field-selector=status.phase=Failed -o wide # Error
kubectl get pods -A --field-selector=status.phase=Succeeded -o wide # Completed
[05] Completed 상태의 판단 기준
Completed는 상황에 따라 정상일 수도 있고 비정상 상태를 나타낼 수도 있다. 판단 기준은 하나다. 이 Pod가 원래 종료되도록 설계됐는지 확인한다.
| 소유자(Controller) |
Completed의 의미 |
|---|---|
| Job / CronJob | ✅ 정상 (작업 완료, exit 0) |
| Init Container | ✅ 정상 (초기화 후 종료) |
| Deployment / ReplicaSet | ⚠️ 비정상 (계속 실행돼야 하는데 종료됨) |
| StatefulSet / DaemonSet | ⚠️ 비정상 (메인 프로세스가 종료됨) |
소유자 확인 명령어:
1
2
3
# 이 Pod를 누가 만들었는지(소유 컨트롤러 종류) 확인
kubectl get pod <pod-name> -n <namespace> \
-o jsonpath='{.metadata.ownerReferences[0].kind}'
- 결과가
Job이면Completed는 정상이다. - 결과가
ReplicaSet, 즉 Deployment 소유이거나StatefulSet이면Completed는 비정상 신호다. 엔트리포인트가 foreground로 실행되지 않고 종료됐을 가능성이 크다.
CronJob은 successfulJobsHistoryLimit 설정에 따라 성공한 Pod를 남겨둔다. Completed Pod가 여러 개 쌓여 있는 것은 대개 정상이다. 그래서 평소 점검에서는 Completed를 제외하는 케이스 A가 불필요한 출력이 적다.
[06] 문제 Pod 원인 진단
비정상 Pod를 찾았다면 원인을 본다.
1
2
3
4
5
6
7
8
9
10
11
# Events 섹션에서 원인 확인 (스케줄링 실패, 이미지 못 받음 등)
kubectl describe pod <pod-name> -n <namespace>
# 로그 확인
kubectl logs <pod-name> -n <namespace>
# CrashLoopBackOff 디버깅의 핵심 — 이전(크래시된) 컨테이너 로그
kubectl logs <pod-name> -n <namespace> --previous
# 재시작 횟수가 많은 Pod 찾기 (RESTARTS 컬럼 정렬)
kubectl get pods -A --sort-by='.status.containerStatuses[0].restartCount' -o wide
[07] 핵심 요약
| # | 요약 |
|---|---|
| 1 | STATUS 컬럼은 phase(Pending/Running/Succeeded/Failed)와 컨테이너 reason(CrashLoopBackOff/Init 등)이 섞여 있다 |
| 2 |
--field-selector=status.phase!=Running은 CrashLoopBackOff를 놓친다 — phase가 Running이기 때문 |
| 3 | 케이스 A, Completed 비포함: kubectl get pods -A -o wide \| grep -v -E 'Running\|Completed'
|
| 4 | 케이스 B, Completed 포함: kubectl get pods -A -o wide \| grep -v 'Running'
|
| 5 |
--sort-by는 정렬만 할 뿐 Running을 걸러주지 않는다. 필터링은 grep이나 field-selector로 한다 |
| 6 |
Completed가 정상인지는 소유 컨트롤러로 판단 — Job/CronJob이면 정상, Deployment/StatefulSet이면 의심 |
가장 자주 쓰는 한 줄은 kubectl get pods -A -o wide | grep -v -E 'Running|Completed' 이다. 정상이 아닌 모든 Pod를 한 번에 확인한다.