1 · 애플리케이션
Pod 자체의 문제.
describe → logs → -o yaml
배점 30% — 앞의 모든 장이 재료다
고치려 하지 말고, 먼저 “어느 층에서 끊겼는지”를 확정하라.
클러스터는 결국 선언된 상태(spec)를 실제 상태(status)로 맞추는 루프들의 모음이다 (시작하기 전에). 고장이란 그 루프가 어딘가에서 멈춘 것이고, 층을 가른다는 건 멈춘 지점이 루프의 어느 구간인지를 좁히는 일이다. 선언이 API 서버에 들어가고 → 컨트롤러·스케줄러가 그것을 읽어 결정하고 → kubelet이 노드에서 실행하고 → 런타임·CNI(Container Network Interface, Pod 네트워크)· CSI(Container Storage Interface, 볼륨 연결)가 실제로 만들어 내는 사슬에서, 층은 그 사슬을 끊어 보는 눈금이다.
층은 넷이다.
1 · 애플리케이션
Pod 자체의 문제.
describe → logs → -o yaml
2 · 노드
kubelet, 런타임, 자원.
journalctl -u kubelet, df -h
3 · 컨트롤 플레인
API 서버, 스케줄러, 컨트롤러, etcd.
crictl ps -a, 매니페스트
4 · 네트워크
Service, DNS, CNI, 정책.
get endpoints, nslookup
각 층은 확인 명령이 다르다. 층을 잘못 짚으면 엉뚱한 곳을 파게 된다. 시험에서는 이 판별이 곧 시간이다.
층을 정하는 질문은 셋, 치는 명령은 두 줄이다.
kubectl get nodes # Q1 · Q2kubectl get pods -A | grep -vE 'Running|Completed' # Q3| 상황 | 도구 |
|---|---|
| 왜 안 뜨는가 | kubectl describe → Events |
| 앱이 무슨 말을 하는가 | kubectl logs, logs --previous |
| 시간순으로 무슨 일이 있었나 | kubectl get events --sort-by=.lastTimestamp |
| 정확한 값이 뭔가 | kubectl get ... -o yaml |
| 자원을 얼마나 쓰나 | kubectl top, describe node |
| 안에서 확인하고 싶다 | kubectl exec, kubectl debug, 임시 Pod |
| kubectl이 안 될 때 | crictl(컨테이너 런타임 직접 조회 CLI), journalctl -u kubelet(kubelet의 systemd 서비스 로그) |
| 노드 자체 | systemctl status, df -h, free -m, dmesg |
순서가 중요하다.
describe(Events) → logs → -o yaml.
로그부터 보면 스케줄링·볼륨·이미지 문제는 아무것도 안 나온다.
막혔을 때 시험 중에 열어 볼 곳도 정해져 있다 — 공식
Monitoring, Logging, and Debugging 문서가
애플리케이션/클러스터 갈래로 이 장과 같은 층 구분을 쓴다.
루프가 끝까지 돌긴 했는데 마지막 한 걸음에서 걸린 경우다 — 스케줄러는 노드를 정했고 kubelet도 만들라는 지시를 받았다. Pod의 STATUS는 그 마지막 걸음이 어디서 멈췄는지 알려 주는 눈금이라, 상태 이름만 읽어도 다음에 칠 명령이 정해진다.
STATUS를 보는 순간 다음 명령이 정해져야 한다.
| STATUS | 층 | 첫 명령 |
|---|---|---|
Pending | 스케줄링 | describe pod → Events |
ContainerCreating | 볼륨/네트워크 | describe pod → Events |
ImagePullBackOff | 이미지 | describe pod → Events |
CrashLoopBackOff | 앱 | logs --previous |
Error | 앱 | logs, exit code |
OOMKilled | 리소스 | describe pod → Last State |
CreateContainerConfigError | 설정 | describe pod → ConfigMap/Secret |
Running 인데 0/1 | readinessProbe | describe pod → Events |
Terminating 지속 | finalizer / 노드 | get pod -o yaml |
Completed 반복 | restartPolicy | Job 여부 확인 |
kubectl describe pod web | grep -A20 EventsEvents 메시지 하나가 원인을 그대로 지목한다.
| 메시지 | 원인 | 조치 |
|---|---|---|
Insufficient cpu/memory | request 여유 부족 | request 낮추거나 노드 추가 |
had untolerated taint | taint | toleration 추가 또는 taint 제거 |
didn't match node affinity/selector | 라벨 불일치 | 노드에 라벨 추가 또는 셀렉터 수정 |
node(s) were unschedulable | cordon | kubectl uncordon |
unbound immediate PersistentVolumeClaims | PVC 미바인딩 | 스토리지 진단 |
didn't match pod anti-affinity rules | antiAffinity | 스케줄링 |
| Events 자체가 없다 | 스케줄러가 죽었다 또는 schedulerName 오타 | 컨트롤 플레인 확인 |
kubectl describe node node01 | grep -A8 'Allocated resources'kubectl get nodes # SchedulingDisabled 표시kubectl describe pod web | grep -A5 Events# Failed to pull image "nginx:1.99": rpc error: ... not found| Events 내용 | 원인 |
|---|---|
not found / manifest unknown | 이미지 이름·태그 오타 |
unauthorized / authentication required | imagePullSecrets 없음 |
dial tcp: i/o timeout | 네트워크·레지스트리 접근 불가 |
no such host | 레지스트리 도메인 해석 실패 |
# 이미지 이름이 맞는지 확인kubectl get pod web -o jsonpath='{.spec.containers[*].image}'
# 노드에서 직접 받아보기sudo crictl pull nginx:1.27
# 고치기kubectl set image deploy/web nginx=nginx:1.27kubectl logs web --previous # ★ 죽기 직전 로그kubectl describe pod web | grep -A15 'Last State'# Last State: Terminated# Reason: Error# Exit Code: 1exit code 하나로 절반이 좁혀진다.
| Exit Code | 의미 | 다음 행동 |
|---|---|---|
0 | 정상 종료했는데 restartPolicy: Always | 명령이 즉시 끝난다 — sleep이 필요하거나 Job이어야 한다 |
1, 2 | 앱 에러 | 로그를 읽는다 |
126 | 실행 권한 없음 | command 경로·권한 |
127 | 명령을 못 찾음 | command 오타 또는 이미지에 그 바이너리가 없다 |
137 | SIGKILL | OOMKilled 또는 liveness 실패로 강제 종료 |
143 | SIGTERM | 정상 종료 신호 |
OOM(Out of Memory — 메모리 한도 초과)으로 커널이 컨테이너를 강제 종료한 상태다.
kubectl describe pod web | grep -A8 'Last State'# Last State: Terminated# Reason: OOMKilled# Exit Code: 137kubectl top pod web --containers # 실제 사용량kubectl get pod web -o jsonpath='{.spec.containers[0].resources}'조치 순서
kubectl top으로 실제 사용량을 본다
limits.memory를 실사용의 1.5~2배로 올린다
그래도 계속 오르면 앱의 메모리 누수다 — 인프라 문제가 아니다
둘은 다른 사건이다.
kubectl describe pod web | grep -A20 Events| 메시지 | 원인 |
|---|---|
MountVolume.SetUp failed ... not found | ConfigMap/Secret이 없다 |
Unable to attach or mount volumes | PV/CSI 문제 (스토리지 진단) |
Multi-Attach error | RWO 볼륨을 두 노드에서 |
failed to create pod sandbox ... cni | CNI 문제 |
network plugin is not ready | CNI Pod이 안 떴다 |
Multi-Attach error는 RWO(ReadWriteOnce — 한 번에 한 노드에서만 마운트할 수 있는
접근 모드) 볼륨을 쓰는 Pod이 다른 노드로 옮겨 갈 때 잘 나온다. 옛 Pod이 완전히 사라져
볼륨이 detach될 때까지 새 Pod은 계속 ContainerCreating에 머문다 (스토리지 진단).
# 볼륨 관련kubectl get cm,secret -n <ns>kubectl get pvc,pv
# CNI 관련kubectl get pods -n kube-system | grep -Ei 'calico|cilium|flannel'ls /etc/cni/net.d/sudo journalctl -u kubelet | grep -i cni | tail -20kubectl get pods# NAME READY STATUS RESTARTS AGE# web 0/1 Running 0 3m
kubectl describe pod web | grep -A10 Events# Warning Unhealthy Readiness probe failed: HTTP probe failed with statuscode: 404컨테이너는 살아 있는데 Service에서 빠진다. 그래서 “연결이 안 된다”로 보인다.
# 프로브 설정 확인kubectl get pod web -o jsonpath='{.spec.containers[0].readinessProbe}'
# 안에서 직접 호출해본다kubectl exec -it web -- wget -qO- http://localhost:8080/healthzkubectl get pod web -o yaml | grep -A5 finalizerskubectl get ns stuck -o yaml | grep -A5 finalizers삭제는 즉시 지우는 게 아니라 “지워도 좋다”는 표식을 남기는 일이다.
오브젝트에 finalizer(삭제 전에 끝내야 할 정리 작업을 표시해 둔 문자열 목록 — CRD)가
하나라도 남아 있으면 API 서버는 실제 삭제를 미룬다. 그 표식을 지워 줄 컨트롤러가
죽어 있으면 아무도 지워 주지 않아 영원히 Terminating에 머문다.
| 원인 | 조치 |
|---|---|
| finalizer가 남아 있고 처리할 컨트롤러가 없다 | finalizer 제거 |
| 노드가 unreachable | 노드 복구 또는 강제 삭제 |
preStop 훅이 안 끝난다 | grace period 확인 (종료 유예 시간, 기본 30초) |
# Pod 강제 삭제kubectl delete pod web --force --grace-period=0
# finalizer 제거kubectl patch pod web -p '{"metadata":{"finalizers":null}}' --type=merge
# 네임스페이스가 Terminating에서 안 끝날 때kubectl get ns stuck -o json \ | jq '.spec.finalizers = []' \ | kubectl replace --raw "/api/v1/namespaces/stuck/finalize" -f -마지막 /finalize 호출은 정리를 건너뛰고 표식만 떼어 내는 최후의 수단이다.
원인(아래 함정의 죽은 APIService 등)을 그대로 두면 다음 네임스페이스에서 또 걸린다.
시험에서 이 한 줄까지 필요한 경우는 흔치 않으니, 외우기보다 원인부터 본다는 순서를
기억해 두는 편이 낫다.
층을 좁혔으면 다음은 증거다. 상태(STATUS·Conditions)는 루프가 어디서 멈췄는지까지만
알려 주고, 왜 멈췄는지는 로그와 사용량 숫자에 있다. 이 절은 그 증거를 어디서 꺼내는지,
그리고 kubectl이 죽었을 때 같은 증거를 노드에서 어떻게 찾는지를 다룬다.
kubectl logs webkubectl logs web -c sidecar # 멀티 컨테이너kubectl logs web --previous # 이전 컨테이너kubectl logs web -f --tail=100kubectl logs web --since=15m --timestampskubectl logs -l app=web --all-containers --prefix --max-log-requests=10kubectl logs deploy/web # 컨트롤러 지정kubectl logs job/import로그가 어디를 거쳐 오는지 알면 kubectl이 죽었을 때 어디를 봐야 하는지도 안다.
/var/log/pods/<ns>_<pod>_<uid>/<container>/0.log/var/log/containers/ 는 거기로 향하는 심볼릭 링크다# kubectl이 안 될 때 노드에서 직접sudo ls /var/log/containers/sudo tail -f /var/log/containers/kube-apiserver-*.logsudo crictl logs <container-id>kubectl top nodeskubectl top pods -A --sort-by=memorykubectl top pod web --containers
kubectl describe node node01 | grep -A10 'Allocated resources'kubectl get pods -A -o wide --field-selector spec.nodeName=node01# 노드에서 직접df -h # 디스크free -m # 메모리top # CPUsudo journalctl -u kubelet | grep -i evictkubelet은 루프의 실행 담당이자 보고 담당이다. 노드가 NotReady라는 건 실행이
멈췄거나 보고가 끊겼다는 뜻이고, 보고가 끊기면 API 서버가 아는 상태 자체를 믿을 수 없게
된다. 그래서 이 층부터는 kubectl이 아니라 노드에 들어가 systemd 로그를 읽는 쪽이
정답에 가깝다.
kubectl get nodeskubectl describe node node01 | grep -A15 Conditions| Condition | 원인 |
|---|---|
Ready: False, KubeletNotReady, cni plugin not initialized | CNI 미설치/고장 |
Ready: Unknown, NodeStatusUnknown | kubelet이 보고를 멈췄다 |
MemoryPressure: True | 메모리 부족 → 축출 시작 |
DiskPressure: True | 디스크 부족 → 이미지 GC, 축출 |
PIDPressure: True | 프로세스 수 초과 |
# 노드에 들어가서ssh node01sudo systemctl status kubeletsudo journalctl -u kubelet -n 100 --no-pager # ★ 여기에 이유가 있다sudo systemctl status containerddf -h /var/lib/kubelet /var/lib/containerdfree -msudo swapon --show # 스왑이 켜졌나sudo systemctl status kubeletsudo journalctl -u kubelet -n 50 --no-pager| 로그 메시지 | 원인 | 조치 |
|---|---|---|
failed to run Kubelet: running with swap on | 스왑 | swapoff -a |
misconfiguration: kubelet cgroup driver ... != ... | cgroup 드라이버 불일치 | containerd SystemdCgroup = true |
x509: certificate has expired | 인증서 만료 | kubeadm certs renew |
Unable to register node ... connection refused | API 서버가 죽었다 | 컨트롤 플레인을 본다 |
open /var/lib/kubelet/config.yaml: no such file | 설정 파일 없음 | kubeadm 재초기화 필요 |
failed to load kubelet config file | YAML 문법 오류 | 파일을 되돌린다 |
sudo systemctl restart kubeletsudo systemctl enable kubelet # 부팅 시 자동 시작sudo systemctl daemon-reload # 설정 파일을 바꿨다면루프를 도는 주체들이 죽은 경우다. 선언은 받아도(혹은 그마저 못 받고) 아무도 그것을
읽고 행동하지 않으니, 증상은 “명령은 되는데 아무 일도 안 일어난다” 또는 “명령 자체가
안 된다”로 나온다. 여기서는 kubectl이 도구가 아니라 진단 대상이므로
crictl과 journalctl로 내려간다 (확장).
kubectl get nodes# The connection to the server 192.168.1.10:6443 was refused순서대로 확인한다.
kubeconfig가 맞는가
kubectl config current-contextls -l ~/.kube/configkubectl cluster-infoAPI 서버 컨테이너가 도는가 — ★ 컨트롤 플레인 노드에서
sudo crictl ps -a | grep kube-apiserver죽었다면 왜 죽었는가
sudo crictl logs $(sudo crictl ps -a --name kube-apiserver -q | head -1)kubelet이 매니페스트를 읽고 있는가
sudo journalctl -u kubelet -n 50 --no-pager | grep -i apiserver매니페스트 자체 확인
sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml아래가 죽으면 위가 전부 죽는다. 그래서 고치는 순서가 정해진다.
etcd가 죽으면 API 서버도 못 뜬다. API 서버 로그에 etcd 관련 에러가 있으면 etcd부터 고쳐야 한다. 위에서부터 고치려 들면 시간만 버린다.
| 원인 | 증상 | 조치 |
|---|---|---|
| 매니페스트 YAML 문법 오류 | 컨테이너가 아예 안 생긴다 | journalctl -u kubelet에 파싱 에러 |
| 잘못된 플래그 | 컨테이너가 즉시 죽는다 | crictl logs에 unknown flag |
| etcd에 못 붙는다 | connection refused 반복 | etcd 컨테이너 확인 |
| 인증서 만료/경로 오류 | x509 에러 | kubeadm certs check-expiration |
| 포트 충돌 | bind: address already in use | 6443을 쓰는 프로세스 확인 |
sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/backup.yaml # 먼저 백업sudo vim /etc/kubernetes/manifests/kube-apiserver.yamlwatch sudo crictl ps # 다시 뜨는지 지켜본다증상이 다르다. 이 비대칭이 판별의 실마리다.
| 죽은 것 | 증상 |
|---|---|
| kube-scheduler | 새 Pod이 영원히 Pending. Events가 비어 있다 |
| kube-controller-manager | Deployment를 만들어도 ReplicaSet/Pod이 안 생긴다. kubelet이 죽은 노드가 NotReady/Unknown으로 전환되지 않는다 (노드 status 자체는 kubelet이 갱신한다) |
kubectl get pods -n kube-system | grep -E 'scheduler|controller'kubectl logs -n kube-system kube-scheduler-controlplanesudo crictl ps -a | grep -E 'scheduler|controller'sudo cat /etc/kubernetes/manifests/kube-scheduler.yaml# 스케줄러가 죽은 상태에서 Pod을 띄워야 한다면kubectl run web --image=nginx --dry-run=client -o yaml > pod.yaml# spec.nodeName: node01 을 추가한 뒤kubectl apply -f pod.yaml컨트롤 플레인 컴포넌트의 로그는 kubectl logs -n kube-system으로 볼 수 있다
— API 서버가 살아 있을 때만. 아니면 crictl logs.
sudo crictl ps -a | grep etcd# etcd-controlplane은 Pod 이름이다. logs에는 -q가 낸 컨테이너 ID를 넘긴다.sudo crictl logs $(sudo crictl ps -a --name etcd -q | head -1) 2>&1 | tail -30
sudo ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key \ endpoint health --clusterx509: certificate signed by unknown authority는 로그를 낸 주체가 상대 인증서를
자신의 CA로 검증하지 못했다는 뜻이다. 메시지 한 줄만으로는 인증서를 제시한 쪽과
CA를 설정한 쪽 중 어느 파일이 바뀌었는지 확정할 수 없다. 로그 주체 → 접속 대상 →
인증서·CA 한 쌍 순으로 좁힌다.
| 로그 주체·문맥 | 실패한 검증 | 대조할 한 쌍 |
|---|---|---|
kube-apiserver 로그의 127.0.0.1:2379 연결 | API 서버가 etcd 서버 인증서를 검증 | etcd --cert-file ↔ API 서버 --etcd-cafile |
| etcd 로그의 client certificate 거부 | etcd가 API 서버의 클라이언트 인증서를 검증 | API 서버 --etcd-certfile ↔ etcd --trusted-ca-file |
kubectl의 API 서버 인증서 거부 | kubectl이 API 서버 인증서를 검증 | API 서버 --tls-cert-file ↔ kubeconfig의 cluster CA |
API 서버의 --client-ca-file은 kubectl·kubelet 등 API로 들어오는 클라이언트
인증서를 검증한다. API 서버가 etcd에 나가는 연결에서 쓰는 --etcd-cafile과
혼동하지 않는다.
| 증상 | 원인 |
|---|---|
database space exceeded | 쿼터 초과 → compact + defrag 필요 |
no leader / context deadline exceeded | 과반이 안 산다 — 멤버를 확인 |
API 서버 로그의 etcdserver: request timed out | etcd가 느리다 (디스크 I/O) |
| 데이터 디렉터리 권한 오류 | 복구 후 chown 누락 (etcd 백업과 복구) |
database space exceeded는 etcd가 오브젝트의 옛 리비전을 계속 쌓다 쿼터에 닿은
상태다 — 오래된 리비전을 잘라내고(compact) 빈 공간을 되돌려받아야(defrag) 쓰기가
다시 열린다. 이쪽 운영 작업까지 깊게 팔 필요는 없다. etcd에서 시험의 본론은
etcd 백업과 복구의 백업·복구이고, 여기서는 “API 서버가 이상하면 etcd 로그부터 본다”는 습관이면 된다.
여기는 루프가 이미 다 돌아간 뒤의 문제다 — 선언대로 Pod이 떠 있고 상태도 정상인데
패킷만 안 간다. kubectl get으로는 다 정상으로 보이기 때문에, 상태를 읽는 대신
실제로 요청을 쏘아 보며 한 겹씩 벗기는 방식으로 바뀐다.
한 겹씩 벗긴다. 처음 실패하는 겹이 곧 원인이다.
# ① 앱이 포트를 열었는가kubectl exec -it web -- wget -qO- http://localhost:8080
# ② Pod IP로 직접kubectl get pod web -o widekubectl run tmp --image=busybox:1.36 --rm -it --restart=Never -- wget -qO- http://10.244.1.5:8080
# ③ Service(ClusterIP)로 — 실소스는 EndpointSlice, get endpoints 는 요약 조회다 (v1.33+ 에선 deprecated 경고)kubectl get endpoints web-svc # ★ 비어 있으면 여기가 문제kubectl run tmp --image=busybox:1.36 --rm -it --restart=Never -- wget -qO- http://web-svc:80
# ④ DNS로kubectl run tmp --image=busybox:1.36 --rm -it --restart=Never -- nslookup web-svc
# ⑤ 외부에서curl http://<노드IP>:30080kubectl describe ingress web| 증상 | 원인 후보 | 확인 |
|---|---|---|
| 엔드포인트가 비어 있다 | 라벨 불일치 / Pod 미Ready | describe svc, get pods --show-labels |
| ClusterIP만 안 된다 | kube-proxy 문제 | kubectl get ds kube-proxy -n kube-system |
| 이름만 안 된다 | CoreDNS | nslookup kubernetes.default |
| 특정 Pod끼리만 안 된다 | NetworkPolicy | kubectl get netpol -A |
| 노드 간 Pod 통신이 안 된다 | CNI | CNI Pod 상태, /etc/cni/net.d/ |
| 외부에서만 안 된다 | NodePort 범위 / 방화벽 / LB | describe svc |
| Ingress에서 404 / 503 | 규칙·백엔드 Service | describe ingress, 컨트롤러 로그 |
| egress가 전부 안 된다 | NetworkPolicy의 DNS 미허용 | NetworkPolicy |
kube-proxy가 죽으면 Pod-to-Pod 직접 통신은 정상이고 ClusterIP만 죽는다. 이 비대칭이 판별의 실마리다.
층 판별이 잘 안 먹는 두 부류다. 인증서와 노드 압박은 한 층에서 시작해 다른 층의 증상으로
나타난다 — 만료된 인증서 하나가 kubelet(노드 층)과 kubectl(컨트롤 플레인 층)을 동시에
무너뜨리고, 디스크가 차면 앱이 축출된다(애플리케이션 층). 층별 확인이 서로 어긋난다 싶으면
이 둘을 의심한다.
sudo kubeadm certs check-expiration
# 개별 인증서 확인sudo openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text | grep -A2 Validitysudo openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text | grep -A3 'Subject Alternative Name'| 에러 | 원인 |
|---|---|
x509: certificate has expired | 만료 → kubeadm certs renew all |
x509: certificate signed by unknown authority | CA 불일치 — 로그 주체와 접속 대상을 먼저 확인한 뒤 인증서·CA 쌍을 대조 |
x509: cannot validate certificate for <IP> | SAN에 그 IP가 없다 |
Unauthorized (401) | 토큰/인증서가 유효하지 않다 |
sudo kubeadm certs renew all# 컨트롤 플레인 Pod 재시작 (매니페스트를 잠시 옮겼다 되돌린다)sudo mv /etc/kubernetes/manifests /tmp/m && sleep 20 && sudo mv /tmp/m /etc/kubernetes/manifests
# admin.conf도 갱신되었으므로 다시 복사sudo cp /etc/kubernetes/admin.conf ~/.kube/configsudo chown $(id -u):$(id -g) ~/.kube/configkubectl get pods -A --field-selector status.phase=Failedkubectl get events -A --field-selector reason=Evictedkubectl describe node node01 | grep -A5 ConditionsFailed 상태로 남는다. 상위 컨트롤러가 새로 만든다왼쪽부터 축출된다. Guaranteed가 가장 오래 버틴다.
# 노드에서 공간 확보sudo crictl rmi --prune # 안 쓰는 이미지 삭제sudo journalctl --vacuum-size=200M # 저널 정리df -h /var/lib/containerd /var/log
# 축출된 Pod 정리kubectl delete pods --field-selector status.phase=Failed -A| 문제 | 진단 경로 | 조치 |
|---|---|---|
| 노드 하나가 NotReady | journalctl -u kubelet | 스왑/cgroup/서비스 재시작 |
| 앱이 계속 재시작 | logs --previous + exit code | limit 상향 또는 command 수정 |
| Service 연결 실패 | get endpoints | 라벨 수정 / probe 수정 |
| 이름 해석 실패 | nslookup kubernetes.default | CoreDNS 확인 |
| Pod이 계속 Pending | describe pod Events | taint/affinity/자원/PVC |
kubectl이 죽었다 | crictl ps -a | 매니페스트 복구 |
| 클러스터를 되돌려야 한다 | etcd 스냅샷 | restore + etcd.yaml 수정 |
| 특정 사용자만 403 | 에러 메시지 | RoleBinding 추가 |
# 층별 검증kubectl get nodes # 전부 Readykubectl get pods -A | grep -vE 'Running|Completed' # 비정상 Pod 없음kubectl get events -A --sort-by=.lastTimestamp | tail -20
# 대상 리소스 직접 확인kubectl rollout status deploy/webkubectl get endpoints web-svckubectl wait --for=condition=ready pod -l app=web --timeout=60s
# 실제로 동작하는지kubectl run tmp --image=busybox:1.36 --rm -it --restart=Never -- wget -qO- http://web-svcget nodes 응답 · 전부 Ready · get pods -A 정상), 명령은 두 줄describe(Events) → logs → -o yaml. 로그부터 보면 안 되는 문제가 많다logs --previous 와 get events --sort-by 가 두 기둥0=명령이 끝남, 127=명령 없음, 137=OOM/강제종료Running 0/1 = readinessProbe 실패 → 엔드포인트에서 빠진다crictl + journalctl -u kubelet/etc/kubernetes/manifests/의 값 하나