infra
Platform

모듈 맵

[Kubernetes] get, describe, logs, exec 필수 kubectl 명령어 10선

0 / 29 완료

펼치기
0 / 29 완료0%

쿠버네티스 & GitOps · 03 / 29

[Kubernetes] get, describe, logs, exec 필수 kubectl 명령어 10선

get, describe, logs, exec, apply, delete — 실무에서 매일 쓰는 kubectl 명령어를 체계적으로 마스터합니다

🚨INCIDENT ALERT
HIGH

운영 배포 직후 파드가 CrashLoopBackOff가 되었지만 팀원이 kubectl get, describe, logs의 차이를 몰라 같은 명령만 반복하고 있습니다. Kubernetes 장애 대응의 첫 5분은 대부분 kubectl 출력 읽기에서 결정됩니다. 기본 명령을 손에 익혀야 다음 단계의 진단이 가능합니다.

kubectl 기본 명령어

팀에 합류한 첫 날, 선임이 말했다. "Pod가 자꾸 죽는데, 로그 좀 봐줄 수 있어?" kubectl을 처음 본 신입은 화면을 뚫어져라 쳐다봤다. 명령어를 모르니 아무것도 할 수 없었다. Kubernetes는 아무리 강력한 플랫폼이어도, kubectl을 다루지 못하면 블랙박스일 뿐이다. kubectl은 Kubernetes를 조종하는 유일한 손이다. get으로 상태를 확인하고, describe로 원인을 찾고, logs로 앱 내부를 들여다보고, exec로 컨테이너 안으로 들어간다. 이 네 개 명령어만 능숙해도, 대부분의 Pod 장애는 10분 안에 원인을 찾을 수 있다.


이번 챕터에서 배울 것

매일 쓰는 kubectl 명령어를 체계적으로 익히고, 각 명령어가 장애 진단의 어느 단계에서 쓰이는지 파악합니다.

  • 1kubectl get으로 리소스 목록을 조회하고 출력 형식(-o wide, -o yaml, -o json)을 조정할 수 있다
  • 2kubectl describe의 이벤트와 상세 정보로 장애 원인을 파악할 수 있다
  • 3kubectl logs(-f, --previous, --since)로 컨테이너 로그를 조회할 수 있다
  • 4kubectl exec으로 실행 중인 컨테이너 내부에 접속할 수 있다
  • 5kubectl apply/delete로 선언적 리소스를 관리할 수 있다
  • 6--dry-run=client -o yaml 패턴으로 YAML 템플릿을 생성할 수 있다
실습 환경 준비

minikube 사용 시: minikube start로 클러스터를 시작하세요. kubectl이 설치되어 있고 클러스터에 연결되어 있으면 바로 시작할 수 있습니다.

kubectl 설치 확인
kubectl version --client
클러스터 연결 확인
kubectl cluster-info
현재 컨텍스트 확인
kubectl config current-context
기본 네임스페이스 리소스 확인
kubectl get all
💡개념

kubectl 명령 한 줄이 처리되는 법 — 클라이언트에서 응답까지 5단계

kubectl get pods를 치면 목록이 뜨고, 가끔은 Forbidden이나 connection refused가 뜹니다. 클러스터 아키텍처 모듈이 apiserver 안에서 벌어지는 일을 봤다면, 여기서는 내 PC의 kubectl이 그 요청을 만들어 보내고 응답을 그리기까지 클라이언트 쪽에서 무슨 일이 일어나는지를 봅니다. 이 흐름을 알면 같은 "안 된다"라도 context 문제인지, 인증 만료인지, 권한 거부인지, 연결 실패인지를 에러 메시지만으로 구분할 수 있습니다.

TEXT
[내 PC]  kubectl get pods
   │
   ① kubeconfig 로드 → current-context 결정
   │      (~/.kube/config에서 cluster·user·namespace 한 세트를 고름)
   │
   ② API 엔드포인트·인증 재료 준비
   │      (server URL, CA 인증서, client-cert 또는 token)
   │
   ③ 명령을 REST 요청으로 조립 → 전송
   │      (get pods → GET /api/v1/namespaces/<ns>/pods, TLS로 apiserver에)
   │
   ④ apiserver 처리 → 응답 반환
   │      (인증 → 인가(RBAC) → etcd 조회 → JSON 응답)
   │
   ⑤ 응답 파싱 → 사람이 읽는 형식으로 출력
   ▼
[화면]  NAME  READY  STATUS ...   (-o wide/yaml/json으로 렌더링 형식만 바뀜)

각 단계가 무슨 일을 하고, 여기서 틀어지면 어떤 에러가 나는가:

단계하는 일여기서 틀어지면
① context 로드current-context의 cluster·user·namespace를 읽어 어느 클러스터·네임스페이스를 볼지 결정context가 다른 클러스터·네임스페이스를 가리킴 → 분명히 만든 리소스가 NotFound. 실제로는 다른 곳에 있음
② 인증 재료 준비server URL과 CA·client-cert·token을 로드인증서·토큰 만료 → Unauthorized (401), You must be logged in to the server
③ REST 요청 조립·전송하위 명령을 HTTP 동사·경로로 변환해 TLS로 전송server 주소가 틀리거나 클러스터 다운 → connection refused 또는 타임아웃
④ apiserver 처리인증 통과 후 RBAC로 권한 확인, etcd 조회 후 응답권한 부족 → Forbidden (403) cannot list resource "pods"
⑤ 응답 파싱·출력JSON 응답을 테이블·yaml·json으로 렌더링-o 형식 오타·jsonpath 오류 → 출력이 비거나 파싱 에러(요청 자체는 성공)

kubectl 에러는 대부분 "요청이 어느 단계에서 멈췄나"를 그대로 알려줍니다NotFound면 ①(context·네임스페이스)을, 401이면 ②(인증), refused·타임아웃이면 ③(연결), 403 Forbidden이면 ④(RBAC)를 봅니다. 안 될 때 가장 먼저 kubectl config current-contextkubectl config view --minify로 지금 어느 클러스터·계정·네임스페이스로 말하고 있는지 확인하는 습관이 ①~②의 착각을 즉시 걷어냅니다.

💡개념

kubectl get — 상태 확인의 시작점

장애 대응 첫 5분, 아무것도 모르는 상황에서 가장 먼저 해야 할 일은 현재 상태를 파악하는 것입니다. 파드가 Running인지, 몇 개가 Ready인지, 어느 노드에 배치됐는지를 빠르게 확인해야 다음 단계로 진단을 좁힐 수 있습니다. kubectl get은 클러스터의 리소스 목록과 기본 상태를 한눈에 보여주는 가장 자주 쓰이는 명령어입니다. -o wide, -o yaml, -l 플래그를 조합하면 IP, 노드, 레이블까지 원하는 정보를 골라 볼 수 있습니다. 이 CB에서는 일상적인 상태 확인부터 장애 시 빠른 파악까지 kubectl get의 핵심 사용 패턴을 다룹니다.

kubectl get — 상태 확인의 시작점확대

기본 사용법

Kubernetes
# Pod 목록
kubectl get pods
# NAME          READY   STATUS    RESTARTS   AGE
# nginx-xxx     1/1     Running   0          5m
# broken-xxx    0/1     Error     3          2m

# 모든 네임스페이스
kubectl get pods -A  # 또는 --all-namespaces
# NAMESPACE     NAME                    READY   STATUS    RESTARTS
# kube-system   coredns-xxx             1/1     Running   0
# default       nginx-xxx               1/1     Running   0

# 특정 네임스페이스
kubectl get pods -n kube-system

# 여러 리소스 동시 조회
kubectl get pods,services,deployments

# 모든 리소스 타입 조회
kubectl get all
🔍실행 후 확인할 것
  • kubectl get pods에서 STATUS 열을 먼저 확인 — Running이 아니면 CrashLoopBackOff/Pending/ImagePullBackOff 중 하나로, 각각 원인이 다름. kubectl describe pod <name>으로 Events에서 구체적 원인 파악
  • RESTARTS 수치 기준: 3회 미만은 일시적 오류, 5회 이상이면 kubectl logs <pod> --previous 로 이전 크래시 로그 확인. 10회 이상이면 liveness probe 설정 또는 메모리 limits 검토 필요
  • STATUS=Running이고 READY=0/1이면 → 컨테이너는 실행 중이지만 readinessProbe가 실패한 것. 서비스 트래픽이 차단된 상태로, kubectl describe pod에서 Readiness probe: 항목과 마지막 실패 이유 확인

출력 형식 조정

Kubernetes
# 넓은 형식 (노드 IP 포함)
kubectl get pods -o wide
# NAME       READY   STATUS    IP           NODE
# nginx-xxx  1/1     Running   10.244.0.5   minikube

# YAML 형식 (전체 스펙 확인)
kubectl get pod nginx-xxx -o yaml

# JSON 형식 (스크립트에서 파싱 시)
kubectl get pods -o json

# 특정 필드만 추출
kubectl get pods -o jsonpath='{.items[*].metadata.name}'
# nginx-xxx broken-xxx

# 테이블 커스텀 컬럼
kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName
# NAME       STATUS    NODE
# nginx-xxx  Running   minikube

라벨 필터링

Kubernetes
# 라벨로 필터
kubectl get pods -l app=nginx
kubectl get pods -l app=nginx,env=prod

# 라벨 표시
kubectl get pods --show-labels

# 실시간 감시 (상태 변화 추적)
kubectl get pods -w  # watch
💡개념

kubectl describe — 장애 원인의 보물창고

파드가 Pending인데 kubectl get만 보면 이유를 알 수 없습니다. 노드 자원 부족인지, 이미지 pull 실패인지, Affinity 조건 미충족인지 구분이 되지 않아 엉뚱한 방향으로 디버깅을 시작하게 됩니다. kubectl describe의 Events 섹션은 스케줄러와 kubelet이 파드에 무슨 일을 했는지 타임라인으로 기록합니다. "왜 그 상태인가"를 알려주는 핵심 도구입니다. 이 CB에서는 kubectl describe의 출력 구조와, Events 섹션에서 장애 원인을 빠르게 읽어내는 방법을 다룹니다. 특히 Events 섹션이 핵심입니다.

kubectl 진단 워크플로 — 넓게 좁히고 깊게 판다. ① kubectl get pods로 Running/Pending/CrashLoop과 RESTARTS를 훑어 문제 파드를 좁히고, ② kubectl describe pod로 Events 섹션에서 원인(이미지 pull 실패·리소스 부족·마운트)을 가설하고, ③ kubectl logs로 컨테이너 stdout/stderr(-p는 직전 크래시)를 확인하고, ④ 그래도 모르면 kubectl exec로 컨테이너 내부의 파일·프로세스·DNS·포트를 실측한다확대

기본 사용법

Kubernetes
kubectl describe pod <pod-name>
kubectl describe node <node-name>
kubectl describe deployment <deployment-name>
kubectl describe service <service-name>

describe 출력 구조 이해

Kubernetes
kubectl describe pod nginx-xxx
# Name:         nginx-xxx
# Namespace:    default
# Priority:     0
# Node:         minikube/192.168.49.2    ← 어느 노드에서 실행 중인지
# Start Time:   ...
# Labels:       app=nginx
# Status:       Running
# IP:           10.244.0.5
#
# Containers:
#   nginx:
#     Image:          nginx:alpine
#     Port:           80/TCP
#     State:          Running
#     Ready:          True
#     Restart Count:  0           ← 재시작 횟수 (높으면 문제)
#     Limits:         ...
#     Requests:       ...
#     Liveness:       http-get ... ← 헬스체크 설정
#
# Conditions:
#   Type              Status
#   Initialized       True
#   Ready             True        ← Ready가 False면 문제
#   ContainersReady   True
#   PodScheduled      True
#
# Events:                         ← 여기가 핵심!
#   Type    Reason     Age    Message
#   Normal  Scheduled  5m     Successfully assigned default/nginx-xxx to minikube
#   Normal  Pulling    5m     Pulling image "nginx:alpine"
#   Normal  Pulled     4m     Successfully pulled image
#   Normal  Created    4m     Created container nginx
#   Normal  Started    4m     Started container nginx

이벤트로 장애 진단

Kubernetes
# 이미지 pull 실패 예시
# Events:
#   Warning  Failed   2m   Failed to pull image "nginx:nonexistent": ...
#             ImagePullBackOff

# 리소스 부족으로 스케줄 실패
# Events:
#   Warning  FailedScheduling  ... 0/1 nodes available: 1 Insufficient memory.

# 네임스페이스 전체 이벤트 확인 (장애 시 빠른 파악)
kubectl get events --sort-by='.lastTimestamp'
kubectl get events --field-selector type=Warning  # 경고만
💡개념

kubectl logs, exec — 컨테이너 내부 들여다보기

파드가 Running인데 API가 500을 반환합니다. kubectl getkubectl describe에는 이상이 없고, 문제는 컨테이너 안에서 돌고 있는 애플리케이션에 있습니다. 이때 필요한 것이 kubectl logskubectl exec입니다. logs는 앱이 stdout/stderr에 출력한 내용을 보여주고, exec는 컨테이너 내부로 직접 들어가 환경변수, 파일, 네트워크 연결을 확인합니다. CrashLoopBackOff 상황에서는 --previous 플래그로 죽기 직전 로그를 볼 수 있습니다. 이 CB에서는 로그 조회와 컨테이너 내부 접속의 핵심 패턴을 다룹니다.

kubectl logs — 앱 로그 확인

Kubernetes
# 기본 로그 조회
kubectl logs <pod-name>

# 실시간 스트리밍
kubectl logs -f <pod-name>

# 마지막 N줄
kubectl logs --tail=100 <pod-name>

# 특정 시간 이후 로그
kubectl logs --since=1h <pod-name>
kubectl logs --since-time="2024-01-15T10:00:00Z" <pod-name>

# 이전 컨테이너 로그 (CrashLoopBackOff 시 필수)
kubectl logs --previous <pod-name>
# ← 현재 컨테이너가 죽기 전 로그를 봄

# 멀티 컨테이너 Pod에서 특정 컨테이너 로그
kubectl logs <pod-name> -c <container-name>

# 라벨 셀렉터로 여러 Pod 로그 동시
kubectl logs -l app=nginx --tail=50

kubectl exec — 컨테이너 내부 접속

Kubernetes
# 인터랙티브 셸 접속
kubectl exec -it <pod-name> -- bash
kubectl exec -it <pod-name> -- sh  # bash 없을 때

# 단일 명령어 실행 (셸 없이)
kubectl exec <pod-name> -- ls /app
kubectl exec <pod-name> -- cat /etc/nginx/nginx.conf
kubectl exec <pod-name> -- env | grep DB

# 멀티 컨테이너 Pod에서 특정 컨테이너
kubectl exec -it <pod-name> -c <container-name> -- bash

# 환경변수 확인 (설정 디버깅 시)
kubectl exec <pod-name> -- env

# 네트워크 확인 (내부에서 다른 서비스 접근 테스트)
kubectl exec -it <pod-name> -- curl http://other-service:8080/health
kubectl exec -it <pod-name> -- nslookup other-service

실습: 핵심 명령어 마스터하기

실습 1: 기본 CRUD 패턴

로컬 터미널
# 실습용 리소스 생성
cat <<EOF > /tmp/practice-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: practice-nginx
  labels:
    app: practice
    env: dev
spec:
  containers:
  - name: nginx
    image: nginx:alpine
    ports:
    - containerPort: 80
    env:
    - name: MY_ENV
      value: "hello-k8s"
EOF

# 적용
kubectl apply -f /tmp/practice-pod.yaml
# pod/practice-nginx created

# 상태 확인
kubectl get pod practice-nginx -o wide

# 상세 확인
kubectl describe pod practice-nginx

# 라벨 필터링
kubectl get pods -l app=practice

실습 2: 로그와 exec 실습

Kubernetes
# nginx 로그 확인
kubectl logs practice-nginx

# 실시간 로그 (다른 터미널에서 curl을 날리면서 확인)
kubectl logs -f practice-nginx

# 컨테이너 내부 접속
kubectl exec -it practice-nginx -- sh

# 내부에서 실행할 명령어들:
# ls /usr/share/nginx/html
# cat /etc/nginx/nginx.conf | head -20
# env | grep MY_ENV  # MY_ENV=hello-k8s 확인
# exit

실습 3: --dry-run과 -o yaml 패턴

Kubernetes
# 실제 생성 없이 YAML 생성 (템플릿 작성 시 유용)
kubectl run my-app --image=nginx:alpine --dry-run=client -o yaml
# apiVersion: v1
# kind: Pod
# metadata:
#   creationTimestamp: null
#   labels:
#     run: my-app
#   name: my-app
# spec:
#   containers:
#   - image: nginx:alpine
#     name: my-app
#     resources: {}
# ...

# 파일로 저장해서 수정 후 사용
kubectl run my-app --image=nginx:alpine --dry-run=client -o yaml > /tmp/my-app.yaml

# 기존 리소스의 YAML 추출 (현재 설정 확인)
kubectl get pod practice-nginx -o yaml > /tmp/practice-nginx-export.yaml
위험 명령어Pod가 삭제되면 해당 컨테이너의 모든 프로세스가 즉시 종료됩니다. 이 실습 파드는 개발 클러스터 전용이지만, 현재 컨텍스트가 실수로 프로덕션 클러스터를 가리키고 있다면 실제 서비스 파드를 삭제할 수 있습니다.

Pod 삭제 — 즉시 종료, 처리 중인 요청 강제 중단

안전한 실행 조건: kubectl config current-context 로 현재 컨텍스트가 minikube 또는 로컬 개발 클러스터인지 반드시 확인 후 실행하세요.

실행 전 반드시 확인

  • kubectl config current-context 로 현재 컨텍스트가 개발 클러스터(minikube 등)인지 확인
  • kubectl get pod practice-nginx 로 삭제 대상이 실습용 파드인지 이름 확인
kubectl delete pod practice-nginx

위 항목을 모두 확인한 후 복사할 수 있습니다

Kubernetes
# 정리
kubectl delete pod practice-nginx

실습 4: kubectl apply vs create 비교

로컬 터미널
cat <<EOF > /tmp/test-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: test-config
data:
  key: "value1"
EOF

# apply: 없으면 생성, 있으면 업데이트
kubectl apply -f /tmp/test-cm.yaml
# configmap/test-config created

kubectl apply -f /tmp/test-cm.yaml
# configmap/test-config unchanged  ← 이미 동일하면 변경 없음

# 내용 변경 후 재apply
sed -i 's/value1/value2/' /tmp/test-cm.yaml
kubectl apply -f /tmp/test-cm.yaml
# configmap/test-config configured  ← 변경됨

# create는 이미 존재하면 에러
kubectl create -f /tmp/test-cm.yaml
# Error from server (AlreadyExists): configmaps "test-config" already exists

# 정리
kubectl delete configmap test-config

상황

Kubernetes
kubectl logs my-pod
# Error from server (NotFound): pods "my-pod" not found

kubectl describe pod my-pod
# Error from server (NotFound): pods "my-pod" not found

분명히 배포했는데 Pod를 찾을 수 없다는 에러입니다.

진단: 네임스페이스 확인

Kubernetes
# 1. 현재 컨텍스트의 네임스페이스 확인
kubectl config get-contexts
# CURRENT   NAME       CLUSTER    AUTHINFO   NAMESPACE
# *         minikube   minikube   minikube   (비어있으면 default)

# 2. 모든 네임스페이스에서 검색
kubectl get pods -A | grep my-pod
# production   my-pod   1/1   Running   0   5m
# ↑ 'production' 네임스페이스에 있었음!

# 3. 네임스페이스를 명시해서 명령 실행
kubectl logs my-pod -n production
kubectl describe pod my-pod -n production

원인과 해결

원인해결
다른 네임스페이스에 배포됨-n <namespace> 플래그 추가
Pod가 실제로 없음 (배포 실패)kubectl get events로 배포 오류 확인
이름 오타kubectl get pods -A | grep <partial-name>
이미 종료되어 삭제됨Job/CronJob이면 정상 (--previous 로그 확인)

기본 네임스페이스 변경 (자주 쓰는 네임스페이스가 있을 때)

Kubernetes
# 현재 컨텍스트의 기본 네임스페이스 변경
kubectl config set-context --current --namespace=production

# 이후 -n 생략 가능
kubectl get pods  # production 네임스페이스가 기본

# 다시 default로
kubectl config set-context --current --namespace=default

핵심 교훈: NotFound 에러의 80%는 네임스페이스 문제입니다. 항상 -A 플래그로 모든 네임스페이스를 먼저 확인하세요.

실습 단계
1

실습용 파드 생성 및 상태 확인

kubectl run practice-nginx --image=nginx:alpine --labels=app=practice kubectl get pod practice-nginx -o wide

예상 출력

NAME             READY   STATUS    RESTARTS   AGE   IP
practice-nginx   1/1     Running   0          ...
2

describe로 이벤트 확인

kubectl describe pod practice-nginx | grep -A 10 Events

예상 출력

Events:
  Type    Reason     Age   Message
  Normal  Scheduled  ...   Successfully assigned
3

컨테이너 로그 조회

kubectl logs practice-nginx --tail=20

예상 출력

/docker-entrypoint.sh: Configuration complete; ready for start up
4

컨테이너 내부 명령어 실행

kubectl exec practice-nginx -- nginx -v kubectl exec practice-nginx -- ls /usr/share/nginx/html

예상 출력

nginx version: nginx/
index.html  50x.html
5

dry-run으로 YAML 생성 후 파드 정리

kubectl run my-app --image=nginx:alpine --dry-run=client -o yaml | head -10 kubectl delete pod practice-nginx

예상 출력

apiVersion: v1
kind: Pod
pod "practice-nginx" deleted

심화 — exec가 통하지 않을 때

💡개념

심화: 셸 없는 이미지와 임시(ephemeral) 디버그 컨테이너

kubectl exec는 만능처럼 보이지만, 정작 프로덕션 파드에 들어가려 할 때 막히는 경우가 많습니다. 그 이유와 우회로를 알아야 실전 디버깅이 가능합니다.

  • exec는 컨테이너 안에 있는 바이너리를 빌려 쓰는 것입니다: kubectl exec는 대상 컨테이너의 프로세스 네임스페이스 안에서 지정한 실행 파일(sh/bash/ls)을 새 프로세스로 실행합니다. 그 바이너리가 이미지에 없으면 executable file not found가 납니다.
  • 요즘 프로덕션 이미지엔 셸이 일부러 없습니다: 보안과 크기를 위해 distroless(gcr.io/distroless)나 scratch 기반으로 빌드하면 sh는 물론 ls, cat조차 없습니다. exec -- sh, exec -- bash 둘 다 실패하는 건 잘못 배포된 게 아니라 의도된 슬림 이미지라는 신호입니다.
  • 그래서 exec 대신 임시(ephemeral) 컨테이너를 붙입니다: kubectl debug -it <pod> --image=busybox --target=<container>는 도구가 든 컨테이너를 실행 중인 파드에 추가합니다. --target으로 대상 컨테이너의 프로세스 네임스페이스를 공유하면, 앱 이미지는 건드리지 않고 그 프로세스와 /proc를 통한 파일시스템까지 들여다볼 수 있습니다. 파드 재시작도 필요 없습니다.

정리하면 exec는 컨테이너가 스스로 진단 도구를 품고 있어야 통합니다. 도구가 없는 슬림 이미지는 exec가 아니라 ephemeral 디버그 컨테이너를 표준으로 삼아야 합니다.

상황: 프로덕션 파드가 500을 내서 안에 들어가 설정 파일을 보려고 kubectl exec -it -- sh를 실행했더니 not found. bash로 바꿔도 마찬가지입니다. kubectl get pod로 보면 파드는 1/1 Running으로 멀쩡합니다.

원인: 이미지가 distroless나 scratch 기반이라 셸과 기본 유틸리티가 아예 들어 있지 않습니다. exec는 컨테이너 안의 바이너리를 실행하는 것이라, 없는 sh를 실행할 수 없어 executable file not found가 납니다. 파드가 Running이라는 사실과 셸 유무는 무관합니다.

진단: kubectl get pod <pod> -o jsonpath로 컨테이너 image를 확인하거나 kubectl describe pod의 Image 필드를 봅니다. distroless/scratch 계열이면 확정입니다. exec -- ls마저 not found면 셸뿐 아니라 기본 유틸리티도 없는 것입니다.

해결: kubectl debug -it <pod> --image=busybox:1.36 --target=<container>로 busybox를 임시 컨테이너로 얹고, 그 안에서 ps, wget, cat /proc/1/root/... 로 대상 컨테이너의 프로세스와 파일을 진단합니다. --target으로 프로세스 네임스페이스를 공유해야 대상 컨테이너 내부가 보입니다. 앱 로그와 환경변수는 컨테이너 밖에서 kubectl logs와 kubectl get pod -o yaml로 확인하면 됩니다. 프로덕션 이미지는 셸이 없는 게 정상이므로, 디버깅 표준을 exec에서 ephemeral 컨테이너로 옮기는 것이 근본 대응입니다.

💼
실무 맥락
현업 패턴

실무 시나리오: kubectl 장애 대응 플로우

팀장: "API 서버에서 500 에러가 납니다."

1단계: 빠른 상태 파악 (30초)

Kubernetes
kubectl get pods -n production
# NAME           READY   STATUS             RESTARTS   AGE
# api-server-xxx 0/1     CrashLoopBackOff   5          10m

2단계: 이벤트로 원인 파악 (1분)

Kubernetes
kubectl describe pod api-server-xxx -n production | grep -A20 Events
# Events:
#   Warning  BackOff  ... Back-off restarting failed container

3단계: 로그로 앱 오류 확인 (2분)

Kubernetes
# 현재 컨테이너 로그
kubectl logs api-server-xxx -n production --tail=50
# Error: Cannot connect to database at postgres:5432

# 이전 컨테이너 로그 (죽기 직전)
kubectl logs api-server-xxx -n production --previous | tail-20

4단계: 내부 진단 (필요시)

Kubernetes
# DB 연결 확인
kubectl exec -it api-server-xxx -n production -- nc -zv postgres 5432
# postgres (5432:) open  ← 연결 가능
# postgres (5432:) refused  ← DB 다운

# 환경변수 확인
kubectl exec api-server-xxx -n production -- env | grep DB

총 소요 시간: 5분 이내에 "DB 연결 문제" 파악 완료.

kubectl get → describe → logs → exec 이 4단계 흐름이 K8s 장애 진단의 표준 패턴입니다.


명령어·단축키 빠른 참조

이 모듈에서 다룬 kubectl 기본 명령을 자주 쓰는 플래그·조합과 함께 모았습니다.

명령어/단축키용도자주 쓰는 예
kubectl get리소스 목록·상태(진단 시작점)kubectl get pods -A -o wide, -l app=nginx, -w(watch)
kubectl get -o출력 형식 조정·필드 추출-o yaml, -o jsonpath='{.items[*].metadata.name}', -o custom-columns=...
kubectl describeEvents·Conditions로 원인 파악kubectl describe pod X | grep -A15 Events
kubectl logs앱 stdout/stderr 확인kubectl logs -f X --tail=100, --since=1h
kubectl logs --previous크래시 직전 로그(CrashLoopBackOff)kubectl logs X --previous
kubectl exec -it실행 중 컨테이너 셸 접속kubectl exec -it X -- sh (bash 없을 때), -c <container>
kubectl exec -- (단일)셸 없이 명령 실행kubectl exec X -- env | grep DB, -- nc -zv postgres 5432
kubectl apply / create선언적 관리 / 일회성 생성kubectl apply -f pod.yaml (create는 존재 시 AlreadyExists)
--dry-run=client -o yaml배포 없이 YAML 템플릿 생성kubectl run app --image=nginx --dry-run=client -o yaml > app.yaml
kubectl config컨텍스트·기본 네임스페이스 변경kubectl config set-context --current --namespace=production
-n / -A네임스페이스 지정 / 전체kubectl get pods -n kube-system, kubectl get pods -A | grep X

관련 모듈로 더 깊이:

다음 모듈 pod-lifecycle에서는 Pod가 Pending → Running → Succeeded/Failed로 전환되는 상태 머신을 이해하고, CrashLoopBackOff와 ImagePullBackOff 같은 실무에서 자주 만나는 에러를 체계적으로 진단합니다.

지식 확인

퀴즈 — 8문제

Q1

`kubectl get pods`와 `kubectl describe pod <name>`의 가장 큰 차이점은?

Q2

`kubectl apply -f`와 `kubectl create -f`의 차이점은?

Q3

실행 중인 Pod의 컨테이너 내부에서 셸 명령을 실행하려면?

Q4

`kubectl get pods -o yaml`에서 `-o yaml` 플래그의 주요 활용 용도는?

Q5

파드가 CrashLoopBackOff 상태다. 원인을 보려면 어떤 kubectl 명령이 가장 직접적인가?

Q6

다른 네임스페이스(kube-system)의 파드를 보려면?

Q7

[심화] 프로덕션 파드에 kubectl exec -it -- sh로 들어가려는데 executable file not found가 난다. 파드는 Running이다. 가장 가능성 높은 원인은?

Q8

[심화] 셸이 없는 distroless 파드의 내부(프로세스·파일)를 살아 있는 채로 진단해야 한다. 표준적인 방법은?

0 / 8 답변

🧪 실습으로 확인하기

K8s 기초 — Pod/Deployment/Service 생성

초급

kubectl로 nginx Pod를 생성하고 Deployment와 Service를 차례로 만들어 클러스터 외부에서 접근 가능한 상태까지 구성한다. K8s 3대 리소스의 역할과 관계를 직접 손으로 익힌다.

55📋 5단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요