=================
== The Archive ==
=================

[그림과 실습으로 배우는 쿠버네티스 입문] 5장. 트러블 슈팅 가이드와 kubectl 명령어 사용법

|

cover.jpg

5.1 트러블 슈팅 가이드

flowchart TD
    A[kubectl get pod 실행한 결과,<br/>Pod가 전부 Running인가?] -->|NO| B[Pod의 상태가?]
    A -->|YES| C[Pod의 컨테이너는 전부 Ready인가?]
    B -->|CrashLoopBackOff| D[컨테이너의 로그를 조회하여 오류가 출력되면 고친다.]
    B -->|ImagePullBackOff| H[이미지 이름이 잘못 되었을 수 있다.]
    B -->|Pending| E[kubectl describe pod `Pod 이름`으로 Events의 내용을 확인한다.]
    D -->|오류가 출력되지 않는다.| D1[CrashLoopBackOff를 반복하고 있다면 Liveness probe 설정 확인]
    H -->|이미지 이름이 틀리지 않았다.| I[태그 이름이 잘못되었을 수 있다.]
    I -->|태그 이름이 틀리지 않았다.| K[프라이빗 리포지터리라면<br/>리포지터리 접근 설정에 문제일 수 있다.]
    C -->|NO| N[kubectl describe pod `Pod 이름`<br/>Readiness probe / Liveness probe는 정상인가?<br/>아니라면 Probe 설정을 고친다.]
    C -->|YES| O[kubectl logs `Pod 이름`<br/>결과 로그에 오류가 출력되었다면 애플리케이션을 고쳐야 한다.]
    O -->|로그에 오류가 없다.| P[kubectl describe service `Service 이름`<br/>으로 Endpoint 목록이 표시되지 않으면<br/>Service의 selector가 잘못 설정되었을 수 있다.]
    P -->|Service의 selector 설정에 문제가 없다.| Q[만약 kubectl port-forward service/'Service 이름' 8080:`service port` 를 실행하여 애플리케이션에 접속할 수 없다면<br/>Service의 TargetPort와 컨테이너의 포트 번호가 잘못 설정되었을 수 있다.]

5.1.1 트러블 슈팅에 도움이 되는 Pod의 STATUS 컬럼

1
2
3
4
~/gitFolders/build-breaking-fixing-kubernetes master                   14:23:30
❯ kubectl get pods --namespace default                                    
NAME          READY   STATUS    RESTARTS   AGE
hello-world   1/1     Running   0          75s
상태 (Status)의미 (Meaning)
PendingKubernetes 클러스터에서 Pod 생성이 허가되었지만, 하나 이상의 컨테이너가 준비 중인 상태입니다. Pod가 처음 시작될 때는 이 STATUS가 표시될 수 있지만, 오랫동안 이 STATUS가 유지된다면 문제가 있다고 의심해야 합니다. Pod의 Events를 참조하여 원인에 대한 단서를 찾아보세요.
RunningPod가 노드에 스케줄링되었고 모든 컨테이너가 생성된 상태입니다. 하나 이상의 컨테이너가 실행 중이거나 시작 또는 재시작 중입니다. 항상 실행 중이어야 하는 Pod라면 정상적인 STATUS입니다.
CompletedPod 내의 모든 컨테이너가 완료된 상태입니다. 재시작되지 않습니다.
Unknown어떠한 이유로 Pod의 상태를 가져오지 못했습니다. 이 STATUS는 일반적으로 Pod가 실행되는 노드와의 통신 오류로 발생합니다.
ErrImagePull이미지를 가져오지 못했습니다. Pod의 Events를 참조하여 원인에 대한 단서를 찾아보세요.
Error컨테이너가 비정상적으로 종료되었습니다. Pod의 로그를 참조하여 원인에 대한 단서를 찾아보세요.
OOMKilled컨테이너가 메모리 부족(Out Of Memory)으로 종료되었습니다. Pod의 사용 리소스를 늘려 보세요.
TerminatingPod가 삭제 중인 상태입니다. Terminating 상태가 반복된다면 이상으로 간주해야 합니다. Pod의 Events를 참조하여 원인에 대한 단서를 찾아보세요.

5.2 kubectl로 현황 파악하기

1
2
3
4
5
~/gitFolders/build-breaking-fixing-kubernetes master*                  14:41:10
❯ kubectl get pods --namespace default
NAME                  READY   STATUS    RESTARTS   AGE
another-hello-world   1/1     Running   0          45s
hello-world           1/1     Running   0          18m

5.2.1 리소스 확인하기: kubectl get

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
~
❯ kubectl get pod --namespace default 
NAME                  READY   STATUS    RESTARTS   AGE
another-hello-world   1/1     Running   0          102m
hello-world           1/1     Running   0          120m

~
❯ kubectl get pods --namespace default
NAME                  READY   STATUS    RESTARTS   AGE
another-hello-world   1/1     Running   0          103m
hello-world           1/1     Running   0          120m

~
❯ kubectl get pod -n default          
NAME                  READY   STATUS    RESTARTS   AGE
another-hello-world   1/1     Running   0          105m
hello-world           1/1     Running   0          123m

~
❯ kubectl get pods -n default         
NAME                  READY   STATUS    RESTARTS   AGE
another-hello-world   1/1     Running   0          105m
hello-world           1/1     Running   0          123m
1
2
3
4
5
6
7
8
9
~
❯ kubectl get pod hello-world --namespace default
NAME          READY   STATUS    RESTARTS   AGE
hello-world   1/1     Running   0          131m

~
❯ kubectl get pod another-hello-world --namespace default
NAME                  READY   STATUS    RESTARTS   AGE
another-hello-world   1/1     Running   0          113m
1
2
3
4
5
~
❯ kubectl get pod --output wide --namespace default      
NAME                  READY   STATUS    RESTARTS   AGE    IP           NODE                 NOMINATED NODE   READINESS GATES
another-hello-world   1/1     Running   0          115m   10.244.0.6   kind-control-plane   <none>           <none>
hello-world           1/1     Running   0          133m   10.244.0.5   kind-control-plane   <none>           <none>
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
~
❯ kubectl get pod hello-world --output yaml --namespace default
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"app":"hello-world"},"name":"hello-world","namespace":"default"},"spec":{"containers":[{"image":"hello-server:1.0.0","imagePullPolicy":"IfNotPresent","name":"hello-server","ports":[{"containerPort":8080}]}]}}
  creationTimestamp: "2025-11-22T05:23:32Z"
  generation: 1
  labels:
    app: hello-world
  name: hello-world
  namespace: default
  resourceVersion: "8988"
  uid: 8b7b2fff-3c2a-48a2-bf06-c13f44705de2
spec:
  containers:
  - image: hello-server:1.0.0
    imagePullPolicy: IfNotPresent
    name: hello-server
    ports:
    - containerPort: 8080
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-ptcq2
      readOnly: true
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  nodeName: kind-control-plane
  preemptionPolicy: PreemptLowerPriority
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - name: kube-api-access-ptcq2
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2025-11-22T05:23:34Z"
    observedGeneration: 1
    status: "True"
    type: PodReadyToStartContainers
  - lastProbeTime: null
    lastTransitionTime: "2025-11-22T05:23:32Z"
    observedGeneration: 1
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: "2025-11-22T05:23:34Z"
    observedGeneration: 1
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: "2025-11-22T05:23:34Z"
    observedGeneration: 1
    status: "True"
    type: ContainersReady
  - lastProbeTime: null
    lastTransitionTime: "2025-11-22T05:23:32Z"
    observedGeneration: 1
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: containerd://375c3b01c73f9d4ea301aa368dc22796a2dcfa952d5cb12f2463a8e45876c153
    image: docker.io/library/hello-server:1.0.0
    imageID: sha256:09826592b0f07d8fef9da91e8d692a5215f870db4bd573bf78d891acc0624bf2
    lastState: {}
    name: hello-server
    ready: true
    resources: {}
    restartCount: 0
    started: true
    state:
      running:
        startedAt: "2025-11-22T05:23:33Z"
    user:
      linux:
        gid: 0
        supplementalGroups:
        - 0
        - 1
        - 2
        - 3
        - 4
        - 6
        - 10
        - 11
        - 20
        - 26
        - 27
        uid: 0
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-ptcq2
      readOnly: true
      recursiveReadOnly: Disabled
  hostIP: 172.20.0.2
  hostIPs:
  - ip: 172.20.0.2
  observedGeneration: 1
  phase: Running
  podIP: 10.244.0.5
  podIPs:
  - ip: 10.244.0.5
  qosClass: BestEffort
  startTime: "2025-11-22T05:23:32Z"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"app":"hello-world"},"name":"hello-world","namespace":"default"},"spec":{"containers":[{"image":"hello-server:1.0.0","imagePullPolicy":"IfNotPresent","name":"hello-server","ports":[{"containerPort":8080}]}]}}
  creationTimestamp: "2025-11-22T05:23:32Z"
  generation: 1
  labels:
    app: hello-world
  name: hello-world
  namespace: default
  resourceVersion: "8988"
  uid: 8b7b2fff-3c2a-48a2-bf06-c13f44705de2
spec:
  containers:
  - image: hello-server:1.0.0
    imagePullPolicy: IfNotPresent
    name: hello-server
    ports:
lines 1-20
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
~/gitFolders/build-breaking-fixing-kubernetes/chapter-04 master
❯ kubectl get pod hello-world --output yaml --namespace default > hello-world-pod.yaml

~/gitFolders/build-breaking-fixing-kubernetes/chapter-04 master*
❯ diff hello-world-pod.yaml hello-world.yaml 
4,8c4
<   annotations:
<     kubectl.kubernetes.io/last-applied-configuration: |
<       {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"app":"hello-world"},"name":"hello-world","namespace":"default"},"spec":{"containers":[{"image":"hello-server:1.0.0","imagePullPolicy":"IfNotPresent","name":"hello-server","ports":[{"containerPort":8080}]}]}}
<   creationTimestamp: "2025-11-22T05:23:32Z"
<   generation: 1
---
>   name: hello-world
11,14d6
<   name: hello-world
<   namespace: default
<   resourceVersion: "8988"
<   uid: 8b7b2fff-3c2a-48a2-bf06-c13f44705de2
17,139c9,13
<   - image: hello-server:1.0.0
<     imagePullPolicy: IfNotPresent
<     name: hello-server
<     ports:
<     - containerPort: 8080
<       protocol: TCP
<     resources: {}
<     terminationMessagePath: /dev/termination-log
<     terminationMessagePolicy: File
<     volumeMounts:
<     - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
<       name: kube-api-access-ptcq2
<       readOnly: true
<   dnsPolicy: ClusterFirst
<   enableServiceLinks: true
<   nodeName: kind-control-plane
<   preemptionPolicy: PreemptLowerPriority
<   priority: 0
<   restartPolicy: Always
<   schedulerName: default-scheduler
<   securityContext: {}
<   serviceAccount: default
<   serviceAccountName: default
<   terminationGracePeriodSeconds: 30
<   tolerations:
<   - effect: NoExecute
<     key: node.kubernetes.io/not-ready
<     operator: Exists
<     tolerationSeconds: 300
<   - effect: NoExecute
<     key: node.kubernetes.io/unreachable
<     operator: Exists
<     tolerationSeconds: 300
<   volumes:
<   - name: kube-api-access-ptcq2
<     projected:
<       defaultMode: 420
<       sources:
<       - serviceAccountToken:
<           expirationSeconds: 3607
<           path: token
<       - configMap:
<           items:
<           - key: ca.crt
<             path: ca.crt
<           name: kube-root-ca.crt
<       - downwardAPI:
<           items:
<           - fieldRef:
<               apiVersion: v1
<               fieldPath: metadata.namespace
<             path: namespace
< status:
<   conditions:
<   - lastProbeTime: null
<     lastTransitionTime: "2025-11-22T05:23:34Z"
<     observedGeneration: 1
<     status: "True"
<     type: PodReadyToStartContainers
<   - lastProbeTime: null
<     lastTransitionTime: "2025-11-22T05:23:32Z"
<     observedGeneration: 1
<     status: "True"
<     type: Initialized
<   - lastProbeTime: null
<     lastTransitionTime: "2025-11-22T05:23:34Z"
<     observedGeneration: 1
<     status: "True"
<     type: Ready
<   - lastProbeTime: null
<     lastTransitionTime: "2025-11-22T05:23:34Z"
<     observedGeneration: 1
<     status: "True"
<     type: ContainersReady
<   - lastProbeTime: null
<     lastTransitionTime: "2025-11-22T05:23:32Z"
<     observedGeneration: 1
<     status: "True"
<     type: PodScheduled
<   containerStatuses:
<   - containerID: containerd://375c3b01c73f9d4ea301aa368dc22796a2dcfa952d5cb12f2463a8e45876c153
<     image: docker.io/library/hello-server:1.0.0
<     imageID: sha256:09826592b0f07d8fef9da91e8d692a5215f870db4bd573bf78d891acc0624bf2
<     lastState: {}
<     name: hello-server
<     ready: true
<     resources: {}
<     restartCount: 0
<     started: true
<     state:
<       running:
<         startedAt: "2025-11-22T05:23:33Z"
<     user:
<       linux:
<         gid: 0
<         supplementalGroups:
<         - 0
<         - 1
<         - 2
<         - 3
<         - 4
<         - 6
<         - 10
<         - 11
<         - 20
<         - 26
<         - 27
<         uid: 0
<     volumeMounts:
<     - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
<       name: kube-api-access-ptcq2
<       readOnly: true
<       recursiveReadOnly: Disabled
<   hostIP: 172.20.0.2
<   hostIPs:
<   - ip: 172.20.0.2
<   observedGeneration: 1
<   phase: Running
<   podIP: 10.244.0.5
<   podIPs:
<   - ip: 10.244.0.5
<   qosClass: BestEffort
<   startTime: "2025-11-22T05:23:32Z"
---
>     - name: hello-server
>       image: hello-server:1.0.0 # chapter-01/hello-server
>       imagePullPolicy: IfNotPresent
>       ports:
>         - containerPort: 8080

--output(-o) 으로 jsonpath 를 사용해 필드를 지정하여 출력하기

1
2
3
~
❯ kubectl get pod hello-world --output jsonpath='{.spec.containers[].image}' --namespace default
hello-server:1.0.0%                                                             
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
~ 10s
❯ brew info jaq   
==> jaq: stable 2.3.0 (bottled), HEAD
JQ clone focussed on correctness, speed, and simplicity
https://github.com/01mf02/jaq
Conflicts with:
  json2tsv (because both install `jaq` binaries)
Installed
/opt/homebrew/Cellar/jaq/2.3.0 (8 files, 2.3MB) *
  Poured from bottle using the formulae.brew.sh API on 2025-11-23 at 01:10:20
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/j/jaq.rb
License: MIT
==> Dependencies
Build: rust ✘
==> Options
--HEAD
	Install HEAD version
==> Downloading https://formulae.brew.sh/api/formula/jaq.json
==> Analytics
install: 145 (30 days), 233 (90 days), 1,739 (365 days)
install-on-request: 145 (30 days), 233 (90 days), 1,739 (365 days)
build-error: 0 (30 days)

~
❯ kubectl get pod hello-world --output json --namespace default | jaq '.spec.containers[].image'
"hello-server:1.0.0"

--vkubectl 출력 결과의 로그 레벨 지정하기

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
~
❯ kubectl get pod hello-world --v=7 --namespace default
I1123 01:14:30.559232   27416 cmd.go:527] kubectl command headers turned on
I1123 01:14:30.563318   27416 loader.go:402] Config loaded from file:  /Users/bossm0n5t3r/.kube/config
I1123 01:14:30.563624   27416 envvar.go:172] "Feature gate default state" feature="ClientsPreferCBOR" enabled=false
I1123 01:14:30.563633   27416 envvar.go:172] "Feature gate default state" feature="InOrderInformers" enabled=true
I1123 01:14:30.563636   27416 envvar.go:172] "Feature gate default state" feature="InformerResourceVersion" enabled=false
I1123 01:14:30.563639   27416 envvar.go:172] "Feature gate default state" feature="WatchListClient" enabled=false
I1123 01:14:30.563642   27416 envvar.go:172] "Feature gate default state" feature="ClientsAllowCBOR" enabled=false
I1123 01:14:30.566184   27416 round_trippers.go:527] "Request" verb="GET" url="https://127.0.0.1:50038/api/v1/namespaces/default/pods/hello-world" headers=<
	Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json
	User-Agent: kubectl/v1.34.2 (darwin/arm64) kubernetes/8cc511e
 >
I1123 01:14:30.583893   27416 round_trippers.go:632] "Response" status="200 OK" milliseconds=17
NAME          READY   STATUS    RESTARTS   AGE
hello-world   1/1     Running   2          10h
VerbosityDescription
--v=0Generally useful for this to always be visible to a cluster operator.
--v=1A reasonable default log level if you don’t want verbosity.
--v=2Useful steady state information about the service and important log messages that may correlate to significant changes in the system. This is the recommended default log level for most systems.
--v=3Extended information about changes.
--v=4Debug level verbosity.
--v=5Trace level verbosity.
--v=6Display requested resources.
--v=7Display HTTP request headers.
--v=8Display HTTP request contents.
--v=9Display HTTP request contents without truncation of contents.

5.2.2 리소스 상세 정보 출력하기: kubectl describe

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
~
❯ kubectl describe pod hello-world --namespace default
Name:             hello-world
Namespace:        default
Priority:         0
Service Account:  default
Node:             kind-control-plane/172.20.0.2
Start Time:       Sat, 22 Nov 2025 14:23:32 +0900
Labels:           app=hello-world
Annotations:      <none>
Status:           Running
IP:               10.244.0.2
IPs:
  IP:  10.244.0.2
Containers:
  hello-server:
    Container ID:   containerd://5b9ddc08be13da7f191675b8a7e11920ac9b64eb6cb95b5a35a426d2565070dd
    Image:          hello-server:1.0.0
    Image ID:       sha256:09826592b0f07d8fef9da91e8d692a5215f870db4bd573bf78d891acc0624bf2
    Port:           8080/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sun, 23 Nov 2025 18:00:09 +0900
    Last State:     Terminated
      Reason:       Unknown
      Exit Code:    255
      Started:      Sun, 23 Nov 2025 17:59:53 +0900
      Finished:     Sun, 23 Nov 2025 18:00:04 +0900
    Ready:          True
    Restart Count:  4
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-ptcq2 (ro)
Conditions:
  Type                        Status
  PodReadyToStartContainers   True 
  Initialized                 True 
  Ready                       True 
  ContainersReady             True 
  PodScheduled                True 
Volumes:
  kube-api-access-ptcq2:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    Optional:                false
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason          Age    From     Message
  ----    ------          ----   ----     -------
  Normal  SandboxChanged  6m52s  kubelet  Pod sandbox changed, it will be killed and re-created.
  Normal  Pulled          6m51s  kubelet  Container image "hello-server:1.0.0" already present on machine
  Normal  Created         6m51s  kubelet  Created container: hello-server
  Normal  Started         6m51s  kubelet  Started container hello-server

5.2.3 컨테이너의 로그 출력하기: kubectl logs

특정 Pod 의 로그 참조하기

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
~/gitFolders/build-breaking-fixing-kubernetes master*
❯ kubectl logs hello-world --namespace default             

09:39:07.136 [info] Starting server on port 8080

09:41:45.503 [info] GET /

09:41:45.505 [info] Sent 200 in 1ms

~/gitFolders/build-breaking-fixing-kubernetes master*
❯ kubectl logs hello-world --container hello-server --namespace default

09:39:07.136 [info] Starting server on port 8080

09:41:45.503 [info] GET /

09:41:45.505 [info] Sent 200 in 1ms

특정 Deployment 에 연결된 Pod 의 로그 조회하기

1
2
3
4
❯ kubectl logs deploy/hello-server                                     
error: error from server (NotFound): deployments.apps "hello-server" not found in namespace "default"

# 아직 Deployment 리소스를 만들지 않아 위 내용처럼 나옴

레이블을 지정하여 참조할 Pod 한정하기

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
~/gitFolders/build-breaking-fixing-kubernetes master
❯ kubectl get pod --namespace default                  
NAME                     READY   STATUS    RESTARTS   AGE
another-hello-world      1/1     Running   0          144m
hello-world              1/1     Running   0          144m
hello-world-with-label   1/1     Running   0          2m1s

~/gitFolders/build-breaking-fixing-kubernetes master*
❯ kubectl get pod --selector app=hello-world
NAME                     READY   STATUS    RESTARTS   AGE
hello-world              1/1     Running   0          144m
hello-world-with-label   1/1     Running   0          2m20s

~/gitFolders/build-breaking-fixing-kubernetes master*
❯ kubectl logs --selector app=hello-world   

12:01:31.609 [info] Starting server on port 8080

09:39:07.136 [info] Starting server on port 8080

09:41:45.503 [info] GET /

09:41:45.505 [info] Sent 200 in 1ms

5.3 kubectl 명령어로 상세 정보 출력하기

5.3.1 디버그용 사이드카 컨테이너 시작하기: kubectl debug

kubectl debug --stdin --tty <디버그 대상 Pod 이름> --image=<디버그용 컨테이너 이미지> --target=<디버그 대상의 컨테이너 이름> --namespace default -- sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
~
❯ kubectl debug --stdin --tty hello-world --image=curlimages/curl:latest --target=hello-server --namespace default -- sh
Targeting container "hello-server". If you don't see processes from this container it may be because the container runtime doesn't support this feature.
--profile=legacy is deprecated and will be removed in the future. It is recommended to explicitly specify a profile, for example "--profile=general".
Defaulting debug container name to debugger-ssst6.
All commands and output from this session will be recorded in container logs, including credentials and sensitive information passed through the command prompt.
If you don't see a command prompt, try pressing enter.
~ $ curl localhost:8080
Hello, world!~ $ exit
Session ended, the ephemeral container will not be restarted but may be reattached using 'kubectl attach hello-world -c debugger-ssst6 -i -t' if it is still running

5.3.2 컨테이너를 그 자리에서 실행하기 kubectl run

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
❯ kubectl --namespace default run busybox --image=busybox:latest --rm --stdin --tty --restart=Never --command -- nslookup google.com
Server:		10.96.0.10
Address:	10.96.0.10:53

Non-authoritative answer:

Non-authoritative answer:
Name:	google.com
Address: 172.217.31.174

pod "busybox" deleted from default namespace

5.3.3 컨테이너에 로그인하기: kubectl exec

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
~
❯ kubectl --namespace default run curlpod --image=curlimages/curl:latest --command -- /bin/sh -c "while true; do sleep infinity; done;"
pod/curlpod created

~
❯ kubectl get pod --namespace default       
NAME                     READY   STATUS    RESTARTS      AGE
another-hello-world      1/1     Running   1 (30m ago)   3d1h
curlpod                  1/1     Running   0             57s
hello-world              1/1     Running   1 (30m ago)   3d1h
hello-world-with-label   1/1     Running   1 (30m ago)   2d23h

~
❯ kubectl get pod hello-world --output wide --namespace default
NAME          READY   STATUS    RESTARTS      AGE    IP           NODE                 NOMINATED NODE   READINESS GATES
hello-world   1/1     Running   1 (31m ago)   3d1h   10.244.0.6   kind-control-plane   <none>           <none>

~
❯ kubectl --namespace default exec --stdin --tty curlpod -- /bin/sh
~ $ curl 10.244.0.6:8080
Hello, world!~ $ exit

5.3.4 포트 포워딩으로 애플리케이션에 접속하기

1
2
3
4
5
6
# Terminal 1
❯ kubectl port-forward hello-world 5555:8080 --namespace default
Forwarding from 127.0.0.1:5555 -> 8080
Forwarding from [::1]:5555 -> 8080
Handling connection for 5555
^C%                                                                             
1
2
3
4
# Terminal 2
~
❯ curl localhost:5555
Hello, world!%                                                                  
1
2
3
4
5
6
7
8
9
❯ kubectl port-forward hello-world :8080
Forwarding from 127.0.0.1:49852 -> 8080
Forwarding from [::1]:49852 -> 8080
^C%                                                                             
~
❯ kubectl port-forward hello-world :8080
Forwarding from 127.0.0.1:49857 -> 8080
Forwarding from [::1]:49857 -> 8080
^C%                                                                             

5.4 장애를 해결하기 위한 kubectl 명령어

5.4.1 매니페스트를 그 자리에서 편집하기: kubectl edit

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
~
❯ kubectl edit pod hello-world --namespace default
pod/hello-world edited

~ 16s
❯ kubectl get pod hello-world --output yaml --namespace default
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"app":"hello-world"},"name":"hello-world","namespace":"default"},"spec":{"containers":[{"image":"hello-server:1.0.0","imagePullPolicy":"IfNotPresent","name":"hello-server","ports":[{"containerPort":8080}]}]}}
  creationTimestamp: "2025-11-23T09:39:05Z"
  generation: 2
  labels:
    app: hello-world
    env: prod # <----------------------------------------- 추가됨
  name: hello-world
  namespace: default
  resourceVersion: "58196"
  uid: d17de46e-50ab-4f7a-a0d1-788b06ca0d04
spec:
  containers:
  - image: hello-server:1.0.0
    imagePullPolicy: IfNotPresent
    name: hello-server
    ports:
    - containerPort: 8080
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-rxwrx
      readOnly: true
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  ephemeralContainers:
  - command:
    - sh
    image: curlimages/curl:latest
    imagePullPolicy: Always
    name: debugger-ssst6
    resources: {}
    stdin: true
    targetContainerName: hello-server
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    tty: true
  nodeName: kind-control-plane
  preemptionPolicy: PreemptLowerPriority
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - name: kube-api-access-rxwrx
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2025-11-26T10:50:14Z"
    observedGeneration: 2
    status: "True"
    type: PodReadyToStartContainers
  - lastProbeTime: null
    lastTransitionTime: "2025-11-23T09:39:05Z"
    observedGeneration: 2
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: "2025-11-26T10:50:14Z"
    observedGeneration: 2
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: "2025-11-26T10:50:14Z"
    observedGeneration: 2
    status: "True"
    type: ContainersReady
  - lastProbeTime: null
    lastTransitionTime: "2025-11-23T09:39:05Z"
    observedGeneration: 2
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: containerd://d5e58aedb87717a317221863db5dbfb7f04e35cf3d78bb7e6ac48b28d9123b1f
    image: docker.io/library/hello-server:1.0.0
    imageID: sha256:42ee6041506dc12d6f7962576f56d0ea2d027727863afab01b246ccae4930c1b
    lastState:
      terminated:
        containerID: containerd://c2ee8c7fa00b3768bb62b20a037ade4b7e7c36c24936cf92298e5e445219d671
        exitCode: 255
        finishedAt: "2025-11-26T10:49:50Z"
        reason: Unknown
        startedAt: "2025-11-23T09:39:06Z"
    name: hello-server
    ready: true
    resources: {}
    restartCount: 1
    started: true
    state:
      running:
        startedAt: "2025-11-26T10:50:13Z"
    user:
      linux:
        gid: 0
        supplementalGroups:
        - 0
        - 1
        - 2
        - 3
        - 4
        - 6
        - 10
        - 11
        - 20
        - 26
        - 27
        uid: 0
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-rxwrx
      readOnly: true
      recursiveReadOnly: Disabled
  ephemeralContainerStatuses:
  - containerID: containerd://89e6422ddd97565383baffc8a7111c09d0ae71d6ad45077953d39cc3ede9c06f
    image: docker.io/curlimages/curl:latest
    imageID: docker.io/curlimages/curl@sha256:935d9100e9ba842cdb060de42472c7ca90cfe9a7c96e4dacb55e79e560b3ff40
    lastState: {}
    name: debugger-ssst6
    ready: false
    resources: {}
    restartCount: 0
    state:
      terminated:
        containerID: containerd://89e6422ddd97565383baffc8a7111c09d0ae71d6ad45077953d39cc3ede9c06f
        exitCode: 0
        finishedAt: "2025-11-23T12:09:35Z"
        reason: Completed
        startedAt: "2025-11-23T12:09:15Z"
    user:
      linux:
        gid: 101
        supplementalGroups:
        - 101
        uid: 100
  hostIP: 172.20.0.2
  hostIPs:
  - ip: 172.20.0.2
  observedGeneration: 2
  phase: Running
  podIP: 10.244.0.6
  podIPs:
  - ip: 10.244.0.6
  qosClass: BestEffort
  startTime: "2025-11-23T09:39:05Z"

5.4.2 리소스를 삭제하기: kubectl delete

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
~
❯ kubectl get pod --namespace default
NAME                     READY   STATUS    RESTARTS      AGE
another-hello-world      1/1     Running   1 (36m ago)   3d1h
curlpod                  1/1     Running   0             7m13s
hello-world              1/1     Running   1 (36m ago)   3d1h
hello-world-with-label   1/1     Running   1 (36m ago)   2d23h

~
❯ kubectl delete pod hello-world --namespace default
pod "hello-world" deleted from default namespace

~
❯ kubectl get pod --namespace default
NAME                     READY   STATUS    RESTARTS      AGE
another-hello-world      1/1     Running   1 (37m ago)   3d1h
curlpod                  1/1     Running   0             7m26s
hello-world-with-label   1/1     Running   1 (37m ago)   2d23h
1
2
3
4
5
6
7
8
9
~
❯ kubectl delete pod curlpod another-hello-world hello-world-with-label --namespace default
pod "curlpod" deleted from default namespace
pod "another-hello-world" deleted from default namespace
pod "hello-world-with-label" deleted from default namespace

~ 31s
❯ kubectl get pod --namespace default
No resources found in default namespace.

5.5 터미널을 더 편리하게 사용하기 위한 팁

5.5.1 자동 완성 설정하기

5.5.2 kubectl의 별명 설정하기

1
alias k=kubectl

5.5.3 리소스 이름 축약하기

1
kubectl api-resources # SHORTNAMES 참고

5.5.4 kubectl 작업을 도와주는 도구

5.5.5 kubectl 플러그인 사용해 보기

5.6 [고치기] 디버그해 보기

5.6.1 준비: Pod가 실행 중인 것을 확인하기

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
~/gitFolders/build-breaking-fixing-kubernetes master ⇡
❯ k apply --filename chapter-05/hello-world.yaml --namespace default
pod/hello-world created

~/gitFolders/build-breaking-fixing-kubernetes master ⇡
❯ k get pod hello-world --namespace default                       
NAME          READY   STATUS    RESTARTS   AGE
hello-world   1/1     Running   0          3m4s

~/gitFolders/build-breaking-fixing-kubernetes master ⇡
❯ k delete pod hello-world --namespace default 
pod "hello-world" deleted from default namespace

5.6.2 애플리케이션 망가뜨리기

1
2
3
~/gitFolders/build-breaking-fixing-kubernetes master* ⇡
❯ k apply --filename chapter-05/pod-destruction.yaml --namespace default 
pod/hello-world created

5.6.3 애플리케이션 조사하기

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
~/gitFolders/build-breaking-fixing-kubernetes master* ⇡
❯ k get pod hello-world --namespace default                             
NAME          READY   STATUS         RESTARTS   AGE
hello-world   0/1     ErrImagePull   0          32s

~/gitFolders/build-breaking-fixing-kubernetes master* ⇡
❯ k get pod hello-world --namespace default
NAME          READY   STATUS             RESTARTS   AGE
hello-world   0/1     ImagePullBackOff   0          44s

~/gitFolders/build-breaking-fixing-kubernetes master* ⇡
❯ k describe pod hello-world --namespace default 
Name:             hello-world
Namespace:        default
Priority:         0
Service Account:  default
Node:             kind-control-plane/172.20.0.2
Start Time:       Wed, 26 Nov 2025 21:53:30 +0900
Labels:           app=hello-world
Annotations:      <none>
Status:           Pending
IP:               10.244.0.10
IPs:
  IP:  10.244.0.10
Containers:
  hello-server:
    Container ID:   
    Image:          hello-server:1.1.0
    Image ID:       
    Port:           8080/TCP
    Host Port:      0/TCP
    State:          Waiting
      Reason:       ErrImagePull
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-wpdqn (ro)
Conditions:
  Type                        Status
  PodReadyToStartContainers   True 
  Initialized                 True 
  Ready                       False 
  ContainersReady             False 
  PodScheduled                True 
Volumes:
  kube-api-access-wpdqn:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    Optional:                false
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled  60s                default-scheduler  Successfully assigned default/hello-world to kind-control-plane
  Normal   Pulling    16s (x3 over 60s)  kubelet            Pulling image "hello-server:1.1.0"
  Warning  Failed     15s (x3 over 58s)  kubelet            Failed to pull image "hello-server:1.1.0": failed to pull and unpack image "docker.io/library/hello-server:1.1.0": failed to resolve reference "docker.io/library/hello-server:1.1.0": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
  Warning  Failed     15s (x3 over 58s)  kubelet            Error: ErrImagePull
  Normal   BackOff    0s (x3 over 58s)   kubelet            Back-off pulling image "hello-server:1.1.0"
  Warning  Failed     0s (x3 over 58s)   kubelet            Error: ImagePullBackOff

~/gitFolders/build-breaking-fixing-kubernetes master* ⇡
❯ k edit pod hello-world --                     
-- completions --
--allow-missing-template-keys  -- If true, ignore any errors in templates wh
--as                           -- Username to impersonate for the operation.
--as-group                     -- Group to impersonate for the operation, th
--as-uid                       -- UID to impersonate for the operation.
--cache-dir                    -- Default cache directory
--certificate-authority        -- Path to a cert file for the certificate au
--client-certificate           -- Path to a client certificate file for TLS
--client-key                   -- Path to a client key file for TLS
--cluster                      -- The name of the kubeconfig cluster to use
--context                      -- The name of the kubeconfig context to use
--disable-compression          -- If true, opt-out of response compression f
--field-manager                -- Name of the manager used to track field ow
--filename                     -- Filename, directory, or URL to files to us
--help                         -- help for edit
--insecure-skip-tls-verify     -- If true, the server's certificate will not
--kubeconfig                   -- Path to the kubeconfig file to use for CLI
--kuberc                       -- Path to the kuberc file to use for prefere
--kustomize                    -- Process the kustomization directory. This 
--log-flush-frequency          -- Maximum number of seconds between log flus
--match-server-version         -- Require server version to match client ver
--namespace                    -- If present, the namespace scope for this C
--output                       -- Output format. One of: (json, yaml, name, 
--output-patch                 -- Output the patch if the resource is edited
--password                     -- Password for basic authentication to the A
--profile                      -- Name of profile to capture. One of (none|c
--profile-output               -- Name of the file to write the profile to
--recursive                    -- Process the directory used in -f, --filena
--request-timeout              -- The length of time to wait before giving u
--save-config                  -- If true, the configuration of current obje
--server                       -- The address and port of the Kubernetes API
--show-managed-fields          -- If true, keep the managedFields when print
--subresource                  -- If specified, edit will operate on the sub
--template                     -- Template string or path to template file t
--tls-server-name              -- Server name to use for server certificate 
--token                        -- Bearer token for authentication to the API
--user                         -- The name of the kubeconfig user to use
--username                     -- Username for basic authentication to the A
--v                            -- number for the log level verbosity
--validate                     -- Must be one of: strict (or true), warn, ig
--vmodule                      -- comma-separated list of pattern=N settings
--warnings-as-errors           -- Treat warnings received from the server as
--windows-line-endings         -- Defaults to the line ending native to your
~/gitFolders/build-breaking-fixing-kubernetes master* ⇡
❯ k edit pod hello-world --namespace default 
pod/hello-world edited

~/gitFolders/build-breaking-fixing-kubernetes master* ⇡ 16s
❯ k get pod hello-world --namespace default 
NAME          READY   STATUS    RESTARTS   AGE
hello-world   1/1     Running   0          2m1s

~/gitFolders/build-breaking-fixing-kubernetes master* ⇡
❯ k delete --filename chapter-05/pod-destruction.yaml --namespace default 
pod "hello-world" deleted from default namespace

~/gitFolders/build-breaking-fixing-kubernetes master* ⇡
❯ k get pod --namespace default                                          
No resources found in default namespace.

Categories:

Tags: