티스토리 뷰

Cloud/Kubernetes

kubectl debug and koolkit

Jacob_baek 2022. 4. 14. 21:47

배경

기본적으로 container를 가볍고 안전하게 만들기 위해 container에 불필요한 binary를 제거하고 container image를 생성하고 운영한다. 허나 실제 운영하다보면 pod가 통신이 안되거나 디버깅을 해야하는 경우가 발생되면 관련된 command를 쓸수 없어 디버깅에 어려움이 생기는 경우가 다수있다. 기본적으로 사용하는 명령어를 설치를 해서 쓸수도 있지만 대다수 container들은 도구 설치에 대한 권한을 허용하지 않기에 이또한 어려움이 있다.

kubectl debug

앞선 배경상의 문제를 kubectl debug 명령을 사용하여 debugging 가능한 환경을 만들수 있다.

https://kubernetes.io/ko/docs/tasks/debug-application-cluster/debug-running-pod/

근데 막상 사용하려 하니 아래와 같은 이슈가 나왔다.

root@test001:/home/dubaek# kubectl debug -it testpod --image=lightruncom/koolkits:python --image-pull-policy=Never
error: ephemeral containers are disabled for this cluster (error from server: "the server could not find the requested resource").

이 에러가 왜 나왔는지를 보면 어떻게 디버깅이 가능한 환경을 만들어내는지도 알수 있을 것이라 보인다.

EphemeralContainers enable

먼저 kubectl debug를 사용하기 위해서는 EphemeralContainers feature-gate가 enable 되어야 한다.
즉, kubectl debug는 Ephemeral Container로 기존 pod에 별도의 container를 붙이는 개념이라는 뜻이다.

Ephemeral Container는?
기존의 container와는 다르게 ports, liveness, readness, resources 필드가 허용되지 않는다.

/etc/kubernetes/manifests내

  • kube-apiserver.yaml
  • kube-scheduler.yaml
  • kube-controller-manager.yaml

파일들에 다음 라인을 추가한다.

spec:
  containers:
  - command:
    - kube-apiserver
    - --advertise-address=10.10.10.251
    - --allow-privileged=true
    ...
    - --feature-gates=EphemeralContainers=true
...

이후 각 node들에 kubelet systemd service를 재시작한다.

systemctl restart kubelet

사용중인 버전이 1.22이하인 경우는 기본값으로 false 이며 1.23이상인 경우는 별도의 설정없이 사용이 가능하다.

참고링크들

EphemeralContainers enable with Kubespray

How to use kubectl debug

kubectl debug 를 사용하는 방법은 크게 두가지로 볼수 있다.

  1. 복제된 pod를 새롭게 띄우는 방식
  2. 기존 pod에 ephemeral container를 추가하는 방식

1. --copy-to 옵션으로 새로운 pod로 복제

"--copy-to" 옵션을 사용하여 kubectl debug를 실행하게 되면 복제된 pod로 동작되게되며

root@test001:/home/dubaek# kubectl debug -it testpod --image=busybox --share-processes --copy-to=debug-pod
Defaulting debug container name to debugger-8xmwl.
If you don't see a command prompt, try pressing enter.
/ # ps -ef
PID   USER     TIME  COMMAND
    1 root      0:00 /pause
    7 root      0:00 nginx: master process nginx -g daemon off;
   37 101       0:00 nginx: worker process
   38 101       0:00 nginx: worker process
   39 root      0:00 sh
   46 root      0:00 ps -ef
/ # uname
Linux
/ # hostname
debug-pod
/ # exit
Session ended, resume using 'kubectl attach debug-pod -c debugger-8xmwl -i -t' command when the pod is running

다음과 같이 pod가 생긴것을 볼수 있고 종료되지 않은 상태로 남아있음을 볼수 있다.

root@test001:/home/dubaek/testpod# kubectl get po
NAME                                READY   STATUS    RESTARTS      AGE
debug-pod                           2/2     Running   1 (65s ago)   6m11s
nginx-deployment-66b6c48dd5-76v85   1/1     Running   0             176m
nginx-deployment-66b6c48dd5-ll7dj   1/1     Running   0             168m
testpod                             1/1     Running   0             13m

즉, pod가 종료되지는 않기에 필요에 따라 다시 접근하여 확인해볼수 있다.

실제 복제한 pod는 다음과 같이 기존 pod에서 동작되던 container와 지정한 image의 container가 존재한다.

root@test001:/home/kubespray# kubectl get po/debug-pod -o jsonpath='{.spec.containers[*].image}' && echo
nginx busybox

앞서 이야기했듯이 pod가 종료되지 않기에 아래와 같이 pod를 제거해주어야 한다.

root@test001:/home/dubaek/testpod# kubectl delete pod/debug-pod
pod "debug-pod" deleted

완벽하게 동일한 pod는 아니고 동일한 yaml을 기반한 다른 pod가 동작되는 개념이기에 service mesh 구조상에서는 제한점이 생길수도 있다.

2. 기존에 동작되는 pod에 ephemeral container 추가

root@test001:/home/dubaek/testpod# kubectl debug -it pods/testpod --image=busybox
Defaulting debug container name to debugger-8s45p.
If you don't see a command prompt, try pressing enter.
/ # hostname
testpod
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
4: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1480 qdisc noqueue
    link/ether 5e:3a:f1:ae:a8:5d brd ff:ff:ff:ff:ff:ff
    inet 10.233.64.5/32 brd 10.233.64.5 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::5c3a:f1ff:feae:a85d/64 scope link
       valid_lft forever preferred_lft forever
/ # exit
Session ended, resume using 'kubectl attach testpod -c debugger-8s45p -i -t' command when the pod is running

다른 shell에서 해당 pod의 ip를 확인해보면

root@test001:/home/dubaek# kubectl get po/testpod -o jsonpath='{.status.podIP}' && echo
10.233.64.5

와 같다. 즉, 동일한 pod임을 알수 있다.

당시의 pod의 정보를 확인해보면 다음과 같이 ephemeralcontainer 가 spec내 존재한다.

root@test001:/home/dubaek# kubectl get po/testpod -o jsonpath='{.spec.ephemeralContainers}' | jq
[
  {
    "image": "busybox",
    "imagePullPolicy": "Always",
    "name": "debugger-8s45p",
    "resources": {},
    "stdin": true,
    "terminationMessagePath": "/dev/termination-log",
    "terminationMessagePolicy": "File",
    "tty": true
  }
]

앞선 "--copy-to" 옵변을 사용했던것처럼 복제된 pod가 존재하지 않음을 알수 있다.

root@test001:/home/kubespray# kubectl get po
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-66b6c48dd5-76v85   1/1     Running   0          3h
nginx-deployment-66b6c48dd5-ll7dj   1/1     Running   0          172m
testpod                             1/1     Running   0          18m

앞서 언급했듯이 ephemeralcontainer로 동작되기에 다음과 같은 kubectl replace 로도 기존 pod의 ephemeral container를 추가할수도 있다.

root@test001:/home/dubaek# cat es.json
{
    "apiVersion": "v1",
    "kind": "EphemeralContainers",
    "metadata": {
            "name": "testpod"
    },
    "ephemeralContainers": [{
        "command": [
            "sh"
        ],
        "image": "busybox",
        "imagePullPolicy": "IfNotPresent",
        "name": "debugger",
        "stdin": true,
        "tty": true,
        "terminationMessagePolicy": "File"
    }]
}
root@test001:/home/dubaek# kubectl replace --raw /api/v1/namespaces/default/pods/testpod/ephemeralcontainers  -f ec.json

삭제하려보니 아직 정식 기능으로 포함되지 않아서 인지 지원이 안되는상황이었다.
사용되고 있던 k8s version이 1.21이라 버전 문제로 보인다.

하여 테스트 했던 cluster에서는 해당 pod 자체를 terminate 시키거나 deployment가 있다면 rollout 시켜 기존 pod를 terminate 시켜 ephemeral container를 제거해야했다.

참고링크들

Koolkit

다음 Language를 기반으로 한 디버깅용 container image를 만드는 프로젝트이다.
현재(2022.04.14 기준) 제공중인 Language 들은 다음과 같다.

  • nodejs
  • java
  • python
  • golang

Koolkit도 앞선 kubectl debug 를 사용하여 debugging을 수행하도록 한다.

echo "## KoolKits - Shorthand
kk() {
    kubectl debug -it $1 --image=lightruncom/koolkits:$2 --image-pull-policy=Never --target=$3
}" >> ~/.bashrc
source ~/.bashrc

즉, koolkit 자체가 하나의 도구라기보다는 kubectl debug를 할때 language 별로 유용한 도구를 모아놓은 container image를 만드는 프로젝트라 볼수 있다.

참고링크

댓글
댓글쓰기 폼