Post

Part 22/26: 트러블슈팅 체크리스트

Part 22/26: 트러블슈팅 체크리스트

Kubernetes 트러블슈팅은 체계적인 접근이 필요하다. 문제가 발생한 계층(애플리케이션, Pod, 노드, 클러스터)을 파악하고, 단계별로 원인을 좁혀나가야 한다.

트러블슈팅 접근 방법

계층별 점검

1
2
3
4
5
6
7
8
9
10
11
12
13
┌────────────────────────────────────────┐
│ 1. 애플리케이션 계층                    │
│    - 애플리케이션 로그, 설정           │
├────────────────────────────────────────┤
│ 2. Pod 계층                            │
│    - Pod 상태, 이벤트, 리소스          │
├────────────────────────────────────────┤
│ 3. 노드 계층                           │
│    - kubelet, 컨테이너 런타임          │
├────────────────────────────────────────┤
│ 4. 클러스터 계층                       │
│    - Control Plane 컴포넌트            │
└────────────────────────────────────────┘

Pod 문제 해결

Pod 상태별 진단

Pending:

1
2
3
4
5
6
7
8
kubectl describe pod <pod-name>
# 이벤트 섹션 확인

# 일반적인 원인:
# - Insufficient cpu/memory: 노드 리소스 부족
# - No nodes available: 스케줄 가능한 노드 없음
# - PersistentVolumeClaim not found: PVC 대기 중
# - Taints/Tolerations: nodeSelector/affinity 불일치

ContainerCreating:

1
2
3
4
5
6
7
kubectl describe pod <pod-name>

# 일반적인 원인:
# - ImagePullBackOff: 이미지 pull 실패
# - ErrImagePull: 이미지 없음 또는 인증 실패
# - ConfigMap/Secret not found: 의존성 리소스 없음
# - Volume mount failed: 볼륨 마운트 실패

CrashLoopBackOff:

1
2
3
4
5
6
7
8
9
10
11
# 현재 로그
kubectl logs <pod-name>

# 이전 컨테이너 로그
kubectl logs <pod-name> --previous

# 일반적인 원인:
# - 애플리케이션 오류
# - 잘못된 command/args
# - 환경 변수 누락
# - 종료 코드 확인

ImagePullBackOff / ErrImagePull:

1
2
3
4
5
6
7
kubectl describe pod <pod-name>

# 확인 사항:
# - 이미지 이름/태그 오타
# - 프라이빗 레지스트리 인증 (imagePullSecrets)
# - 네트워크 연결 문제
# - 이미지가 레지스트리에 존재하는지

OOMKilled:

1
2
3
4
5
6
7
8
kubectl describe pod <pod-name>
# Last State: Terminated
# Reason: OOMKilled

# 해결:
# - memory limits 증가
# - 애플리케이션 메모리 누수 수정
# - JVM heap size 조정 (Java 앱)

Evicted:

1
2
3
4
5
6
7
8
9
kubectl get pods -A | grep Evicted

# 원인: 노드 리소스 부족
# - 디스크 부족 (ephemeral-storage)
# - 메모리 부족

# 해결:
# - Evicted Pod 정리
kubectl delete pods --field-selector=status.phase=Failed -A

Pod 상세 진단

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. Pod 상태 확인
kubectl get pod <pod-name> -o wide
kubectl describe pod <pod-name>

# 2. 로그 확인
kubectl logs <pod-name>
kubectl logs <pod-name> --previous
kubectl logs <pod-name> -c <container>

# 3. Pod 내부 접속
kubectl exec -it <pod-name> -- /bin/sh

# 4. 이벤트 확인
kubectl get events --field-selector involvedObject.name=<pod-name>

# 5. YAML 확인
kubectl get pod <pod-name> -o yaml

컨테이너 내부 디버깅

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 컨테이너 쉘 접속
kubectl exec -it <pod-name> -- /bin/sh
kubectl exec -it <pod-name> -c <container> -- /bin/bash

# DNS 테스트
nslookup kubernetes.default
nslookup <service-name>

# 네트워크 연결 테스트
wget -qO- http://service-name:port
curl http://service-name:port

# 환경 변수 확인
env
printenv

# 프로세스 확인
ps aux

# 파일 시스템 확인
df -h
ls -la /path/to/volume

# 네트워크 인터페이스
ip addr
cat /etc/resolv.conf

Service 문제 해결

Service 연결 문제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. Service 확인
kubectl get svc <service-name> -o wide
kubectl describe svc <service-name>

# 2. Endpoints 확인 (가장 중요!)
kubectl get endpoints <service-name>
# ENDPOINTS가 비어있다면 → selector 불일치

# 3. selector 확인
kubectl get svc <service-name> -o jsonpath='{.spec.selector}'
kubectl get pods -l <key>=<value>

# 4. Pod Ready 상태 확인
kubectl get pods -l <key>=<value> -o wide
# Pod가 Ready 상태여야 Endpoints에 등록됨

# 5. Service 내부에서 테스트
kubectl run test --rm -it --image=busybox -- /bin/sh
# nslookup <service-name>
# wget -qO- http://<service-name>:<port>

DNS 문제

1
2
3
4
5
6
7
8
9
10
11
# DNS Pod 확인
kubectl get pods -n kube-system -l k8s-app=kube-dns

# DNS 테스트
kubectl run test --rm -it --image=busybox -- nslookup kubernetes.default

# resolv.conf 확인
kubectl exec <pod-name> -- cat /etc/resolv.conf

# DNS 로그 확인
kubectl logs -n kube-system -l k8s-app=kube-dns

외부 접근 문제 (NodePort/LoadBalancer)

1
2
3
4
5
6
7
8
9
10
# NodePort 확인
kubectl get svc <service-name>
# 외부에서 <NodeIP>:<NodePort>로 접근

# 방화벽 확인
# - 클라우드: Security Group, Network ACL
# - 온프레미스: iptables, firewalld

# externalTrafficPolicy 확인
kubectl get svc <service-name> -o jsonpath='{.spec.externalTrafficPolicy}'

노드 문제 해결

노드 상태 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 노드 상태
kubectl get nodes
kubectl describe node <node-name>

# Conditions 확인
# - Ready: 노드 정상
# - MemoryPressure: 메모리 부족
# - DiskPressure: 디스크 부족
# - PIDPressure: PID 부족
# - NetworkUnavailable: 네트워크 문제

# 리소스 사용량
kubectl top node <node-name>
kubectl describe node <node-name> | grep -A5 "Allocated resources"

kubelet 문제

1
2
3
4
5
6
7
8
9
10
# 노드에서 실행
# kubelet 상태
sudo systemctl status kubelet

# kubelet 로그
sudo journalctl -u kubelet -f
sudo journalctl -u kubelet --since "10 minutes ago"

# kubelet 재시작
sudo systemctl restart kubelet

컨테이너 런타임 문제

1
2
3
4
5
6
7
8
9
10
11
12
# containerd 상태
sudo systemctl status containerd
sudo journalctl -u containerd

# containerd로 컨테이너 확인
sudo crictl ps
sudo crictl pods
sudo crictl images

# Docker (사용 시)
sudo systemctl status docker
sudo docker ps

노드 NotReady 문제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 1. 노드 상태 확인
kubectl describe node <node-name>

# 2. kubelet 로그 확인
sudo journalctl -u kubelet -f

# 일반적인 원인:
# - kubelet 중지
# - 컨테이너 런타임 문제
# - 네트워크 연결 끊김
# - 인증서 만료
# - 디스크 가득 참

# 3. 네트워크 확인 (API Server와 통신)
curl -k https://<api-server>:6443/healthz

# 4. 디스크 확인
df -h

Control Plane 문제 해결

Control Plane 컴포넌트 확인

1
2
3
4
5
6
7
8
9
10
11
# Static Pod 확인
kubectl get pods -n kube-system | grep -E 'api|controller|scheduler|etcd'

# 각 컴포넌트 로그
kubectl logs -n kube-system kube-apiserver-<node>
kubectl logs -n kube-system kube-controller-manager-<node>
kubectl logs -n kube-system kube-scheduler-<node>
kubectl logs -n kube-system etcd-<node>

# 또는 노드에서 직접
sudo crictl logs <container-id>

API Server 문제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# API Server 접근 테스트
kubectl cluster-info
kubectl get --raw /healthz

# API Server 상태 확인
kubectl get pods -n kube-system | grep api

# 로그 확인
kubectl logs -n kube-system kube-apiserver-<master>
# 또는
sudo cat /var/log/pods/kube-system_kube-apiserver-*/kube-apiserver/*.log

# 일반적인 문제:
# - 인증서 만료
# - etcd 연결 실패
# - 메모리 부족

etcd 문제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# etcd 상태 확인
ETCDCTL_API=3 etcdctl endpoint health \
  --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

# etcd 멤버 확인
ETCDCTL_API=3 etcdctl member list \
  --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

# etcd 로그
kubectl logs -n kube-system etcd-<master>

인증서 문제

1
2
3
4
5
6
7
8
# 인증서 만료 확인
sudo kubeadm certs check-expiration

# 개별 인증서 확인
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -enddate

# 인증서 갱신
sudo kubeadm certs renew all

네트워크 문제 해결

Pod-to-Pod 통신

1
2
3
4
5
6
7
8
9
# 같은 노드
kubectl run test1 --image=busybox -- sleep 3600
kubectl run test2 --image=busybox -- sleep 3600

# test1에서 test2로 ping
kubectl exec test1 -- ping <test2-ip>

# 다른 노드 간 통신 테스트
kubectl get pods -o wide  # Pod가 다른 노드에 있는지 확인

CNI 플러그인 문제

1
2
3
4
5
6
7
8
9
# CNI 플러그인 Pod 확인
kubectl get pods -n kube-system | grep -E 'calico|flannel|weave|cilium'

# CNI 로그
kubectl logs -n kube-system <cni-pod>

# CNI 설정 확인 (노드에서)
ls /etc/cni/net.d/
cat /etc/cni/net.d/*.conf

NetworkPolicy 문제

1
2
3
4
5
6
7
8
9
# NetworkPolicy 확인
kubectl get networkpolicy -A
kubectl describe networkpolicy <name>

# 연결 테스트
kubectl run test --rm -it --image=busybox -- wget -qO- --timeout=2 http://<service>

# NetworkPolicy 일시적 제거 (테스트용)
kubectl delete networkpolicy <name>

스토리지 문제 해결

PVC Pending

1
2
3
4
5
6
7
8
9
10
11
12
13
# PVC 상태
kubectl get pvc
kubectl describe pvc <pvc-name>

# 일반적인 원인:
# - PV 없음 (정적 프로비저닝)
# - StorageClass 없거나 잘못됨
# - accessModes 불일치
# - 용량 부족

# StorageClass 확인
kubectl get storageclass
kubectl describe storageclass <name>

볼륨 마운트 실패

1
2
3
4
5
6
7
8
kubectl describe pod <pod-name>
# Events에서 "MountVolume.SetUp failed" 확인

# 원인:
# - PVC가 bound 상태가 아님
# - 권한 문제
# - fsType 불일치
# - 노드에 볼륨이 이미 attach됨 (다른 Pod에서 사용 중)

일반적인 트러블슈팅 체크리스트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 1. 기본 상태 확인
kubectl get nodes
kubectl get pods -A
kubectl get events -A --sort-by='.lastTimestamp' | tail -20

# 2. 문제 Pod 상세 확인
kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl logs <pod-name> --previous

# 3. 관련 리소스 확인
kubectl get svc
kubectl get endpoints
kubectl get pvc
kubectl get configmap
kubectl get secret

# 4. 노드 상태 확인
kubectl describe node <node-name>
kubectl top nodes

# 5. 클러스터 컴포넌트 확인
kubectl get pods -n kube-system
kubectl cluster-info

기술 면접 대비

자주 묻는 질문

Q: Pod가 Pending 상태일 때 어떻게 진단하는가?

A: kubectl describe pod로 이벤트를 확인한다. 일반적인 원인은 리소스 부족(Insufficient cpu/memory), 노드 selector/affinity 불만족, PVC 바인딩 대기, taints/tolerations 불일치 등이다. 이벤트 메시지가 원인을 명확히 알려준다.

Q: CrashLoopBackOff 문제는 어떻게 해결하는가?

A: kubectl logs –previous로 이전 컨테이너의 로그를 확인한다. 애플리케이션 오류, 잘못된 command/args, 환경 변수 누락, 의존 서비스 연결 실패 등이 원인이다. Exit code도 힌트가 된다 (1: 일반 오류, 137: OOMKilled, 143: SIGTERM).

Q: Service에 연결이 안 될 때 점검 순서는?

A: 먼저 kubectl get endpoints로 Endpoints가 있는지 확인한다. Endpoints가 비어있으면 selector와 Pod label 일치 여부, Pod가 Ready 상태인지 확인한다. Endpoints가 있으면 Pod 내부에서 직접 연결 테스트를 한다. 그래도 안 되면 NetworkPolicy를 확인한다.

Q: 노드가 NotReady일 때 어떻게 진단하는가?

A: kubectl describe node로 Conditions를 확인한다. 노드에서 sudo systemctl status kubelet과 journalctl -u kubelet로 kubelet 상태를 확인한다. 컨테이너 런타임(containerd/docker) 상태도 확인한다. 네트워크 연결, 디스크 공간, 인증서 만료도 점검한다.

Q: kubectl 명령이 API Server에 연결되지 않을 때?

A: kubeconfig 설정(~/.kube/config)을 확인하고, API Server 주소와 인증 정보가 올바른지 확인한다. Master 노드에서 직접 kubectl cluster-info를 실행해본다. API Server Pod 상태와 로그를 확인한다. 인증서 만료 여부도 점검한다.

CKA 시험 대비 필수 명령어

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Pod 진단
kubectl get pods -A
kubectl describe pod <pod>
kubectl logs <pod>
kubectl logs <pod> --previous
kubectl exec -it <pod> -- /bin/sh

# Service 진단
kubectl get svc,endpoints
kubectl describe svc <svc>
kubectl run test --rm -it --image=busybox -- wget -qO- http://<svc>

# 노드 진단
kubectl get nodes
kubectl describe node <node>
kubectl top nodes
sudo journalctl -u kubelet -f

# 클러스터 진단
kubectl get pods -n kube-system
kubectl cluster-info
kubectl get events -A --sort-by='.lastTimestamp'

# Control Plane 로그
kubectl logs -n kube-system kube-apiserver-<master>
kubectl logs -n kube-system kube-controller-manager-<master>
kubectl logs -n kube-system kube-scheduler-<master>

다음 단계

This post is licensed under CC BY 4.0 by the author.