kubectl logs와 describe를 활용한 효율적인 파드 디버깅 마스터하기
이 가이드는 필수 쿠버네티스 디버깅 명령어인 `kubectl logs`와 `kubectl describe`를 마스터하기 위한 전문 기술을 제공합니다. 효율적인 문제 해결에 필요한 `-f`, `--tail`, `-c`, `--previous`와 같은 중요한 플래그를 배웁니다. `describe`의 중요한 'Events' 섹션을 해석하여 스케줄링 및 구성 문제를 진단하고, `logs`를 사용하여 충돌하거나 멀티 컨테이너 파드에서 런타임 오류를 추출하여 디버깅 워크플로우를 가속화하는 방법을 자세히 설명합니다.
kubectl logs와 describe를 활용한 효율적인 파드 디버깅 마스터하기
쿠버네티스 파드가 실패하면 kubectl describe와 kubectl logs가 일반적으로 다음에 어디를 봐야 할지 알려줍니다. describe는 쿠버네티스가 무엇을 시도했는지 설명합니다. logs는 컨테이너가 실패 전, 중, 후에 기록한 내용을 보여줍니다.
이 명령어들은 쿠버네티스 파드의 상태와 이력에 대해 서로 다르지만 상호 보완적인 관점을 제공합니다. kubectl describe는 파드의 메타데이터, 상태, 환경 변수, 그리고 중요한 것은 시스템 이벤트의 이력을 제공합니다. kubectl logs는 컨테이너화된 애플리케이션 자체에서 생성된 표준 출력(stdout) 및 표준 오류(stderr) 스트림을 제공합니다.
핵심은 올바른 순서로 사용하는 것입니다. 파드가 스케줄링되지 않은 경우 로그는 도움이 되지 않습니다. 파드가 시작되었다가 종료되면 이벤트는 충돌했다는 것만 알려줄 수 있습니다. 일반적으로 애플리케이션 로그가 그 이유를 설명합니다.
3단계 파드 디버깅 워크플로우
명령어를 살펴보기 전에 일반적인 디버깅 워크플로우를 이해하는 것이 도움이 됩니다.
- 상태 확인:
kubectl get pods를 사용하여 실패 상태(Pending,CrashLoopBackOff,ImagePullBackOff등)를 식별합니다. - 컨텍스트 및 이벤트 확인:
kubectl describe pod를 사용하여 상태 전환이 발생한 이유를 이해합니다 (예: 스케줄러 실패, 활성 프로브 실패, 볼륨 마운트 실패). - 애플리케이션 출력 검사:
kubectl logs를 사용하여 애플리케이션의 런타임 동작을 검사합니다 (예: 구성 오류, 데이터베이스 연결 실패, 스택 추적).
1. kubectl describe: 시스템 분류 도구
kubectl describe는 파드가 제대로 작동하지 않을 때 가장 먼저 실행해야 하는 명령어입니다. 애플리케이션 출력을 표시하지는 않지만 쿠버네티스 자체가 파드에 대해 기록한 중요한 메타데이터와 이력을 제공합니다.
기본 사용법
기본 사용법은 파드 이름만 필요합니다.
kubectl describe pod my-failing-app-xyz789
기본 네임스페이스에 있지 않은 경우 명시적으로 네임스페이스를 사용합니다.
kubectl describe pod my-failing-app-xyz789 -n payments
디플로이먼트 또는 레이블만 아는 경우 먼저 파드를 찾습니다.
kubectl get pods -n payments -l app=checkout -o wide
출력의 주요 섹션
describe의 출력을 검토할 때 다음 중요한 섹션에 집중하십시오.
A. 상태 및 상태
상단의 Status 필드를 확인한 다음 파드 내 개별 컨테이너 상태를 검토합니다. 이를 통해 컨테이너가 Running, Waiting 또는 Terminated인지와 해당 상태의 이유를 알 수 있습니다.
| 필드 | 일반적인 상태/이유 | 의미 |
|---|---|---|
Status |
Pending |
파드가 스케줄링되기를 기다리거나 리소스가 부족합니다. |
Reason |
ContainerCreating |
컨테이너 런타임이 이미지를 가져오거나 설정을 실행 중입니다. |
State |
Waiting / Reason: CrashLoopBackOff |
컨테이너가 시작되고 반복적으로 종료되었습니다. |
State |
Terminated / Exit Code |
컨테이너 실행이 완료되었습니다. 0이 아닌 종료 코드는 일반적으로 오류를 나타냅니다. |
B. 컨테이너 구성
이 섹션은 환경 변수, 리소스 요청/제한, 볼륨 마운트, 활성/준비 프로브가 적용한 매니페스트와 일치하게 올바르게 정의되었는지 확인합니다.
C. Events 섹션 (중요)
출력 하단에 위치한 Events 섹션은 틀림없이 가장 가치 있는 부분입니다. 쿠버네티스 제어 플레인이 파드에 대해 수행한 작업(경고 및 오류 포함)의 시간순 로그를 제공합니다.
Events에서 드러나는 일반적인 오류:
- 스케줄링 문제:
Warning FailedScheduling: 스케줄러가 적합한 노드를 찾을 수 없음을 나타냅니다 (예: 리소스 제약, 노드 테인트, 선호도 규칙으로 인해). - 이미지 가져오기 실패:
Warning Failed: ImagePullBackOff: 이미지 이름이 잘못되었거나, 태그가 존재하지 않거나, 쿠버네티스가 프라이빗 레지스트리에서 가져올 자격 증명이 부족함을 나타냅니다. - 볼륨 오류:
Warning FailedAttachVolume: 외부 스토리지 연결 문제를 나타냅니다.
팁:
Events섹션이 깨끗하고 컨테이너가 시작된 경우 문제는 일반적으로 애플리케이션 관련 문제입니다: 잘못된 환경 변수, 실패한 마이그레이션, 누락된 시크릿, 연결할 수 없는 종속성 또는 즉시 종료되는 프로세스.
2. kubectl logs: 애플리케이션 출력 검사
describe가 파드가 성공적으로 스케줄링되었고 컨테이너가 실행을 시도했음을 보여주면 다음 단계는 kubectl logs를 사용하여 표준 출력 스트림을 확인하는 것입니다.
기본 로그 검색 및 실시간 스트리밍
파드의 기본 컨테이너에 대한 현재 로그를 보려면:
# 현재 순간까지의 모든 로그 검색
kubectl logs my-failing-app-xyz789
# 로그를 실시간으로 스트리밍 (시작 모니터링에 유용)
kubectl logs -f my-failing-app-xyz789
멀티 컨테이너 파드 처리
사이드카 패턴 또는 기타 멀티 컨테이너 디자인을 사용하는 파드의 경우 -c 또는 --container 플래그를 사용하여 로그를 볼 컨테이너를 지정해야 합니다.
# 파드 내 'sidecar-proxy' 컨테이너의 로그 보기
kubectl logs my-multi-container-pod -c sidecar-proxy
# 기본 애플리케이션 컨테이너의 로그 스트리밍
kubectl logs -f my-multi-container-pod -c main-app
재시작 컨테이너 디버깅 (--previous)
가장 일반적인 디버깅 시나리오 중 하나는 CrashLoopBackOff 상태입니다. 컨테이너가 다시 시작되면 kubectl logs는 현재 (실패한) 시도의 출력만 표시하며, 여기에는 충돌 전 시작 메시지만 포함되는 경우가 많습니다.
종료를 유발한 실제 오류가 포함된 이전에 종료된 인스턴스의 로그를 보려면 --previous 플래그(-p)를 사용합니다.
# 이전에 충돌한 컨테이너 인스턴스의 로그 보기
kubectl logs my-crashloop-pod --previous
# 필요한 경우 컨테이너 사양과 결합
kubectl logs my-crashloop-pod -c worker --previous
출력 제한
볼륨이 많은 로그의 경우 전체 기록을 검색하는 것은 느리거나 압도적일 수 있습니다. --tail을 사용하여 출력을 마지막 N 줄로 제한합니다.
# 컨테이너 로그의 마지막 50줄만 표시
kubectl logs my-high-traffic-app --tail=50
타임스탬프와 시간 창을 추가할 수도 있습니다.
kubectl logs my-high-traffic-app --tail=100 --timestamps
kubectl logs my-high-traffic-app --since=10m
디플로이먼트의 경우 최신 kubectl 버전은 워크로드 이름을 통해 로그를 가져올 수 있습니다.
kubectl logs deploy/checkout-api -n payments --tail=100
너무 광범위한 경우 레이블 선택기를 사용합니다.
kubectl logs -n payments -l app=checkout --all-containers=true --tail=50
3. 고급 진단을 위한 기술 결합
효과적인 디버깅은 종종 describe와 특정 logs 명령어 사이를 빠르게 전환하는 것을 포함합니다.
사례 연구: 활성 프로브 실패 진단
파드가 Running 상태에 갇혀 있지만 가끔 다시 시작되어 중단을 유발하는 경우를 가정해 보겠습니다.
1단계: 시스템 보기를 위해 describe 확인.
kubectl describe pod web-server-dpl-abc
출력은 Events 섹션에 다음을 표시합니다.
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Unhealthy 2s kubelet, node-a01 Liveness probe failed: HTTP GET http://10.42.0.5:8080/health failed: 503 Service Unavailable
1단계 결론: 컨테이너가 실행 중이지만 활성 프로브가 503 오류로 실패하여 쿠버네티스가 컨테이너를 다시 시작하게 합니다.
2단계: 애플리케이션 컨텍스트를 위해 logs 확인.
이제 애플리케이션이 503 상태(애플리케이션 수준 오류)를 반환하는 이유를 조사합니다.
kubectl logs web-server-dpl-abc --tail=200
로그 출력은 다음을 보여줍니다.
2023-10-26 14:01:15 ERROR Database connection failure: Timeout connecting to DB instance 192.168.1.10
최종 결론: 파드가 실패하는 활성 프로브로 인해 다시 시작되고 있으며, 프로브는 애플리케이션이 데이터베이스에 연결할 수 없기 때문에 실패합니다. 문제는 컨테이너 자체가 아니라 외부 네트워킹 또는 데이터베이스 구성입니다.
사례 연구: 로그가 없는 보류 중인 파드
Pending 상태의 파드는 아직 컨테이너가 시작되지 않았기 때문에 유용한 컨테이너 로그가 없는 경우가 많습니다.
kubectl get pod report-worker-6f9c7b9b7d-f2q8m -n analytics
출력:
NAME READY STATUS RESTARTS AGE
report-worker-6f9c7b9b7d-f2q8m 0/1 Pending 0 4m
바로 describe로 이동합니다.
kubectl describe pod report-worker-6f9c7b9b7d-f2q8m -n analytics
이벤트는 다음을 표시할 수 있습니다.
Warning FailedScheduling default-scheduler 0/6 nodes are available: 6 Insufficient memory.
이는 애플리케이션 버그가 아닙니다. 파드가 스케줄러가 배치할 수 있는 것보다 더 많은 메모리를 요청하고 있습니다. 다음 단계는 디플로이먼트 요청, 클러스터 용량, 노드 테인트 및 오토스케일러 동작을 검사하는 것입니다.
kubectl get deploy report-worker -n analytics -o yaml
kubectl top nodes
사례 연구: ImagePullBackOff
ImagePullBackOff의 경우 컨테이너 이미지가 시작되지 않았기 때문에 로그는 일반적으로 비어 있습니다. describe가 유용한 오류를 제공합니다.
kubectl describe pod api-7dfb9c8b7f-bd2p9 -n staging
일반적인 이벤트 메시지에는 존재하지 않는 이미지 태그, 프라이빗 레지스트리에 대한 인증 실패 또는 레지스트리에 도달하는 DNS/네트워크 문제가 포함됩니다. 수정은 태그를 수정하는 것처럼 간단할 수 있습니다.
kubectl set image deploy/api api=registry.example.com/api:2026-05-24 -n staging
또는 이미지 풀 시크릿을 확인해야 할 수도 있습니다.
kubectl get secret regcred -n staging
kubectl describe serviceaccount default -n staging
사례 연구: 조용한 앱이 있는 멀티 컨테이너 파드
사이드카는 잘못된 컨테이너를 보면 신호를 숨길 수 있습니다. 먼저 컨테이너 이름을 나열합니다.
kubectl get pod checkout-84f7c9d7bf-px5mx -n payments \
-o jsonpath='{.spec.containers[*].name}{"\n"}'
그런 다음 각각을 의도적으로 검사합니다.
kubectl logs checkout-84f7c9d7bf-px5mx -n payments -c checkout --tail=100
kubectl logs checkout-84f7c9d7bf-px5mx -n payments -c envoy --tail=100
앱 로그는 조용하지만 프록시 로그에 업스트림 연결 실패가 표시되면 파드는 쿠버네티스 관점에서 정상일 수 있지만 서비스 메시 또는 프록시 구성을 통해 트래픽이 여전히 실패합니다.
모범 사례 및 경고
| 사례 | 명령어 | 근거 |
|---|---|---|
| 항상 이전 로그 확인 | kubectl logs --previous |
CrashLoopBackOff 진단에 필요합니다. 중요한 오류는 거의 항상 이전 실행에 있습니다. |
| 컨테이너 지정 | kubectl logs -c <name> |
멀티 컨테이너 파드에서 모호성을 방지하고 의도하지 않은 사이드카에서 로그를 가져오는 것을 방지합니다. |
| 대량 작업에 레이블 사용 | kubectl logs -l app=frontend -f |
선택기와 일치하는 여러 파드에서 동시에 로그를 스트리밍할 수 있습니다 (롤링 업데이트에 유용). |
| 경고: 로그 순환 | N/A | 쿠버네티스 노드는 로그 순환을 수행합니다. 노드의 구성된 보존 정책(종종 며칠 또는 크기 기준)보다 오래된 로그는 정리되어 kubectl logs를 통해 사용할 수 없게 됩니다. 장기 보존을 위해 외부 중앙 집중식 로깅 솔루션(예: Fluentd, Loki, Elastic Stack)을 사용하십시오. |
이러한 명령어가 알려줄 수 없는 것
kubectl logs는 노드에 보존된 컨테이너 stdout 및 stderr만 표시합니다. 애플리케이션이 컨테이너 내부의 파일에 쓰는 경우 kubectl logs는 아무것도 표시하지 않을 수 있습니다. 이는 kubectl 문제가 아니라 로깅 설계 문제입니다.
kubectl describe는 쿠버네티스 객체 상태 및 최근 이벤트를 표시하지만 이벤트는 영구 감사 로그가 아닙니다. 오래된 이벤트는 만료됩니다. 장기 실행 조사의 경우 관련 출력을 인시던트 노트에 복사하십시오.
두 명령어 모두 메트릭을 대체하지 않습니다. 파드가 실행 중이고 정상적으로 로깅하는 동안 CPU 스로틀링, 메모리 압박 또는 다운스트림 지연으로 인해 사용자에게 표시되는 문제가 발생할 수 있습니다. describe 및 logs 다음 명령어는 종종 다음과 같습니다.
kubectl top pod -n payments
kubectl top node
kubectl get events -n payments --sort-by=.lastTimestamp
쿠버네티스가 파드를 생성하거나 계속 실행할 수 없을 때는 describe를 먼저 사용하십시오. 파드가 실행 중이지만 애플리케이션이 잘못 작동할 때는 logs를 먼저 사용하십시오. 플랫폼 증상과 애플리케이션 증상을 분리할 수 있을 때까지 전환하십시오.
재사용 가능한 디버깅 흐름
압박을 받을 때마다 매번 동일한 흐름을 사용하십시오.
kubectl get pod <pod> -n <namespace> -o wide
kubectl describe pod <pod> -n <namespace>
kubectl logs <pod> -n <namespace> --all-containers=true --tail=100
kubectl logs <pod> -n <namespace> --all-containers=true --previous --tail=100
kubectl get events -n <namespace> --sort-by=.lastTimestamp
순서가 중요합니다. get pod -o wide는 노드, 파드 IP, 재시작 횟수 및 수명을 알려줍니다. describe는 스케줄링, 이미지, 볼륨, 프로브 및 컨테이너 상태 세부 정보를 알려줍니다. 현재 로그는 실행 중인 컨테이너가 지금 무엇을 하고 있는지 보여줍니다. 이전 로그는 이미 발생한 충돌을 포착합니다. 이벤트는 동일한 문제가 네임스페이스 전체에서 발생하는지 여부를 보여줍니다.
디플로이먼트의 경우 롤아웃 확인을 추가합니다.
kubectl rollout status deploy/<name> -n <namespace>
kubectl describe deploy/<name> -n <namespace>
kubectl get rs -n <namespace> -l app=<label>
때로는 디버깅 중인 파드가 롤아웃 중인 이전 ReplicaSet의 파드일 수 있습니다. 디플로이먼트를 수정했지만 종료 중인 이전 파드의 로그를 계속 읽으면 30분 동안 잘못된 문제를 쫓을 수 있습니다.
재시작 올바르게 읽기
RESTARTS 열은 단서이지 진단이 아닙니다. 노드 드레인 후 재시작 횟수가 1이면 무해할 수 있습니다. 매분 증가하는 재시작 횟수는 실시간 실패입니다. describe를 사용하여 마지막 상태를 확인하십시오.
Last State: Terminated
Reason: Error
Exit Code: 1
Started: Sun, 24 May 2026 10:14:02 +0800
Finished: Sun, 24 May 2026 10:14:07 +0800
종료 코드 1은 일반적으로 프로세스가 일반 애플리케이션 오류로 종료되었음을 의미합니다. 137은 종종 프로세스가 종료되었음을 의미하며, 일반적으로 메모리 제한을 초과했기 때문이지만 Reason 필드와 노드/컨테이너 런타임 컨텍스트로 확인해야 합니다. 143은 정상 종료 중 프로세스가 SIGTERM을 수신할 때 자주 나타납니다. 모든 0이 아닌 종료 코드를 동일한 종류의 실패로 취급하지 마십시오.
메모리가 의심되는 경우 다음을 찾으십시오.
Reason: OOMKilled
Exit Code: 137
그런 다음 컨테이너 제한을 실제 사용량과 비교합니다.
kubectl describe pod <pod> -n <namespace> | rg -A5 'Limits|Requests'
kubectl top pod <pod> -n <namespace>
metrics-server가 설치되지 않은 경우 kubectl top이 작동하지 않습니다. 이 경우 플랫폼의 메트릭 시스템 또는 노드 수준 도구를 사용하십시오.