曾幾何時,我們將自己的應用運行在Kubernetes上,每當出現容器異常崩潰時,我們往往都是一邊重啟容器,一邊面對崩潰的容器無從下手。通常在業務研發自己build的鏡像內包含了shell,我們還能通過在command中嵌入一個["sleep", "3600"]
命令來阻塞容器內服務啟動,不過也有時候會出現不知道從哪里冒出來一個distroless
鏡像,這時可能最先崩潰的就是運維了。那是一種運維這個職業自誕生以來,第一次感受到手足無措并脫離掌控的無助感
。于是在k8s環境下無法debug容器的梗開始在坊間廣為吐槽。
第一個打破魔咒的是kubectl-debug,它包含了agent和debug-tools兩個部分。也是目前全網內搜到文檔最全的解決方案。不過目前它的開發似乎已經停止,上一次提交還是在8個月之前,而最近一次Release版本也停留在兩年前。更難以接受的是,當前它無法被集成在容器運行時為Containerd的k8s集群。
盡管kubectl-debug曾經確實是一款非常好用的容器調試工具,但如今Kubernetes已經有了更好的容器調試解決方案,Ephemeral Containers
。
Ephemeral Containers
Ephemeral Containers字如其名,它就是一個臨時容器。這是一個自Kubernetes v1.16中作為alpha引入的新功能,雖然當前它還沒有GA,不過自從在Kubernetes v1.18之后,在kubectl內已經集成了debug客戶端,我們幾乎可以完整的使用并體驗它的新特性。
臨時容器的目標是為Kubernetes用戶提供一個故障診斷工具,同時具備滿足以下需求:
- 作為一個開箱即用的平臺化工具
- 不依賴于已經包含在容器鏡像中的工具
- 不需要直接登陸計算節點(可以通過Kubernetes API的管理訪問Node)
不過也有東西是臨時容器不計劃支持的,比如對windows上啟用臨時容器就不太友好。
啟用臨時容器的特性也非常簡單,在kubernetes v1.16之后的版本中將啟動參數--feature-gates=EphemeralContainers=true
配置到kube-api和kubelet服務上重啟即可。
在1.20之前,kubectl debug工具被放在alpha中,注意不同版本的命令操作差別
這里推薦使用客戶端為1.20+的版本體驗會更好
那么我們有了Ephemeral Containers能做哪些事情呢?
1. POD Troubleshooting
如上文所說,我們可以直接通過kubectl debug命令進行容器調試。最直接簡單的對一個pod進行調試命令如下:
kubectl debug mypod -it --image=busybox
默認情況下用戶不指定臨時容器名稱的話,debug容器名稱就由kubectl自動生成一個唯一id的名稱。如果用戶需要自己指定容器名稱則使用
kubectl debug mypod -c debugger --image=busybox
有了臨時容器除了日常debug功能外,我們可以擴展出很多新花樣的玩法。比如批量跑某個命名空間下的安全掃描的腳本而不用干擾原容器。
for pod in $(kubectl get -o name pod);
do
kubectl debug --image security/pod_scanner -p $pod /sanner.sh
done
2. POD Troubleshooting by Copy
對于沒有開啟Ephemeral Containers特性的集群,我們就只能通過復制模式來調試容器。它的原理是復制一個指定pod的新容器,并將debug作為sidecar跟隨新容器一起啟動。通過這種方式也能達到曲線救國的目的。此種方式的幾個參數還是挺有意思:
--copy-to 指定新pod的名稱
--replace=true 是否刪除原容器
--same-node=true 是否調度到和原容器一樣的node上
--share-processes=true 是否共享容器pid空間
例如我們就可以啟動一個跟需要調試pod一樣配置的debug容器如下:
kubectl debug mypod -it \
--container=debug \
--image=busybox \
--copy-to=my-debugger \
--same-node=true \
--share-processes=true
3. Node Troubleshooting
對!你沒看錯!利用Ephemeral Containers還能對Worker節點進行調試。當以節點為目標調用時,kubectl debug 將創建一個帶有node名稱的pod,并且調度到該節點。同時該容器還具備了hostIPC
、hostNetwork
和hostPID
這些特權模式。不可思議的是Worker節點的根文件系統還被mount到了debug容器下的/host目錄下
。
直接執行這個命令就能debug主機。
kubectl debug node/mynode -it --image=busybox
Debug鏡像
工欲善其事,必先利其器。不管怎樣我們都需要一套工具完善的debug鏡像,在處理問題時能夠得心應手。雖然網上也有不少debug鏡像,不過都還是不如自己構建來的暢快。
這里小白分享一個Debug鏡像的Dockerfile,大家可以根據自己條件修改即可。
FROM golang:alpine as grpcurl
RUN apk update \
&& apk add --virtual build-dependencies git \
&& apk add bash curl jq \
&& go get -u github.com/fullstorydev/grpcurl \
&& go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
FROM alpine:latest
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \
apk update && \
apk add --no-cache vim bash tcpdump curl wget strace mysql-client iproute2 redis jq iftop tzdata tar nmap bind-tools htop && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN wget -O /usr/bin/httpstat https://github.com/davecheney/httpstat/releases/download/v1.0.0/httpstat-linux-amd64-v1.0.0 && \
chmod +x /usr/bin/httpstat
COPY --from=grpcurl /go/bin/grpcurl /usr/bin/grpcurl
ENV TZ=Asia/Shanghai LC_ALL=C.UTF-8 LANG=C.UTF-8 LANGUAGE=C.UTF-8
ENTRYPOINT [ "/bin/bash" ]
debug鏡像內支持的工具包如下圖
總結
本文主要講述了kubernetes在v1.18版本之后被提上alpha的Ephemeral Containers
特性,通過臨時容器我們可以debug容器,甚至還可以debug主機。它確實是一個非常方便和足以替代kubectl-debug的解決方案。不過,目前臨時容器對于用戶權限這塊并沒有特別的說明,特別是用特權模式調試主機的時候,希望后面能夠借助PSP(Pod Security Policy)做一個額外的補充。