Skip to content

當遇到 Distroless Container 除錯要什麼沒什麼該怎麼辦? 你的好朋友 kubectl debug

這篇只有 Red Hat OpenShift 為主的使用者不用看,那個早在 v3.6 好幾年前就弄了一個 oc debug 出來了,但你若是一般 Kubernetes 發行版的,例如 Tanzu Kubernetes Grid 或 Azure Kubernetes Service 等,則可以參考一下此篇作法。主要是會用到 Ephemeral Containerskubectl debug 這兩個主要能力,而目前都是在 Kubernetes v1.25 標註 Stable 穩定狀態

典型狀況

有時候你會遇到一個 Container Images 是採 Distroless 的方式運行,特性是除了程式本身以外,什麼 Shell 都沒有,無法登入進去,或者是你進得去看起來有問題的 Pod 想要進行一些除錯的動作,但剛好沒有裝任何工具可以使用,這時候該怎麼辦呢? 其實你需要要準備一個自己編譯好的 debug-container 和學習一下 kubectl debug 的用法

這邊剛好有一個 Azure Kubernetes Service 常見的狀況,就是若想要登入到 CoreDNS Pod 裡面查看 Corefile 的內容,你會發現到它會一直噴 no such file or directory: unknown 之類的錯誤,其實是因為這個 Pod 裡面根本沒有 /bin/bash 或者是 /bin/cat 的指令可以用,可以算是很扎實的 Distroless Container 實務案例

before
repairman@vm-hub:~$ kubectl --namespace kube-system get pods -l k8s-app=kube-dns
NAME                       READY   STATUS    RESTARTS   AGE
coredns-6698ddd997-gx66m   1/1     Running   0          11s
coredns-6698ddd997-rxlsl   1/1     Running   0          11s

repairman@vm-hub:~$ kubectl -n kube-system exec -ti coredns-6698ddd997-gx66m -- /bin/bash
error: Internal error occurred: error executing command in container: failed to exec in container: failed to start exec "0f831ab9a9d243bb196e31d6578b19ea13088cdfeec57fb1953c3021a0463d12": OCI runtime exec failed: exec failed: unable to start container process: exec: "/bin/bash": stat /bin/bash: no such file or directory: unknown

repairman@vm-hub:~$ kubectl -n kube-system exec -ti coredns-6698ddd997-gx66m -- cat /etc/coredns/Corefile
error: Internal error occurred: error executing command in container: failed to exec in container: failed to start exec "7b5e958107188e3b7748a27138774775dbcebcb8c6bd178b357d187bda720bc9": OCI runtime exec failed: exec failed: unable to start container process: exec: "cat": executable file not found in $PATH: unknown

下面提供用 dive 所分析的容器映像檔內容

2 個前置準備

  1. 準備一個具備可用 Shell 跟其他除錯用工具的 Ephemeral Container Image,如我自己編譯的 pichuang/debug-container:master,基於 CentOS Stream,每日更新,簡單直覺
  2. 使用 kubectl debug,確保你的 kubectl 版本是大於 v1.25,目前這個功能是內建在 kubectl 裡面,不需要額外裝 krew plugin 即可使用
$ kubectl version --short
Client Version: v1.27.3
Kustomize Version: v5.0.1
Server Version: v1.26.3

2 個解決方式

  1. 使用 --target: 直接對 Target Container 進行操作,常見如 Pod Running 中沒什麼問題,但剛好它是 distroless images,缺少一堆可執行 bin。這時候若你只是想要做一些基本測試,譬如網路測試等,可以考慮使用 --target 方式把自己準備的 Ephemeral Container 掛進去使用,無須特別修改也無須重開
  2. 使用 --copy-to: Copy 一份 Pod 出去另外研究,最常見的使用方式,反舉遇到 Completed 或 CrashLoopBackOff 等無法使用 kubectl exec 方式進入的 Pod 且想要知道到底死在那裡,可以掛一個 Ephemeral Container 修改進入點或命令研究看看

1. 使用 --target

target
#
# kubectl -n kube-system debug -it <TARGET POD NAME> --image=<DEBUGGER CONTAINER> --target=<TARGET CONTAINER NAME>
#

repairman@vm-hub:~$ kubectl -n kube-system debug -it coredns-6698ddd997-gx66m --image=ghcr.io/pichuang/debug-container:master --target=coredns
Targeting container "coredns". If you dont see processes from this container it may be because the container runtime doesnt support this feature.
Defaulting debug container name to debugger-pbsr4.
If you dont see a command prompt, try pressing enter.
[root@coredns-6698ddd997-gx66m /]# ps uax
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.1  0.2 762456 46012 ?        Ssl  07:24   0:01 /coredns -conf /etc/coredns/Corefile
root          63  0.0  0.0  12060  3284 pts/0    Ss   07:33   0:00 /bin/bash -l
root          88  0.0  0.0  44708  3380 pts/0    R+   07:35   0:00 ps uax

[root@coredns-6698ddd997-gx66m /]# cat /proc/1/root/etc/coredns/Corefile | head -n5
.:53 {
    errors
    ready
    health {
      lameduck 5s

#
# Qeury ephemeralContainerStatuses
#
# kubectl -n kube-system get pod coredns-6698ddd997-gx66m -o jsonpath='{range .status.ephemeralContainerStatuses[*]}{.name}{"\t"}{.ready}{"\n"}{end}'

如果要查 Ephmeral Container 的狀態,要從 .status.ephemeralContainerStatuses 查詢,可以得知使用的 image 是什麼,以及是否 Ready 等資訊

2. 使用 --copy-to

這邊要特別注意的是要把 --share-processes 勾起來,不然預設狀況下 Linux Namespace 是相互隔離的,會看不到原先的 Process

copy-to
#
# kubectl -n kube-system debug -it <TARGET POD NAME> --image=<DEBUGGER CONTAINER> --copy-to=<NEW POD NAME>
#
repairman@vm-hub:~$ kubectl -n kube-system debug -it coredns-6698ddd997-gx66m --share-processes --image=ghcr.io/pichuang/debug-container:master --copy-to=copy-coredns
Defaulting debug container name to debugger-lkp2m.
If you dont see a command prompt, try pressing enter.
[root@copy-coredns /]# ps uax
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
65535          1  0.1  0.0    972     4 ?        Ss   08:27   0:00 /pause
root           7  1.0  0.2 761944 41720 ?        Ssl  08:27   0:00 /coredns -conf /etc/coredns/Corefile
root          21  0.4  0.0  12060  3328 pts/0    Ss   08:27   0:00 /bin/bash -l
root          46  0.0  0.0  47656  3596 pts/0    R+   08:27   0:00 ps uax
[root@copy-coredns /]# cat /proc/7/root/etc/coredns/Corefile | head -n5
.:53 {
    errors
    ready
    health {
      lameduck 5s

#
# Reattach empeheral container
#
repairman@vm-hub:~$ kubectl -n kube-system attach copy-coredns -c debugger-lkp2m -i -t
If you dont see a command prompt, try pressing enter.
[root@copy-coredns /]# cat /proc/7/root/etc/coredns/Corefile | head -n5

#
# Check copy-coredns status
#
repairman@vm-hub:~$ kubectl -n kube-system get pods |grep coredns
copy-coredns                                2/2     Running            0                 2m29s
coredns-6698ddd997-gx66m                    1/1     Running            0                 65m
coredns-6698ddd997-rxlsl                    1/1     Running            0                 65m
coredns-autoscaler-7dbcd7d9c8-pnqtt         1/1     Running            0                 17h

#
# Wipe out copy-coredns
#
repairman@vm-hub:~$ kubectl -n kube-system delete pod copy-coredns
pod "copy-coredns" deleted

[插花] Microsoft Defender for Cloud

就在我對 Azure Kubernetes Service 內的 CoreDNS 上下其手的時候...我被寄了封 Security Alert: CoreDNS modification in Kubernetes detected,真...貼心的提醒

Security Alert: CoreDNS modification in Kubernetes detected
Kubernetes audit log analysis detected a modification of the CoreDNS configuration. The configuration of CoreDNS can be modified by overriding its configmap. While this activity can be legitimate, if attackers have permissions to modify the configmap, they can change the behavior of the cluster's DNS server and poison it.

Refereneces