효율적인 Pod 디버깅을 위한 kubectl logs 및 describe 마스터하기
Kubernetes와 같은 분산 환경에서 애플리케이션을 디버깅하는 것은 어려울 수 있습니다. Pod가 시작되지 않거나, 재시작 루프에 빠지거나, 예상치 못한 동작을 보일 때, Kubernetes 운영자의 툴킷에서 가장 중요한 두 가지 도구는 kubectl describe와 kubectl logs입니다.
이 명령어들은 Kubernetes Pod의 상태와 이력에 대한 서로 다르면서도 상호 보완적인 시각을 제공합니다. kubectl describe는 Pod의 메타데이터, 상태, 환경 변수, 그리고 결정적으로 시스템 이벤트 기록을 제공합니다. kubectl logs는 컨테이너화된 애플리케이션 자체에서 생성된 표준 출력(stdout) 및 표준 오류(stderr) 스트림을 제공합니다.
이 명령어들과 관련된 플래그 및 기술을 마스터하는 것은 문제를 신속하게 진단하고 해결하며, 전반적인 클러스터 문제 해결 효율성을 크게 향상시키는 데 필수적입니다.
3단계 Pod 디버깅 워크플로
명령어에 뛰어들기 전에, 일반적인 디버깅 워크플로를 이해하는 것이 도움이 됩니다.
- 상태 확인:
kubectl get pods를 사용하여 실패 상태(Pending,CrashLoopBackOff,ImagePullBackOff등)를 식별합니다. - 컨텍스트 및 이벤트 확인:
kubectl describe pod를 사용하여 상태 전환이 왜 발생했는지 이해합니다(예: 스케줄러 실패, 활성 프로브 실패, 볼륨 마운트 실패). - 애플리케이션 출력 검사:
kubectl logs를 사용하여 애플리케이션의 런타임 동작(예: 구성 오류, 데이터베이스 연결 실패, 스택 트레이스)을 검사합니다.
1. kubectl describe: 시스템 트리아지 도구
kubectl describe는 Pod가 제대로 작동하지 않을 때 가장 먼저 실행해야 하는 명령어입니다. 이 명령어는 애플리케이션 출력을 보여주지는 않지만, Kubernetes 자체가 Pod에 대해 기록한 중요한 메타데이터와 이력을 제공합니다.
기본 사용법
기본 사용법은 Pod 이름만 필요합니다.
kubectl describe pod my-failing-app-xyz789
출력의 주요 섹션
describe의 출력을 검토할 때, 다음의 중요한 섹션에 집중하세요.
A. 상태(Status) 및 스테이트(State)
상단의 Status 필드를 확인하고, Pod 내의 개별 컨테이너 상태를 검토하세요. 이는 컨테이너가 Running, Waiting, 또는 Terminated 상태인지 알려주며, 해당 상태의 이유를 제공합니다.
| 필드 | 일반적인 상태/이유 | 의미 |
|---|---|---|
Status |
Pending |
Pod가 스케줄링되기를 기다리거나 리소스가 부족합니다. |
Reason |
ContainerCreating |
컨테이너 런타임이 이미지를 풀(pull)하거나 설정을 실행 중입니다. |
State |
Waiting / Reason: CrashLoopBackOff |
컨테이너가 반복적으로 시작되고 종료되었습니다. |
State |
Terminated / Exit Code |
컨테이너 실행이 완료되었습니다. 0이 아닌 종료 코드는 일반적으로 오류를 나타냅니다. |
B. 컨테이너 구성(Container Configuration)
이 섹션은 환경 변수, 리소스 요청/제한, 볼륨 마운트, 활성/준비 프로브가 적용한 매니페스트와 일치하여 올바르게 정의되었는지 확인합니다.
C. Events 섹션 (매우 중요)
출력 하단에 위치한 Events 섹션은 틀림없이 가장 가치 있는 부분입니다. 이 섹션은 Kubernetes 컨트롤 플레인이 Pod에 대해 수행한 작업(경고 및 오류 포함)의 시간 순서 기록을 제공합니다.
Events에 의해 드러나는 일반적인 오류:
- 스케줄링 문제:
Warning FailedScheduling: 스케줄러가 적합한 노드를 찾을 수 없음을 나타냅니다(예: 리소스 제약, 노드 테인트, 어피니티 규칙).. - 이미지 풀(Pull) 실패:
Warning Failed: ImagePullBackOff: 이미지 이름이 잘못되었거나, 태그가 존재하지 않거나, Kubernetes에 프라이빗 레지스트리에서 이미지를 풀할 자격 증명이 없음을 나타냅니다. - 볼륨 오류:
Warning FailedAttachVolume: 외부 스토리지 연결 문제를 나타냅니다.
팁:
Events섹션이 깨끗하다면, 문제는 일반적으로 애플리케이션 관련(런타임 충돌, 초기화 실패, 구성 오류)이며, 다음 단계로kubectl logs를 사용하도록 안내합니다.
2. kubectl logs: 애플리케이션 출력 검사
describe가 Pod가 성공적으로 스케줄링되었고 컨테이너가 실행을 시도했음을 보여준다면, 다음 단계는 kubectl logs를 사용하여 표준 출력 스트림을 확인하는 것입니다.
기본 로그 검색 및 실시간 스트리밍
Pod의 기본 컨테이너에 대한 현재 로그를 보려면:
# 현재 시점까지의 모든 로그 검색
kubectl logs my-failing-app-xyz789
# 실시간으로 로그 스트리밍 (시작 모니터링에 유용)
kubectl logs -f my-failing-app-xyz789
다중 컨테이너 Pod 처리
사이드카 패턴 또는 기타 다중 컨테이너 설계를 사용하는 Pod의 경우, -c 또는 --container 플래그를 사용하여 보려는 컨테이너의 로그를 지정해야 합니다.
# Pod 내의 '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 라인으로 제한하세요.
b# 컨테이너 로그의 마지막 50줄만 표시
kubectl logs my-high-traffic-app --tail=50
3. 고급 진단을 위한 기술 결합
효과적인 디버깅은 종종 describe와 특정 logs 명령어를 빠르게 전환하는 것을 포함합니다.
사례 연구: 활성 프로브(Liveness Probe) 실패 진단
Pod가 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 오류와 함께 실패하여 Kubernetes가 컨테이너를 재시작하고 있습니다.
단계 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
최종 결론: Pod는 활성 프로브 실패로 인해 재시작되고 있으며, 프로브는 애플리케이션이 데이터베이스에 연결할 수 없기 때문에 실패하고 있습니다. 문제는 컨테이너 자체의 문제가 아니라 외부 네트워킹 또는 데이터베이스 구성에 있습니다.
모범 사례 및 경고
| 모범 사례 | 명령어 | 근거 |
|---|---|---|
| 항상 이전 로그 확인 | kubectl logs --previous |
CrashLoopBackOff 진단에 필수적입니다. 중요한 오류는 거의 항상 이전 실행에 있습니다. |
| 컨테이너 지정 | kubectl logs -c <name> |
다중 컨테이너 Pod에서 모호함을 피하고 의도하지 않은 사이드카에서 로그를 가져오는 것을 방지합니다. |
| 대량 작업에 레이블 사용 | kubectl logs -l app=frontend -f |
선택자와 일치하는 여러 Pod에서 동시에 로그를 스트리밍할 수 있습니다(롤링 업데이트에 유용). |
| 경고: 로그 로테이션 | N/A | Kubernetes 노드는 로그 로테이션을 수행합니다. 노드의 구성된 보존 정책(종종 며칠 또는 크기 기반)보다 오래된 로그는 정리되어 kubectl logs를 통해 사용할 수 없습니다. 장기 보존을 위해 외부 중앙 집중식 로깅 솔루션(예: Fluentd, Loki, Elastic Stack)을 사용하세요. |
결론
kubectl describe와 kubectl logs는 Kubernetes에서 디버깅을 위한 없어서는 안 될 핵심 명령어입니다. describe를 시스템 상태 보고서(구성, 이벤트, 스케줄링 오류에 중점)로, logs를 애플리케이션 실행 스트림(코드 오류 및 런타임 동작에 중점)으로 활용함으로써, 거의 모든 Pod 실패의 원인을 체계적으로 좁힐 수 있으며, 클러스터 내에서 MTTR(Mean Time To Resolution)을 크게 줄일 수 있습니다.