當遇到 Distroless Container 除錯要什麼沒什麼該怎麼辦? 你的好朋友 kubectl debug
這篇只有 Red Hat OpenShift 為主的使用者不用看,那個早在 v3.6 好幾年前就弄了一個 oc debug
出來了,但你若是一般 Kubernetes 發行版的,例如 Tanzu Kubernetes Grid 或 Azure Kubernetes Service 等,則可以參考一下此篇作法。主要是會用到 Ephemeral Containers 和 kubectl 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 實務案例
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 個前置準備
- 準備一個具備可用 Shell 跟其他除錯用工具的 Ephemeral Container Image,如我自己編譯的 pichuang/debug-container:master,基於 CentOS Stream,每日更新,簡單直覺
- 使用
kubectl debug
,確保你的 kubectl 版本是大於 v1.25,目前這個功能是內建在 kubectl 裡面,不需要額外裝 krew plugin 即可使用
2 個解決方式
- 使用
--target
: 直接對 Target Container 進行操作,常見如 Pod Running 中沒什麼問題,但剛好它是 distroless images,缺少一堆可執行 bin。這時候若你只是想要做一些基本測試,譬如網路測試等,可以考慮使用--target
方式把自己準備的 Ephemeral Container 掛進去使用,無須特別修改也無須重開 - 使用
--copy-to
: Copy 一份 Pod 出去另外研究,最常見的使用方式,反舉遇到 Completed 或 CrashLoopBackOff 等無法使用 kubectl exec 方式進入的 Pod 且想要知道到底死在那裡,可以掛一個 Ephemeral Container 修改進入點或命令研究看看
1. 使用 --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
#
# 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
,真...貼心的提醒
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.