日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Kubernetes 上调试 distroless 容器

發布時間:2024/8/23 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Kubernetes 上调试 distroless 容器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者 | Addo Zhang

來源 | 云原生指北

Distroless 鏡像

Distroless 容器,顧名思義使用?Distroless 鏡像[1]作為基礎鏡像運行的容器。

"Distroless" 鏡像只包含了你的應用程序以及其運行時所需要的依賴。不包含你能在標準 Linxu 發行版里的可以找到的包管理器、shells 或者其他程序。

GoogleContainerTools/distroless[2]?針對不同語言提供了 distroless 鏡像:

?gcr.io/distroless/static-debian11[3]?gcr.io/distroless/base-debian11[4]?gcr.io/distroless/java-debian11[5]?gcr.io/distroless/cc-debian11[6]?gcr.io/distroless/nodejs-debian11[7]?gcr.io/distroless/python3-debian11[8]

Distroless 鏡像有什么用?

那些可能是構建鏡像時需要的,但大部分并不是運行時需要的。這也是為什么上篇文章介紹 Buildpacks

其實控制體積并不是 distroless 鏡像的主要作用。將運行時容器中的內容限制為應用程序所需的依賴,此外不應該安裝任何東西。這種方式可能極大的提升容器的安全性,也是 distroless 鏡像的最重要作用。

這里并不會再深入探究 distroless 鏡像,而是如何調試 distroless 容器

沒有了包管理器,鏡像構建完成后就不能再使用類似?apt、yum?的包管理工具;沒有了?shell,容器運行后無法再進入容器。

“就像一個沒有任何門的房間,也無法安裝門。”?Distroless 鏡像在提升容器安全性的同時,也為調試增加了難度。

使用 distroless 鏡像

寫個很簡單的 golang 應用:

package main import ("fmt""net/http" ) func defaultHandler(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello world!") } func main() {http.HandleFunc("/", defaultHandler)http.ListenAndServe(":8080", nil) }

比如使用?gcr.io/distroless/base-debian11?作為 golang 應用的基礎鏡像:

FROM golang:1.12 as build-env WORKDIR /go/src/app COPY . /go/src/app RUN go get -d -v ./... RUN go build -o /go/bin/app FROM gcr.io/distroless/base-debian11 COPY --from=build-env /go/bin/app / CMD ["/app"]

使用鏡像創建 deployment

$ kubectl create deploy golang-distroless --image addozhang/golang-distroless-example:latest $ kubectl get po NAME READY STATUS RESTARTS AGE golang-distroless-784bb4875-srmmr 1/1 Running 0 3m2s

嘗試進入容器:

$ kubectl exec -it golang-distroless-784bb4875-srmmr -- sh error: Internal error occurred: error executing command in container: failed to exec in container: failed to start exec "b76e800eafa85d39f909f39fcee4a4ba9fc2f37d5f674aa6620690b8e2939203": OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: "sh": executable file not found in $PATH: unknown

如何調試 Distroless 容器

1. 使用 distroless debug 鏡像

GoogleContainerTools 為每個 distroless 鏡像都提供了?debug?tag,適合在開發階段進行調試。如何使用?替換容器的 base 鏡像:

FROM golang:1.12 as build-env WORKDIR /go/src/app COPY . /go/src/app RUN go get -d -v ./... RUN go build -o /go/bin/app FROM gcr.io/distroless/base-debian11:debug # use debug tag here COPY --from=build-env /go/bin/app / CMD ["/app"]

重新構建鏡像并部署,得益于debug鏡像中提供了 busybox shell 讓我們可以 exec 到容器中。

2. debug 容器與共享進程命名空間

同一個 pod 中可以運行多個容器,通過設置?pod.spec.shareProcessNamespace?為?true,來讓同一個 Pod 中的多容器共享同一個進程命名空間[9]

Share a single process namespace between all of the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false.

添加一個使用?ubuntu?鏡像的?debug?容器,這里為了測試(后面解釋)我們為原容器添加?securityContext.runAsUser: 1000,模擬兩個容器使用不同的 UID 運行:

apiVersion: apps/v1 kind: Deployment metadata:creationTimestamp: nulllabels:app: golang-distrolessname: golang-distroless spec:replicas: 1selector:matchLabels:app: golang-distrolessstrategy: {}template:metadata:creationTimestamp: nulllabels:app: golang-distrolessspec:shareProcessNamespace: truecontainers:- image: addozhang/golang-distroless-example:latestname: golang-distroless-examplesecurityContext:runAsUser: 1000resources: {}- image: ubuntuname: debugargs: ['sleep', '1d']securityContext:capabilities:add:- SYS_PTRACEresources: {} status: {}

更新 deployment 之后:

$ kubectl get po NAME READY STATUS RESTARTS AGE golang-distroless-85c4896c45-rkjwn 2/2 Running 0 3m12s $ kubectl get po -o json | jq -r '.items[].spec.containers[].name' golang-distroless-example debug

然后通過 debug 容器來進入到 pod 中:

$ kubectl exec -it golang-distroless-85c4896c45-rkjwn -c debug -- sh

然后在容器中執行:

$ ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 14:54 ? 00:00:00 /pause # infra 容器 1000 7 0 0 14:54 ? 00:00:00 /app # 原容器,UID 為 1000 root 19 0 0 14:55 ? 00:00:00 sleep 1d # debug 容器 root 25 0 0 14:55 pts/0 00:00:00 sh root 32 25 0 14:55 pts/0 00:00:00 ps -ef

嘗試訪問 進程?7?的進程空間:

$ cat /proc/7/environ $ cat: /proc/7/environ: Permission denied

我們需要為?debug?容器加上:

securityContext:capabilities:add:- SYS_PTRACE

之后再訪問就正常了:

$ cat /proc/7/environ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=golang-distroless-58b6c5f455-v9zkvSSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crtKUBERNETES_PORT_443_TCP=tcp://10.43.0.1:443KUBERNETES_PORT_443_TCP_PROTO=tcpKUBERNETES_PORT_443_TCP_PORT=443KUBERNETES_PORT_443_TCP_ADDR=10.43.0.1KUBERNETES_SERVICE_HOST=10.43.0.1KUBERNETES_SERVICE_PORT=443KUBERNETES_SERVICE_PORT_HTTPS=443KUBERNETES_PORT=tcp://10.43.0.1:443HOME=/root

同樣我們也可以訪問進程的文件系統:

$ cd /proc/7/root $ ls app bin boot dev etc home lib lib64 proc root run sbin sys tmp usr var

無需修改容器的基礎鏡像,使用?pod.spec.shareProcessNamespace: true?配合安全配置中增加?SYS_PTRACE?特性,為 debug 容器賦予完整的 shell 訪問來調試應用。但是修改 YAML 和安全配置只適合在測試環境使用,到了生產環境這些都是不允許的。

我們就需要用到?kubectl debug?了。

3. Kubectl debug

針對不同的資源?kubectl debug?可以進行不同操作:

?負載:創建一個正在運行的 Pod 的拷貝,并可以修改部分屬性。比如在拷貝中使用新版本的tag。?負載:為運行中的 Pod 增加一個臨時容器(下面介紹),使用臨時容器中的工具調試,無需重啟 Pod。?節點:在節點上創建一個 Pod 運行在節點的 host 命名空間,可以訪問節點的文件系統。

3.1 臨時容器

從 Kubernetes 1.18 之后開始,可以使用?kubectl?為運行的 pod 添加一個臨時容器。這個命令還處于?alpha?階段,因此需要在“feature gate”[10]中打開。

在使用 k3d 創建 k3s 集群時,打開?EphemeralContainers?feature:

$ k3d cluster create test --k3s-arg "--kube-apiserver-arg=feature-gates=EphemeralContainers=true"@

然后創建臨時容器,創建完成后會直接進入容器:

$ kubectl debug golang-distroless-85c4896c45-rkjwn -it --image=ubuntu --image-pull-policy=IfNotPresent #臨時容器 shell $ apt update && apt install -y curl $ curl localhost:8080 Hello world!臨時容器

值得注意的是,臨時容器無法與原容器共享進程命名空間:

$ ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 02:59 pts/0 00:00:00 bash root 3042 1 0 03:02 pts/0 00:00:00 ps -ef

可以通過添加參數?--target=[container]?來將臨時容器掛接到目標容器。這里與?pod.spec.shareProcessNamespace?并不同,進程號為 1 的進程是目標容器的進程,而后者的進程是 infra 容器的進程?/pause:

$ kubectl debug golang-distroless-85c4896c45-rkjwn -it --image=ubuntu --image-pull-policy=IfNotPresent --target=golang-distroless-example

注意:目前的版本還不支持刪除臨時容器,參考?issue[11],支持的版本:

3.2 拷貝 Pod 并添加容器

除了添加臨時容器以外,另一種方式就是創建一個 Pod 的拷貝,并添加一個容器。注意這里的是普通容器,不是臨時容器。?注意這里加上了?--share-processes

$ kubectl debug golang-distroless-85c4896c45-rkjwn -it --image=ubuntu --image-pull-policy=IfNotPresent --share-processes --copy-to=golang-distroless-debug

注意這里加上了?--share-processes,會自動加上?pod.spec.shareProcessNamespace=true:

$ kubectl get po golang-distroless-debug -o jsonpath='{.spec.shareProcessNamespace}' true

注意:使用?kubectl debug?調試,并不能為 pod 自動加上?SYS_PTRACE?安全特性,這就意味著如果容器使用的 UID 不一致,就無法訪問進程空間。?截止發文,計劃在?1.23?中支持[12]

總結

目前上面所有的都不適合在生產環境使用,無法在不修改 Pod 定義的情況下進行調試。

期望 Kubernetes 1.23 版本之后?debug?功能添加?SYS_PTRACE?的支持。到時候,再嘗試一下。

引用鏈接

[1]?Distroless 鏡像:?https://github.com/GoogleContainerTools/distroless
[2]?GoogleContainerTools/distroless:?https://github.com/GoogleContainerTools/distroless
[3]?gcr.io/distroless/static-debian11:?https://github.com/GoogleContainerTools/distroless/blob/main/base/README.md
[4]?gcr.io/distroless/base-debian11:?https://github.com/GoogleContainerTools/distroless/blob/main/base/README.md
[5]?gcr.io/distroless/java-debian11:?https://github.com/GoogleContainerTools/distroless/blob/main/java/README.md
[6]?gcr.io/distroless/cc-debian11:?https://github.com/GoogleContainerTools/distroless/blob/main/cc/README.md
[7]?gcr.io/distroless/nodejs-debian11:?https://github.com/GoogleContainerTools/distroless/blob/main/nodejs/README.md
[8]?gcr.io/distroless/python3-debian11:?https://github.com/GoogleContainerTools/distroless/blob/main/experimental/python3/README.md
[9]?多容器共享同一個進程命名空間:?https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/
[10]?“feature gate”:?k3d%20cluster%20create%20test%20--k3s-arg%20%22--kube-apiserver-arg=feature-gates=EphemeralContainers=true%22@
[11]?issue:?https://github.com/kubernetes/kubernetes/issues/84764#issuecomment-872839644
[12]?計劃在?1.23?中支持:?https://github.com/kubernetes/kubernetes/issues/97103#issuecomment-899382147

往期推薦

什么是RedCup?一文詳解!

谷歌自研Tensor芯片,8核CPU,20核GPU

清華大學:2021元宇宙研究報告

Mendix 發布全球低代碼報告

點分享

點收藏

點點贊

點在看

總結

以上是生活随笔為你收集整理的Kubernetes 上调试 distroless 容器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。