Kubernetes 이야기

Kubernetes Ephemeral Containers를 사용하여 debug 하기 본문

Kubernetes/일반

Kubernetes Ephemeral Containers를 사용하여 debug 하기

kmaster 2022. 5. 11. 14:19
반응형

Kubernetes에서 많은 Pod들을 운영하다 보면, Pod안에 있는 Container들의 오류를 확인해야 하는 경우가 있다. 이 때 다양한 도구 ( 예: telnet, curl, tcpdump, wget 등.. ) 가 필요한데 대부분의 Container image들이 Shell도 없는 기본 배포판을 기반으로 제작된 것들이 많다. 그래서, 오류가 많이 발생하는 Container에 필요한 디버깅 도구들을 추가하여 다시 이미지를 빌드하는 경우가 발생한다. 이러한 경우 임시 컨테이너 ( Ephemeral Containers ) 를 사용한다.

 

Kubernetes의 임시 컨테이너 (Ephemeral Containers)는 문제 해결과 같은 일부 작업을 수행하기 위해 기존 포드에서 일시적으로 실행되는 특수한 유형의 컨테이너이다.

 

배포된 포드에는 컨테이너를 추가할 수 없다. 사양을 업데이트해야 하며 이 때 리소스가 다시 생성된다. 그러나 임시 컨테이너를 기존 포드에 추가하여 라이브 문제를 해결할 수 있다.

 

임시 컨테이너는 애플리케이션을 빌드하는 경우보다는 서비스 점검과 같은 경우에 더 적합하다. 임시 컨테이너는 리소스 또는 실행에 대한 보증이 없다는 점에서 다른 컨테이너와 다르며, 결코 자동으로 재시작되지 않는다. 그래서 애플리케이션을 만드는데 적합하지 않다. 임시 컨테이너는 일반 컨테이너와 동일한 ContainerSpec 을 사용해서 명시하지만, 많은 필드가 호환되지 않으며 임시 컨테이너에는 허용되지 않는다.

 

Ephemeral Container 기능은 1.22에 새롭게 포함된 alpha 기능이고 Kubernetes 1.23에서 beta 기능이다.
Kubernetes 1.22에서는 별도로 기능 게이트를 활성화 해야 하지만, 1.23 에서는 기본적으로 이 기능이 함께 제공된다.

 

임시 컨테이너는 일반 컨테이너 설정과 유사하지만, 아래와 같은 설정이 다르다.

 

  • 임시 컨테이너는 포트를 가지지 않을 수 있으므로, ports, livenessProbe, readinessProbe 와 같은 필드는 허용되지 않는다.
  • 파드에 할당된 리소스는 변경할 수 없으므로, resources 설정이 허용되지 않는다.

 

테스트

[ shell 이 없는 container 로 접근 ]

 

container 안에 sh이나 bash 등 shell이 없는 container들이 있다. ( 예를 들어 coredns 등 ) 이러한 container의 디버깅을 위한 방법이다.

 

아래와 같이 shell이 없는 pause container를 기동해 보자.

kubectl run ephemeral-demo --image=k8s.gcr.io/pause:3.1 --restart=Never

 

실행 상태를 보고, shell에 접근해 보자.

# kubectl get po
NAME             READY   STATUS    RESTARTS   AGE
ephemeral-demo   1/1     Running   0          41s

# kubectl exec -it ephemeral-demo -- sh
error: Internal error occurred: error executing command in container: failed to exec in container: failed to start exec "50481df68397c09b36511d420bdd378e562800dc6d137456a58c6d3ac9e54303": OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH: unknown

 

이 Pod에 임시 컨테이너를 자동으로 삽입해보자.

# kubectl debug -it ephemeral-demo --image=busybox:1.28 --target=ephemeral-demo
Targeting container "ephemeral-demo". If you don't see processes from this container it may be because the container runtime doesn't support this feature.
Defaulting debug container name to debugger-v4mtz.
If you don't see a command prompt, try pressing enter.
/ #

 

sh 로 접근이 되고, 상세정보를 보면 아래와 같다.

# kubectl describe pod ephemeral-demo
...
Ephemeral Containers:
  debugger-v4mtz:
    Container ID:   containerd://89d6810beea4ed621071705684408a5baa48147633072955046c33f6a94b5797
    Image:          busybox:1.28
    Image ID:       docker.io/library/busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 11 May 2022 13:17:49 +0900
    Ready:          False
    Restart Count:  0
    Environment:    <none>
...

 

이제 busybox안에 있는 ping이나 telnet, wget, nc 등의 유틸리티를 사용하여 디버깅을 할 수 있다.

 

shell에서 빠져 나오면 임시 컨테이너는 자동으로 종료된다.

/ # exit

# kubectl describe pod ephemeral-demo
Ephemeral Containers:
  debugger-v4mtz:
    Container ID:   containerd://89d6810beea4ed621071705684408a5baa48147633072955046c33f6a94b5797
    Image:          busybox:1.28
    Image ID:       docker.io/library/busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
    Port:           <none>
    Host Port:      <none>
    State:          Terminated
      Reason:       Error
      Exit Code:    1
      Started:      Wed, 11 May 2022 13:17:49 +0900
      Finished:     Wed, 11 May 2022 13:28:59 +0900
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:         <none>

 

[ Pod 사본을 사용하여 디버깅 ]

 

실행 중인 Container에 접속하여 디버깅을 할때 해당 Container에 디버깅에 필요한 도구가 없을 수 있다. 위의 예에서와 같이 임시 컨테이너로 디버깅을 할 수 있으나, 프로세스 네임스페이스 공유가 안되기 때문에 이러한 디버깅을 위해서는 기존 포드에 적용할 수 없고 대상 포드의 복사본을 생성해야 한다.

 

아래와 같이 nginx container를 포함하는 pod를 생성해 보자.

# kubectl run myapp --image=nginx --restart=Never

 

실행된 nginx에서 ps aux 명령어를 입력하면 ps 명령어가 없다고 나타난다.

# kubectl exec -it  myapp -- bash
root@myapp:/# ps aux
bash: ps: command not found

 

디버깅을 위해 busybox 이미지를 임시 컨테이너로 추가하여 Pod를 복사해 보자.

# kubectl debug myapp -it --image=busybox --share-processes --copy-to=myapp-debug
Defaulting debug container name to debugger-gj6ns.

If you don't see a command prompt, try pressing enter.
root@myapp-debug:/#

 

명령 수행 후 상태를 보자.

# kubectl get po
NAME          READY   STATUS    RESTARTS   AGE
myapp         1/1     Running   0          108s
myapp-debug   2/2     Running   0          67s

 

ps aux 명령어로 프로세스들을 조회하면 busybox에서 수행중인 sleep 1d 가 보인다.

/ # ps aux
PID   USER     TIME  COMMAND
    1 65535     0:00 /pause
    7 root      0:00 nginx: master process nginx -g daemon off;
   43 101       0:00 nginx: worker process
   44 101       0:00 nginx: worker process
   45 101       0:00 nginx: worker process
   46 101       0:00 nginx: worker process
   47 101       0:00 nginx: worker process
   48 101       0:00 nginx: worker process
   49 101       0:00 nginx: worker process
   50 101       0:00 nginx: worker process
   51 root      0:00 sh
   63 root      0:00 ps aux

 

결과를 보면 busybox의 /pause를 볼 수 있고, nginx process도 조회할 수 있다.

 

 

[ 노드의 셸을 통한 디버깅 ]

 

kubectl debug 명령을 사용하여 K8s 노드를 디버그할 수도 있다. 

 

# kubectl debug node/<NODENAME> -it --image=ubuntu
Creating debugging pod node-debugger-node1-lgmxg with container debugger on node node1.
If you don't see a command prompt, try pressing enter.
root@node1:/#

 

노드 디버깅 세션을 생성할 때에는 다음 사항에 유의해야 한다.

Node의 이름을 기반으로 새 Pod의 이름을 자동으로 생성된다.
컨테이너는 호스트 IPC, 네트워크 및 PID 네임스페이스에서 실행된다.
노드의 루트 파일 시스템이 /host에 마운트된다.

 

완료되면 디버깅 Pod를 정리하는 것을 잊지 마십시오.

# kubectl delete pod node-debugger-node1-lgmxg

 

참고

https://kubernetes.io/ko/docs/concepts/workloads/pods/ephemeral-containers/

https://kubernetes.io/docs/tasks/debug/debug-application/debug-running-pod/#ephemeral-container

 

반응형
Comments