
지난 포스팅에서는 파드의 무중단 롤링 업데이트부터 generateName을 활용한 동적 할당, 그리고 wait와 --prune을 이용한 꼼꼼한 생명주기 제어 방법에 대해 알아보았습니다.
배포를 무사히 마쳤다면, 이제는 "시스템이 잘 돌아가고 있는지 감시하고, 에러가 터졌을 때 빠르게 원인을 찾아내는" 운영(Operation) 단계로 넘어갈 차례입니다.
이번 포스팅에서는 실제 쿠버네티스 환경에서 가장 많이 타이핑하게 될 필수 모니터링 명령어와 트러블슈팅의 핵심인 로그 확인, 쉘 접속, 포트포워딩 기법에 대해 정리해 보겠습니다. 🚀
api-resources & get) 📋클러스터에 어떤 리소스들이 있는지, 현재 상태는 어떤지 파악하는 것은 운영의 기본이라고 할 수 있습니다.
쿠버네티스에는 파드, 서비스 외에도 수많은 리소스가 존재합니다. 해당 리소스가 네임스페이스에 속하는지(Namespaced) 아니면 클러스터 전체에 적용되는지 파악할 수 있습니다.
kubectl api-resources kubectl api-resources --namespaced=true kubectl api-resources --namespaced=false 
-o)명령어를 조합하여 특정 조건의 리소스를 찾거나, 원하는 형태로 데이터를 추출할 수 있습니다.
기본 및 필터링 조회:
리소스 전체 가져오기: kubectl get all
특정 리소스 정보만 가져오기: kubectl get [리소스종류]
하나의 리소스만 가져오기: kubectl get [리소스종류] [리소스이름]
특정 레이블을 가진 리소스 가져오기: kubectl get [리소스종류] [label이름]=[label값]
노드 목록 표시: kubectl get nodes
다양한 출력 포맷 활용하기 (-o):
자세히 보기를 원할 때는 -o 옵션 뒤에 JSON, YAML, Custom Columns, JSON Path, Go Template 등의 형식을 지정할 수 있습니다.
# pod 정보를 yaml 형식으로 모든 명세서 보기
kubectl get pods -o yaml sample-pod
# Custom-columns: 특정 컬럼의 값을 내 입맛대로 변경해서 출력
# (.metadata.name을 'NAME'으로, .status.hostIP를 'NodeIP'로 출력)
kubectl get pods -o custom-columns="NAME:{.metadata.name}, NodeIP:{.status.hostIP}"
# JSON Path: 텍스트 파싱을 위해 특정 속성의 값 하나만 출력
kubectl get pods sample-pod -o jsonpath="{.metadata.name}"
💡 실무 팁:
-o yaml에러가 난 파드의 현재 상태나 전체 설정을 그대로 확인하고 싶을 때는
kubectl get pod [이름] -o yaml을 쳐서 확인하는 것이 가장 정확하고 확실한 방법입니다.
describe) 🕵️♂️get 명령어로 상태를 확인했는데 파드가 Pending (대기중)이거나, CrashLoopBackOff, ImagePullBackOff 등의 에러 상태에 빠져있다면 당황을 하게 됩니다.
여기서 문제는 파드가 제대로 뜨지도 않은 상태라 logs 명령어를 쳐도 아무것도 안나온 다는 것이죠.
이럴 때 원인을 파악하기 위해 반드시 쳐야 하는 명령어가 바로 describe입니다.
# 특정 파드의 상세 정보와 생성 과정(Events) 확인
kubectl describe pod sample-pod
이 명령어를 치면 파드의 IP, 할당된 노드, 레이블, 컨테이너 정보 등 모든 상세 명세가 나옵니다.
하지만 여기서 가장 중요한 부분은 맨 아래에 출력되는 Events 항목입니다.
# (출력 예시 - 맨 아래 Events 부분)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 24s default-scheduler Successfully assigned default/sample-pod to node-1
Normal Pulling 23s kubelet Pulling image "nginx:latest"
Warning Failed 10s (x3 over 22s) kubelet Failed to pull image "nginx:latetst": rpc error: code = NotFound
💡실무 팁: 트러블슈팅의 시작은 Events 확인부터!
위 예시처럼 Events 탭을 보면 이미지 이름에 오타가 나서(latetst) 이미지를 당겨오지 못했다는 것을 단번에 알 수 있습니다.
문제가 생겼을 때는 가장 먼저 describe의 Events를 확인하는 습관을 들이는 것이 좋습니다.
top) 📊현재 노드나 파드가 CPU와 메모리를 얼마나 차지하고 있는지 확인하려면 top 명령어를 사용합니다.
단, 이 명령어는 Metric Server가 클러스터에 설치되어 있어야만 동작합니다.
# Metrics Server 설치 (공식 GitHub 매니페스트 적용)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# kube-system 네임스페이스에 metrics-server 파드가 잘 떴는지 확인
kubectl -n kube-system get pods

kubectl top node kubectl -n kube-system top pod kubectl -n kube-system top pod --containers 💡 실무 팁: Metrics Server의 한계와 Prometheus
kubectl top명령어는 "지금 이 순간"의 실시간 리소스 사용량만 보여줍니다. 과거의 사용량 기록이나 그래프 추이를 보려면, 실무에서는 프로메테우스(Prometheus)와 그라파나(Grafana)를 연동하여 모니터링 시스템을 구축하는 것이 표준입니다.
exec & cp) 💻컨테이너 내부에 직접 들어가서 구조를 뜯어보거나, 로컬과 컨테이너 간에 파일을 주고받아야 할 때 사용합니다.
exec)# 단일 컨테이너 파드에 쉘 접속 및 명령어 실행
kubectl exec -it sample-pod -- /bin/ls
# 여러 컨테이너가 묶인 파드의 경우, 특정 컨테이너(-c)를 지정하여 실행
kubectl exec -it sample-pod -c nginx-container -- /bin/ls
cp)로컬 컴퓨터의 파일을 컨테이너 내부로 밀어 넣거나, 반대로 컨테이너 안의 파일을 로컬로 가져올 때 사용합니다.
# 명령어 구조
kubectl cp [소스] [타겟]
port-forward) 🌐Service나 Ingress를 외부에 완전히 노출하지 않은 상태에서, 내 PC(로컬)에서 클러스터 내부 리소스로 직접 트래픽을 꽂아 테스트하고 싶을 때 사용합니다.
# 구조: 외부포트(내 PC) : 내부포트(클러스터 리소스)
kubectl port-forward [리소스종류]/[리소스이름] 외부포트:내부포트
⚠️ 주의할 점
port-forward는 개발 중 디버깅과 임시 테스트를 위한 도구입니다. 운영 환경에서 외부 트래픽을 받을 목적으로 사용해서는 절대 안 되며, 터미널 창을 닫으면 연결도 즉시 끊어집니다.
logs) 📝유지 보수를 할 때 중요하며, 장애 발생 시 원인 파악을 위해 가장 먼저 쳐봐야 하는 명령어가 바로 로그입니다.
kubectl logs [파드이름] kubectl logs [파드이름] -c [컨테이너이름] -f --since=[숫자단위] (예: 1시간 이내 --since=1h) --timestamp=true --tail=[개수] --selector [레이블] 💡 실무 팁: 죽어버린 이전 컨테이너의 로그 보기 (
--previous/-p)
파드가 자꾸 재시작 중(CrashLoopBackOff)일 때 그냥logs를 치면, 막 새로 떠서 아직 에러를 뱉지 않은 빈 화면만 나오는 경우가 있습니다. 이때 "죽어버린 직전 컨테이너가 마지막으로 뱉은 단말마(로그)"를 보려면--previous옵션을 꼭 함께 사용해 보세요!
실제 작업 환경에서 장애가 발생했을 때 어떤 흐름대로 트러블슈팅을 진행을 할까요.?
궁금해서 위에서 배운 명령어들을 실제 장애 상황에서 어떤 순서로 조합해서 쓰는지 찾아보고 하나의 흐름으로 정리해보았습니다.
get -w)배포 후 kubectl get pods -w를 켜두고 파드 상태가 실시간으로 변하는 것을 지켜봅니다. (-w 옵션은 실시간으로 작동되는 것을 보여줍니다.)
여기서 파드 하나가 Error 상태를 내며 작동을 멈췄다고 가정을 해보겠습니다.
describe)kubectl describe pod [에러난 파드]를 쳐서 맨 밑의 Events를 확인합니다.
CPU나 메모리 자원이 부족해서 노드에 할당을 못 받은 건지(Pending), 이미지 이름이 틀린 건지 등 인프라 단의 문제를 먼저 체크합니다.
logs)인프라 설정에 문제가 없다면, 내부 애플리케이션 로직 문제입니다.
kubectl logs -f --previous [파드 이름]을 쳐서 직전에 죽어버린 컨테이너가 뱉은 에러 로그(Exception)를 확인합니다.
exec)로그만으로 부족하다면 kubectl exec -it [파드 이름] -- /bin/sh로 직접 들어갑니다.
내부 라우팅 테이블이나 DNS 질의가 잘 되는지, 특정 포트가 열려있는지 등 네트워크와 환경 변수 상태를 직접 체크하며 문제를 좁혀나갑니다.
오늘은 모니터링과 트러블슈팅의 핵심 명령어(get -o, describe, top, exec, port-forward, logs, cp)들을 정리해 보았습니다.
아무리 완벽하게 설계된 아키텍처라도 에러는 무조건 발생하기 마련입니다. 오늘 배운 트러블슈팅 도구들을 적재적소에 조합하면 문제의 원인을 짚어내는 시간을 획기적으로 줄일 수 있을 것입니다.
다음 포스팅에서는 본격적으로 쿠버네티스 클러스터에서의 핵심 API 중 하나인 Workload API에 대해 알아보도록 하겠습니다.