Pod가 Pending이면 아직 컨테이너 로그가 없을 수 있습니다. CrashLoopBackOff라면 반복 재시작 전의 종료 사유와 로그를 봐야 해요. 기존 웹 앱을 유지한 채 별도의 실패 예제를 만들고, 상태에 맞춰 확인할 곳을 찾아보겠습니다. 마지막에는 워커 한 대를 비우고 복귀시킵니다.
1. 노드·Pod·이벤트 확인
kubectl get nodes -o wide
kubectl -n lab get deploy,pods,svc,pvc -o wide
kubectl -n lab get events --sort-by=.metadata.creationTimestamp
노드 전체인지 특정 네임스페이스나 Pod에 한정됐는지 먼저 나눕니다. 이벤트는 시간이 지나면 없어지고 컨테이너가 바뀌면 로그 조회 방식도 달라질 수 있어요. 장애 시각과 직전 변경을 함께 남깁니다. 장기 보관이 필요하면 Events와 컨테이너 로그를 중앙 저장소에 보내는 구성을 따로 마련합니다.
| 관찰 | 주요 후보 | 첫 확인 |
|---|---|---|
| Pending | 자원 요청·taint·볼륨·선택 조건 | describe pod의 Events |
| ImagePullBackOff | 이미지 이름·레지스트리·인증·통신 | pull 실패 이벤트 |
| CrashLoopBackOff | 앱 종료·설정·프로브·OOM | logs –previous, lastState |
| Running인데 접속 실패 | readiness·Service selector·정책·DNS | EndpointSlice와 직접 통신 |
| NotReady | kubelet·런타임·CNI·디스크 압박 | describe node와 노드 journal |
2. 잘못된 nodeSelector와 Pending
pending-demo.yaml에는 restricted 환경에서 생성할 수 있는 비특권 조건을 넣었습니다. 배치가 실패하는 이유는 존재하지 않는 노드 레이블입니다. 리소스 부족과 구분해 이벤트를 살펴봅니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: pending-demo
namespace: lab
spec:
replicas: 1
selector:
matchLabels:
app: pending-demo
template:
metadata:
labels:
app: pending-demo
spec:
automountServiceAccountToken: false
nodeSelector:
lab.maruops.com/pool: missing
securityContext:
runAsNonRoot: true
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: sleeper
image: busybox:1.37.0
command: [sh, -c, "sleep 3600"]
resources:
requests:
cpu: 10m
memory: 16Mi
limits:
cpu: 100m
memory: 64Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
kubectl apply -f ~/k8s-lab/app/pending-demo.yaml
kubectl -n lab get pods -l app=pending-demo
kubectl -n lab describe pod -l app=pending-demo
이벤트에서 node selector 또는 affinity 조건을 만족하는 노드가 없다는 설명을 찾습니다. 아직 실행 노드가 정해지지 않았으므로 앱 로그보다 배치 조건을 먼저 봐야 합니다. 여기서는 의도적으로 넣은 조건만 제거합니다. 실제 전용 노드가 필요한 앱이라면 레이블을 없애기보다 배치 설계를 확인해야 합니다.
kubectl -n lab patch deployment pending-demo --type=merge \
-p '{"spec":{"template":{"spec":{"nodeSelector":null}}}}'
kubectl -n lab rollout status deployment/pending-demo --timeout=120s
kubectl -n lab delete deployment pending-demo
3. 종료 사유·이전 로그·디스크
POD=$(kubectl -n lab get pods -l app=web -o jsonpath='{.items[0].metadata.name}')
kubectl -n lab describe pod "$POD"
kubectl -n lab logs "$POD" -c nginx --tail=100
kubectl -n lab get pod "$POD" -o jsonpath='{.status.containerStatuses[*].lastState}'
# 재시작 이력이 있는 컨테이너에만 이전 로그가 존재
# kubectl -n lab logs "$POD" -c nginx --previous --tail=100
종료 코드 137만으로 OOM을 확정하지 않습니다. lastState의 reason, limit, 노드 OOM 기록을 함께 봅니다. liveness로 재시작했다면 이벤트의 프로브 실패도 확인합니다. kubectl top에는 별도의 metrics-server가 필요합니다. kubeadm 기본 설치에 포함되지 않으므로 메트릭 API 오류를 앱 장애와 구분합니다.
# 문제가 있는 해당 노드에서 실행
sudo journalctl -u kubelet -b --since '-30 min' --no-pager
sudo journalctl -u containerd -b --since '-30 min' --no-pager
sudo crictl ps -a
df -h
df -i
용량이 남아도 inode가 차면 파일을 만들 수 없습니다. 로그와 이미지, 볼륨 중 어디가 늘었는지 확인하고 정리합니다. /var/lib/containerd나 /var/lib/etcd 전체를 삭제하면 실행 상태와 복구 자료까지 잃을 수 있습니다.
4. PDB와 drain
먼저 웹 Deployment 복제본이 2이고 두 Pod가 Ready인지 확인합니다. 7편의 단독 volume-check Pod와 8편의 테스트 Pod가 남아 있다면 실습 절차대로 삭제합니다. 아래를 web-pdb.yaml로 저장합니다.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-budget
namespace: lab
spec:
minAvailable: 1
selector:
matchLabels:
app: web
kubectl apply -f ~/k8s-lab/app/web-pdb.yaml
kubectl -n lab get pdb
kubectl -n lab get pods -o wide
kubectl drain wk01 --ignore-daemonsets --timeout=180s
kubectl -n lab get pods -o wide
drain은 노드를 새 배치 대상에서 빼고 일반 Pod를 eviction으로 내보냅니다. DaemonSet은 --ignore-daemonsets로 남깁니다. PDB는 이런 자발적 중단에서 최소 가용 수를 지키는 데 도움을 줍니다. VM 전원 차단이나 디스크 고장을 막는 기능은 아니고, 롤링 업데이트의 가용성 설정도 별도로 관리합니다.
단독 Pod나 emptyDir 때문에 멈추면 소유자와 데이터 용도부터 확인합니다. --force, --delete-emptydir-data를 바로 붙이지 않습니다. local PV 데이터는 다른 워커로 자동 이동하지 않으므로 별도 계획이 필요합니다. 실습에서는 7편의 단독 Pod를 정리한 뒤 진행합니다.
5. 노드 복귀와 앱 응답
# wk01에서 실행
sudo reboot
# cp01에서 wk01이 돌아온 뒤 실행
kubectl wait --for=condition=Ready node/wk01 --timeout=300s
kubectl uncordon wk01
kubectl get nodes
kubectl -n lab get pods -o wide
uncordon은 새 배치를 허용할 뿐, 다른 워커로 옮겨간 Pod를 자동으로 되돌리지는 않습니다. 두 워커가 Ready라면 필요할 때 kubectl -n lab rollout restart deployment/web로 재생성해 분포를 확인할 수 있어요. 노드 복귀와 앱 readiness, Windows의 NodePort 응답을 모두 확인하고 작업을 마칩니다.
참고 자료
공식 문서와 배포 파일 확인 기준: 2026년 10월 18일. 출력은 완료 여부를 판단하기 위한 예시이며 환경별로 달라질 수 있습니다.




답글 남기기