
갑작스러운 파드 장애, 당황하지 않고 대응하는 법
모니터링 대시보드에 갑자기 빨간불이 들어오고, {@kubectl get pods} 명령어를 쳤을 때 CrashLoopBackOff나 Pending 상태가 가득한 화면을 본 적이 있나요? 서비스는 중단되었고, 장애 보고는 올라오는데 어디서부터 손을 대야 할지 몰라 식은땀이 흐르는 상황은 모든 주니어 엔지니어가 한 번쯤 겪는 통과의례와 같아요.
단순히 파드를 삭제하고 다시 생성한다고 해서 문제가 해결되지는 않아요. 근본 원인을 찾지 못하면 장애는 반드시 다시 반복되기 때문이죠. 쿠버네티스 환경에서 파드는 컨테이너를 감싸는 가장 작은 단위이기에, 파드가 죽었다는 것은 애플리케이션 설정, 리소스 부족, 네트워크 설정, 혹은 노드 자체의 문제 등 아주 다양한 가능성을 내포하고 있어요.
이 글은 단순히 명령어를 나열하는 가이드가 아니에요. 장애가 발생했을 때 논리적으로 사고를 확장하며 원인을 좁혀나가는 파드 트러블슈팅의 핵심 프로세스를 전수해 드려요. 이 글을 끝까지 읽고 나면, 막연한 공포 대신 차분하게 진단 명령어를 입력하는 자신을 발견하게 될 거예요.
이번 가이드에서 함께 살펴볼 내용은 다음과 같아요.
- 파드 상태별 의미와 현재 상황 파악하기
- 진단의 시작점인 Describe와 Log 활용법
- 리소스 부족 및 네트워크 장애 판별법
- 실무에서 자주 발생하는 실수와 해결책
진단 전 반드시 갖춰야 할 도구와 기본 지식
본격적인 트러블슈팅에 뛰어들기 전에, 최소한의 무기를 챙겨야 해요. 아무 준비 없이 명령어를 치기 시작하면 오히려 혼란만 가중될 수 있어요. 먼저 여러분의 터미널에 {@code kubectl} 도구가 제대로 설치되어 있는지, 그리고 현재 접속 중인 클러스터 컨텍스트가 운영 환경인지 개발 환경인지 반드시 확인해야 해요.
잘못된 컨텍스트에서 명령어를 실행했다가는 개발 환경의 파드를 지우고 운영 환경의 데이터를 건드리는 대참사가 벌어질 수 있거든요. 접속 권한(RBAC) 또한 중요해요. 파드의 로그를 보거나 이벤트를 확인하려면 해당 네임스페이스에 대한 적절한 읽기 권한이 있어야 합니다.
또한, 파드가 가질 수 있는 상태값들을 명확히 이해하고 있어야 해요. 상태를 보고
단계별 파드 장애 진단 및 복구 프로세스
이제 본격적으로 문제를 해결해 볼까요? 트러블슈팅은 마치 탐정이 사건 현장을 조사하는 과정과 비슷해요. 겉으로 드러난 증상(Status)에서 시작하여, 조금 더 깊은 증거(Events)를 거쳐, 마침내 범인(Root Cause)을 찾아내는 순서로 진행해야 합니다.
STEP 1. 파드의 현재 상태와 이벤트 확인하기
가장 먼저 해야 할 일은 {@code kubectl get pods}를 통해 전체적인 파드들의 상태를 훑는 것이에요. 특정 파드가 {@code Error}나 {@code CrashLoopBackOff} 상태라면, 즉시 {@code kubectl describe pod [파드명]} 명령어를 실행하세요.
Describe 명령어는 파드의 생애 주기에 대한 매우 방대한 정보를 제공해요. 특히 하단의 Events 섹션을 유심히 살펴봐야 합니다. 여기에 왜 파드가 생성되지 않았는지, 왜 노드에 배치되지 못했는지에 대한 결정적인 힌트가 담겨 있어요. 예를 들어, {@code Insufficient cpu}라는 메시지가 있다면 노드에 여유 자원이 없다는 뜻이고, {@code FailedMount}가 있다면 볼륨 연결에 문제가 생겼다는 뜻이죠.
STEP 2. 애플리케이션 로그 정밀 분석하기
상태가 {@code Running}임에도 불구하고 서비스가 응답하지 않거나, {@code CrashLoopBackOff}로 계속 재시작된다면 애플리케이션 내부의 목소리를 들어야 해요. 바로 로그를 확인하는 단계입니다. {@code kubectl logs [파드명]} 명령어를 통해 표준 출력(stdout)에 찍힌 에러 메시지를 확인하세요.
여기서 중요한 팁이 하나 있어요. 파드가 이미 종료되어 버려서 {@code kubectl logs}로 아무것도 볼 수 없다면, {@code –previous} 플래그를 사용하세요. {@code kubectl logs [파드명] –previous}라고 입력하면, 현재 실행 중인 컨테이너가 아니라 바로 직전에 죽었던 컨테이너의 로그를 불러올 수 있어요. 애플리케이션이 시작되자마자 환경 변수 오류나 DB 연결 실패로 죽어버린 경우, 이 명령어가 유일한 구원줄이 될 거예요.
STEP 3. 리소스 부족 및 OOMKilled 여부 판단하기
파드가 잘 돌아가다가 갑자기 사라지거나 재시작된다면, 리소스 제한(Limit) 문제를 의심해야 해요. 특히 메모리 부족으로 인해 운영체제가 컨테이너를 강제로 종료시키는 OOMKilled (Out Of Memory Killed) 상황은 매우 빈번하게 발생해요.
이런 경우에는 {@code kubectl describe pod}의 {@code Last State} 섹션을 확인해 보세요. {@code Reason: OOMKilled}라고 적혀 있다면, 해당 파드가 설정된 메모리 한도를 초과했다는 명백한 증거예요. 이럴 때는 파드의 {@code resources.limits.memory} 값을 적절히 늘려주거나, 애플리케이션의 메모리 누수(Memory Leak)를 점검해야 합니다. CPU 부족의 경우 프로세스가 느려지긴 하지만 컨테이너가 즉시 종료되지는 않으므로, 메모리 문제와는 대응 방식이 조금 달라야 해요.
메모리 부족 문제를 해결하기 위해 무작정 Limit 값만 높이는 것은 위험해요. 클러스터 전체의 자원은 한정되어 있기 때문에, 특정 파드에 너무 많은 자원을 할당하면 다른 파드들이 배치될 공간이 없어져 클러스터 전체가 불안정해질 수 있습니다.
STEP 4. 네트워크 연결성 및 서비스 확인
파드는 정상인데 외부에서 접속이 안 된다면, 문제는 파드 외부의 네트워크 레이어에 있을 가능성이 높아요. 이때는 다음 세 가지를 순서대로 점검하세요.
- Service 확인: {@code kubectl get svc}를 통해 서비스가 올바른 포트를 가리키고 있는지 확인하세요.
- Endpoint 확인: {@code kubectl get endpoints [서비스명]} 명령어로 서비스가 실제 파드의 IP 주소들을 제대로 추적하고 있는지 체크해야 해요. 만약 Endpoint 리스트가 비어 있다면, 파드의 {@code selector}와 서비스의 {@code selector}가 일치하지 않는 문제일 가능성이 매우 커요.
- Pod 내부 확인: {@code kubectl exec -it [파드명] — /bin/sh} 명령어로 파드 내부로 직접 들어가 보세요. 파드 안에서 {@code curl}이나 {@code telnet}을 이용해 대상 서버에 접속이 되는지 테스트해보는 것이 가장 확실한 방법이에요.
STEP 5. 실전 시나리오: DB 연결 실패로 인한 CrashLoopBackOff 해결하기
이해를 돕기 위해 실제 상황을 가정해 볼게요. 신규 배포한 API 서버 파드가 계속 {@code CrashLoopBackOff} 상태에 빠졌습니다. 진단 순서는 다음과 같아요.
먼저 {@code describe pod}을 보니 이벤트에 특별한 에러는 없어요. 그래서 {@code kubectl logs –previous}를 실행했더니, {@code
자주 하는 실수와 해결법 및 FAQ
트러블슈팅을 하다 보면 의욕이 앞서서 오히려 상황을 악화시키는 실수를 범하곤 해요. 실무에서 자주 발생하는 패턴들을 정리했으니 꼭 기억해 두세요.
- ❌ 실수: 로그가 안 나온다고 파드를 바로 삭제하고 다시 생성함
➡️ 이유: 원인을 모른 채 재시작하면 똑같은 에러가 반복될 뿐이며, 진단할 수 있는 로그 데이터마저 날려버리게 됩니다.
✅ 해결법: 반드시 {@code kubectl logs –previous}와 {@code describe}를 통해 원인을 먼저 파악하세요. - ❌ 실수: {@code kubectl get pods}의 상태만 보고 판단함
➡️ 이유: {@code Running} 상태라고 해서 서비스가 정상이라는 뜻은 아닙니다. 애플리케이션 내부 에러는 로그를 봐야만 알 수 있어요.
✅ 해결법: 상태가 {@code Running}이더라도 서비스 응답이 이상하다면 즉시 로그를 확인하세요. - ❌ 실수: 리소스 부족 시 Limit 값만 무작정 늘림
➡️ 이유: 클러스터 전체 자원 고갈을 초래하여 다른 서비스까지 죽게 만드는 연쇄 장애를 유발할 수 있습니다.
✅ 해결법: 애플리케이션의 메모리 사용 패턴을 분석하여 최적의 값을 찾거나, 메모리 누수 코드를 수정하세요. - ❌ 실수: {@code selector} 불일치를 간과함
➡️ 이유: 서비스와 파드가 연결되지 않아 발생하는 네트워크 장애는 로그에 아무런 흔적도 남지 않는 경우가 많습니다.
✅ 해결법: {@code kubectl get endpoints} 명령어로 서비스와 파드가 올바르게 매핑되었는지 주기적으로 확인하세요.
자주 묻는 질문
Q. 파드가 왜 계속 Pending 상태에 머물러 있나요?
가장 흔한 이유는 클러스터에 파드를 배치할 수 있는 여유 자원(CPU, Memory)이 없기 때문이에요. 혹은 노드에 설정된 {@code Taints}와 파드의 {@code Tolerations}가 맞지 않아 특정 노드에 들어가지 못하는 경우일 수도 있어요. {@code describe pod} 명령어로 이벤트를 확인하는 것이 가장 빨라요.
Q. Container 내부에 들어가서 직접 디버깅하고 싶은데 어떻게 하나요?
{@code kubectl exec -it [파드명] — [실행할 명령]} 형식을 사용하면 돼요. 예를 들어 {@code kubectl exec -it my-pod — /bin/bash}라고 입력하면 파드 내부의 쉘로 접속할 수 있습니다. 만약 쉘이 설치되어 있지 않다면 {@code /bin/sh}를 시도해 보세요.
Q. ImagePullBackOff 에러가 뜨는데 이미지는 분명히 존재해요. 왜 이럴까요?
이미지 이름이나 태그(Tag)에 오타가 없는지 다시 한번 확인해 보세요. 만약 오타가 없다면, 프라이빗 레지스트리를 사용 중인 경우 {@code imagePullSecrets} 설정이 빠져서 인증에 실패했을 가능성이 매우 높습니다.
Q. 파드가 종료될 때 Exit Code가 137이 나왔어요. 이게 무슨 뜻인가요?
Exit Code 137은 프로세스가 {@code SIGKILL} 신호를 받고 강제 종료되었다는 뜻이에요. 쿠버네티스 환경에서는 대부분 OOMKilled(메모리 부족) 상황에서 발생하니, 메모리 설정을 반드시 점검해 보세요.
장애 대응을 위한 최종 체크리스트
지금까지 살펴본 내용은 파드 장애 상황에서 여러분의 든든한 지도 역할을 해줄 거예요. 갑작스러운 장애가 닥쳤을 때, 당황하지 말고 아래의 흐름을 머릿속에 그리며 차근차근 실행해 보세요. 트러블슈팅은 속도보다 정확한 방향성이 훨씬 중요합니다.
- {@code kubectl get pods}로 전체적인 상태값(Status)을 먼저 파악하기
- {@code kubectl describe pod}의 Events 섹션에서 스케줄링/볼륨 문제 찾기
- {@code kubectl logs –previous}로 종료된 컨테이너의 마지막 메시지 확인하기
- {@code OOMKilled} 확인 시 메모리 Limit 및 애플리케이션 누수 점검하기
- 서비스 접속 불가 시 {@code endpoints}를 통해 파드 연결 상태 확인하기
- 원인을 알기 전까지 무작정 파드를 삭제하거나 재시작하지 않기
장애 대응은 단순히 불을 끄는 과정이 아니라, 시스템을 더 단단하게 만드는 학습의 과정이에요. 이번에 해결한 이슈를 반드시 문서화해 두세요. 다음에 똑같은 문제가 발생했을 때, 여러분은 훨씬 더 빠르게 대응할 수 있을 거예요.
오늘 할 일: 운영 중인 클러스터의 파드 상태를 한 번 더 확인하고, {@code describe} 명령어를 연습해 보세요.
이번 주 할 일: 주요 서비스의 리소스 제한(Limit/Request) 값이 적절한지 검토해 보세요.
실행 직전 할 일: 장애 발생 시 바로 사용할 수 있는 진단 명령어 리스트를 메모장에 저장해 두세요.
실습 환경에서 직접 명령어를 입력해 보다가 막히는 부분이 있다면, 언제든 댓글로 질문을 남겨 주세요. 함께 고민하며 해결해 나가면 좋겠습니다!
함께 읽으면 좋은 글:
쿠버네티스 파드 기본 개념 정리
쿠버네티스 클러스터 구축 입문 가이드