285. Troubleshooting - Section Introduction

Kubernetes 트러블슈팅의 기본 원칙

“문제 층위를 위에서 아래로 좁혀 내려간다”

Kubernetes는 여러 층이 겹친 구조이기 때문에, 증상만 보면 어디가 원인인지 헷갈림.

[사용자 요청] → [Ingress] → [Service] → [Pod] → [Container] → [Application]
                                  ↓
                               [Node (kubelet)]
                                  ↓
                         [Control Plane (API Server)]

원칙:

  1. 증상 확인 (뭐가 안 되나?) → Pod 안 뜸? Service 응답 없음? API Server 다운?
  2. 위에서 아래로 내려가며 확인 — describelogs → 시스템 로그
  3. Events 섹션을 먼저 본다 (kubectl describe의 핵심)
  4. 이벤트는 시간 순 정렬 (--sort-by=.lastTimestamp)

분류:

  • 애플리케이션 장애 (Application Failure)
  • 컨트롤 플레인 장애 (Control Plane Failure)
  • 워커 노드 장애 (Worker Node Failure)
  • 네트워크 트러블슈팅

286-288. Application Failure

공식문서: Debug Pods / Debug Services

트러블슈팅 접근 순서

  1. 사용자 접근 불가
  2. Service 확인 — Endpoints 연결됐는지
  3. Pod 상태 확인 — Running? Restarts?
  4. Pod 로그 확인kubectl logs
  5. Pod 상세 확인kubectl describe pod
  6. Deployment 확인 — 레플리카, 이미지, 셀렉터

Service → Pod 연결 확인

# Service 확인
kubectl get svc
kubectl describe svc web-service
# Endpoints 항목이 있어야 함 → 없으면 selector 불일치
 
# Pod 라벨 vs Service selector 비교
kubectl get pod --show-labels
kubectl get svc web-service -o yaml | grep selector -A5
 
# Service에서 직접 curl 테스트
kubectl run tmp --image=busybox --rm -it -- wget -qO- http://web-service:80

Pod 상태별 트러블슈팅

상태원인확인 방법
Pending스케줄링 실패 (리소스 부족, NodeSelector 불일치)kubectl describe pod → Events
CrashLoopBackOff컨테이너 반복 재시작kubectl logs --previous
ImagePullBackOff이미지 없음 / 인증 실패이미지 이름/태그 확인, imagePullSecrets
OOMKilled메모리 초과resources.limits 확인/조정
Error컨테이너 실행 오류kubectl logs 확인
# Pod 로그 확인
kubectl logs <pod-name>
kubectl logs <pod-name> -c <container-name>   # 멀티 컨테이너
kubectl logs <pod-name> --previous            # 재시작 전 로그
 
# Pod 상세 확인 (Events 섹션이 핵심)
kubectl describe pod <pod-name>
 
# Pod 내부 접속
kubectl exec -it <pod-name> -- /bin/sh
 
# 환경 변수 확인
kubectl exec <pod-name> -- env
 
# ConfigMap / Secret 마운트 확인
kubectl exec <pod-name> -- cat /etc/config/my-key

일반적인 실수 패턴

# 1. Service selector와 Pod label 불일치
#    Service: selector: app=web
#    Pod: labels: app=webapp  ← 다름!
 
# 2. 잘못된 Service 포트 매핑
#    Service: port: 80, targetPort: 8080
#    컨테이너: containerPort: 80  ← targetPort가 틀림
 
# 3. 잘못된 ConfigMap/Secret 참조
kubectl get configmap
kubectl describe configmap <name>

289-291. Control Plane Failure

컨트롤 플레인 컴포넌트 확인

# 노드 상태 확인
kubectl get nodes
 
# 컨트롤 플레인 파드 상태 (kubeadm 환경)
kubectl get pods -n kube-system
 
# Static Pod 매니페스트 확인
ls /etc/kubernetes/manifests/
cat /etc/kubernetes/manifests/kube-apiserver.yaml
cat /etc/kubernetes/manifests/kube-controller-manager.yaml
cat /etc/kubernetes/manifests/kube-scheduler.yaml
cat /etc/kubernetes/manifests/etcd.yaml

컴포넌트별 로그 확인

# kubeadm 환경 (파드로 실행)
kubectl logs kube-apiserver-master -n kube-system
kubectl logs kube-controller-manager-master -n kube-system
kubectl logs kube-scheduler-master -n kube-system
kubectl logs etcd-master -n kube-system
 
# 바이너리로 실행되는 환경 (서비스로 실행)
sudo journalctl -u kube-apiserver -f
sudo journalctl -u kube-controller-manager -f
sudo journalctl -u kube-scheduler -f
 
# 컨테이너 런타임으로 직접 확인
sudo crictl ps | grep -E "apiserver|controller|scheduler|etcd"
sudo crictl logs <container-id>

kube-apiserver 장애 시

# API Server가 죽으면 kubectl 자체가 안 됨
# → 마스터 노드에 직접 SSH 접속하여 확인
 
# Static Pod 매니페스트 문제 확인
sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml
 
# 인증서 만료 확인
sudo openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout | grep "Not After"
 
# etcd 연결 확인 (--etcd-servers 옵션)
sudo grep etcd /etc/kubernetes/manifests/kube-apiserver.yaml

etcd 상태 확인

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
 
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 \
  member list

292-294. Worker Node Failure

공식문서: Troubleshooting Nodes

워커 노드 상태 확인

# 노드 상태 확인
kubectl get nodes
kubectl describe node <node-name>
# → Conditions 섹션 확인 (Ready / MemoryPressure / DiskPressure / PIDPressure)

Node Conditions

ConditionTrue 의미원인
Ready노드 정상-
MemoryPressure메모리 부족메모리 확보 필요
DiskPressure디스크 부족디스크 정리 필요
PIDPressure프로세스 과다프로세스 정리 필요
Unknown마스터와 통신 끊김kubelet/네트워크 확인

워커 노드 SSH 접속 후 확인

# kubelet 상태 확인 (가장 중요!)
sudo systemctl status kubelet
sudo journalctl -u kubelet -f
sudo journalctl -u kubelet --since "10 minutes ago"
 
# kubelet 재시작
sudo systemctl restart kubelet
sudo systemctl enable kubelet
 
# kubelet 설정 파일 확인
cat /var/lib/kubelet/config.yaml
sudo cat /etc/kubernetes/kubelet.conf   # kubeconfig
 
# 인증서 만료 확인
sudo openssl x509 -in /var/lib/kubelet/pki/kubelet.crt -text -noout | grep "Not After"
 
# 컨테이너 런타임 상태
sudo systemctl status containerd
sudo crictl ps
sudo crictl info
 
# 시스템 리소스 확인
free -h          # 메모리
df -h            # 디스크
top              # CPU/프로세스

노드 강제 복구

# 노드 드레인 (워크로드 이동)
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
 
# 노드 유지보수 모드 해제
kubectl uncordon <node-name>
 
# 노드를 스케줄링 불가로 표시 (drain 없이)
kubectl cordon <node-name>

295-296. Network Troubleshooting

CNI 플러그인 확인

# CNI 설정 파일 확인
ls /etc/cni/net.d/
cat /etc/cni/net.d/10-flannel.conflist   # Flannel 예시
 
# CNI 바이너리 확인
ls /opt/cni/bin/
 
# CNI 플러그인 파드 상태 (DaemonSet)
kubectl get pods -n kube-system | grep -E "weave|calico|flannel|cilium"
kubectl logs -n kube-system <cni-pod-name>

kube-proxy 확인

# kube-proxy 파드 상태
kubectl get pods -n kube-system | grep kube-proxy
kubectl logs -n kube-system <kube-proxy-pod>
 
# kube-proxy ConfigMap 확인
kubectl get configmap kube-proxy -n kube-system -o yaml
 
# iptables 규칙 확인
sudo iptables -t nat -L KUBE-SERVICES -n | head -20
sudo iptables -t nat -L | grep <service-ip>

CoreDNS 확인

# CoreDNS 파드 상태
kubectl get pods -n kube-system | grep coredns
kubectl logs -n kube-system -l k8s-app=kube-dns
 
# CoreDNS ConfigMap 확인
kubectl get configmap coredns -n kube-system -o yaml
 
# DNS 해석 테스트
kubectl run dns-test --image=busybox --rm -it -- nslookup kubernetes
kubectl run dns-test --image=busybox --rm -it -- nslookup <service-name>.<namespace>

Pod 간 통신 테스트

# Pod IP 확인
kubectl get pods -o wide
 
# Pod에서 직접 curl
kubectl exec <pod-a> -- curl http://<pod-b-ip>:8080
kubectl exec <pod-a> -- wget -qO- http://<service-name>:<port>
 
# 네트워크 정책 확인
kubectl get networkpolicy
kubectl describe networkpolicy <name>
 
# 특정 포트 연결 확인
kubectl exec <pod-name> -- nc -zv <target-ip> <port>

트러블슈팅 종합 체크리스트

  1. 문제 발생kubectl이 동작하는가?
    • NoAPI Server 확인: /etc/kubernetes/manifests/, journalctl -u kube-apiserver
    • Yes → 다음 단계
  2. 노드 상태? (kubectl get nodes)
    • NotReadykubelet 확인: systemctl status kubelet, journalctl -u kubelet
    • Ready → 다음 단계
  3. Pod 상태? (kubectl get pods)
    • CrashLoop / Errorkubectl logs, kubectl describe pod
    • Running → 다음 단계
  4. 서비스 접근 불가?
    • Service / Endpoint 확인 → kube-proxy / CNI 확인 → DNS 확인