容器故障?別慌:debug 不行,還有superdebug
本文轉載自微信公眾號「云原生百寶箱」
這篇內容主要探討了 Kubernetes 的調試功能,介紹了 kubectl debug 和 kubectl superdebug。它們支持容器掛載并且能夠調試一些需要排查問題的 Pod。文章指出了在 Kubernetes 中使用 kubectl exec 命令的限制,并介紹了 kubectl debug 的作用,它能創建一個新的容器來調試運行中的容器,并且能夠在同一個 Pod 內共享系統資源。此外,還提到了 ephemeral containers,它們在調試過程中可以臨時運行在現有的 Pod 中,支持一些排查操作。最后,文章還提及了一些非 Kubernetes 本地調試容器的方法,包括使用 Docker Engine 或者一些基于 Linux namespaces 的工具。
使用 kubectl exec 執行命令
如果你在 Kubernetes 上運行軟件,你有時會想要調試所部署的應用。對于習慣使用虛擬機的人來說,一種簡單的調試方法是連接到正在運行的 Pod 并進行分享:
kubectl exec -it podname -c containername -- bash
這通常有效并且非常有用。然而,至少有兩個 Kubernetes“最佳實踐”限制了 exec 在現實世界中的用處:
? 不以 root 身份運行。容器以盡可能少的權限運行,甚至可以使用隨機 UID 運行。
? 最小鏡像。鏡像盡可能小,極端情況下將二進制文件安裝到distroless 鏡像中。[1]
當應用這些最佳實踐時,使用kubectl exec連接到容器要么是不可能的,要么會讓你陷入不適合調試的貧瘠荒地般的環境。
調試容器
調試正在運行的容器的 Kubernetes 原生答案是使用kubectl debug。
debug 命令將一個新容器附加到正在運行的 pod 中。這個新容器可以以不同的用戶身份從你選擇的任何鏡像運行。由于調試容器與其目標容器在同一 Pod 中運行(因此在同一節點上),因此兩個容器之間的隔離不需要是絕對的。調試容器可以與同一 Pod 中運行的其他容器共享系統資源。
考慮要檢查pod容器postpod中運行的 PostgreSQL 數據庫的 CPU 使用情況。Pod 不以 root 身份運行,并且 Postgres 鏡像沒有類似top或htop安裝的工具——換句話說,該kubectl exec命令沒什么用處。你可以運行以下命令:
kubectl debug -it \
--container=debug-container \
--image=alpine \
--target=postcont \
postpod
你將以 root 身份登錄(這是 Alpine 鏡像的默認設置),并且可以輕松安裝你最喜歡的交互式進程查看器 htop ( apt add htop)。你與容器postcont共享相同的進程命名空間,并且可以查看甚至殺死在那里運行的所有進程!當你退出該進程時,臨時容器也將停止存在。
注意:你可以通過按 CTRL+P 或 CTRL+D 斷開與臨時容器/bash 會話的連接,而無需退出(終止)它。然后你可以稍后使用 重新連接到它kubectl attach。
注意:kubectl debug提供的功能比此處概述的更多,例如使用修改后的啟動命令復制 Pod 或啟動可訪問節點文件系統的“節點”Pod。
臨時容器
上面的命令kubectl debug通過創建一個稱為臨時容器[2]東西來工作。這些容器應該在現有Pod 中臨時運行,以支持故障排除等操作。
“普通”容器和臨時容器之間的區別很小。沒有什么能真正阻止臨時容器長期運行。我認為,通過查看 Kubernetes 在誕生之初所做的基礎架構選擇,可以最好地理解擁有臨時容器的原因:
? Pod 應該是一次性且可更換的,并且支持這一點,
? Pod 規范是不可變的。
當 Kubernetes 主要用于部署無狀態工作負載時(當 Pod 本身可以被認為是短暫的)時,這非常有意義。在這個 Kubernetes無所不能的新世界中,它可能會受到限制。Pod 規范保持不變,但 Kubernetes 將臨時容器建模為Pod 的子資源。與“普通”容器不同,臨時容器不是 Pod規范的一部分,即使它們是 pod 的一部分。這種微妙的區別讓每個人都高興??!
臨時容器仍然相對較新;
它們自 Kubernetes v1.25(2022 年 8 月)處于Stable狀態,自 v1.23(2021 年 12 月)是Beta狀態,自 v1.22(2021 年 8 月)是Alpha狀態。
掛載卷
內置命令kubectl debug非常有用。它允許你將臨時容器添加到正在運行的 Pod,可以選擇與正在運行的容器共享其進程命名空間。但是,如果你希望用于kubectl debug檢查或修改正在運行的容器的文件系統的任何部分,那么你就不走運了 - 調試 Pod 的文件系統與你連接到的容器的文件系統是脫節的。
幸運的是,我們可以做得更好。這個想法很簡單:
? 檢索正在運行的目標容器的規格。
? 將臨時容器修補到 Pod 中。將其配置為與目標容器共享相同的進程命名空間,并另外包含相同的卷掛載。
沒有用于創建臨時容器的 kubectl 命令,因此我們需要向 K8s API 發送 PATCH 請求來創建它。該kubectl proxy命令允許訪問 K8s API。
這個過程并不完全是用戶友好的,因此將過程包裝到腳本或 kubectl 插件中是有意義的。你可以在此處找到此類腳本的示例實現:
https://github.com/JonMerlevede/kubectl-superdebug
kubectl debug 的擴展將目標容器的卷規格附加到臨時調試 pod 中……
kubectl superdebug
請注意,此方法和腳本可以輕松擴展以從目標容器復制環境變量規范。
如果將此腳本另存為kubectl-superdebug并使其在你的路徑上可用,則可以kubectl superdebug從任何地方運行它,如下所示:
kubectl superdebug \
--container=debug-container \
--image=alpine \
--target=postcont \
postpod
你可能還想擴展此腳本以將目標容器的其他方面復制到調試容器中,例如對環境變量的引用。
這完成了調試運行容器的 Kubernetes 原生方法的概述,應該可以滿足大多數人的需求。
非 Kubernetes 原生方法
Kubernetes 不提供以 root 身份連接到正在運行的容器(除非主進程以 root 身份運行)或從另一個容器訪問容器的根文件系統的方法。這并不意味著這些事情不可能做到。畢竟,Kubernetes 只是一個位于容器化引擎之上的容器編排器。如果由于某種原因確實有必要的話,通??梢酝ㄟ^刪除抽象層來做任何你想做的事情。只要確保你必須...
如果你使用 Docker 引擎并且可以直接從節點或通過節點上運行的特權容器訪問你的引擎,那么你可以docker exec --user作為你選擇的用戶運行和執行進程。
諸如kubectl ssh和 之類的插件kubectl exec-user實現了這種方法。不幸的是, containerd[3]和CRI-O[4]等現代引擎不再提供--user標志功能——這意味著這些插件無法在現代 Kubernetes 安裝上運行。
然而,即使是這些現代引擎通常也只是與 Linux 命名空間交互。你可以通過輸入適當的 Linux 命名空間集在任何你想要的“容器”中運行命令。kpexec[5]工具實現了這種方法。它在與目標容器相同的節點上啟動一個特權 Pod,然后確定要定位的 (Linux) 命名空間,在這些 (Linux) 命名空間中執行命令,最后將其輸出流式傳輸到你的終端。作為一個額外的好處,它可以在目標容器的文件系統之上覆蓋一組可用于調試的工具。
與 kubectl exec 不同,kpexec 可以運行具有不同 uid/gid 甚至不同功能的命令作為容器的主進程。它與containerd和cri-o兼容。kpexec 采用某種重量級且脆弱的方法,可能與你的集群的安全配置不兼容。如果 kubectl (super)debug 無法滿足你的需求,則值得考慮。
請注意,kpexec 使用nsenter命令直接執行到命名空間中。它與無處不在的容器運行時 runc 兼容,但與Kata Containers[6]等運行時不兼容。
在這篇文章中,我們研究了兩種調試運行容器的 Kubernetes 原生方法:kubectl exec和kubectl debug。我們研究了kubectl debug工作原理,并提出了kubectl superdebug一種變體,kubectl debug它啟動一個與目標容器共享相同卷和相同進程命名空間的臨時容器。最后,我們回顧了一些非 Kubernetes 原生的容器調試方法。
引用鏈接
[1] distroless 鏡像中。: https://github.com/GoogleContainerTools/distroless
[2] 臨時容器: https://kubernetes.io/docs/concepts/workloads/pods/ephemeral-containers/
[3] containerd: https://containerd.io/
[4] CRI-O: https://cri-o.io/
[5] kpexec: https://github.com/ssup2/kpexec[6] Kata Containers: https://katacontainers.io/