Istio 中的 Kubernetes 原生 Sidecar
使用 Istio 演示新的 SidecarContainers 功能。
如果你聽過任何關於服務網格的事情,那就是它們使用 sidecar 模式運作:一個代理伺服器與你的應用程式碼一同部署。sidecar 模式只是一種模式。在此之前,Kubernetes 完全沒有正式支援 sidecar 容器。
這導致了一些問題:如果你的工作(Job)按照設計會終止,但 sidecar 容器不會呢?這個確切的用例是 Kubernetes 問題追蹤器上最受歡迎的問題。
在 2019 年提出了在 Kubernetes 中加入 sidecar 支援的正式提案。經過多次停頓和重新啟動,在去年重新啟動該專案後,對 sidecar 的正式支援將在 Kubernetes 1.28 中以 Alpha 版本發布。Istio 已經實作了對此功能的支援,你可以在這篇文章中了解如何利用它。
Sidecar 的困境
Sidecar 容器提供了很多功能,但也帶來了一些問題。雖然 Pod 中的容器可以共享一些東西,但它們的生命週期是完全解耦的。對 Kubernetes 來說,這兩個容器在功能上是相同的。
然而,在 Istio 中,它們並不相同 - Istio 容器是主要應用程式容器運作所必需的,如果沒有主要應用程式容器,它就沒有價值。
這種期望上的不匹配導致了各種問題
- 如果應用程式容器啟動速度快於 Istio 的容器,它將無法訪問網路。這在 Istio 的 GitHub 上贏得了 最多的 +1,遙遙領先。
- 如果 Istio 的容器在應用程式容器之前關閉,應用程式容器將無法訪問網路。
- 如果應用程式容器有意退出(通常用於
Job
),Istio 的容器仍會執行並使 Pod 無限期地執行。這也是一個 熱門的 GitHub 問題。 - 在 Istio 的容器啟動之前執行的
InitContainers
無法訪問網路。
Istio 社群及其他社群花了無數時間來解決這些問題,但效果有限。
解決根本原因
雖然 Istio 中越來越複雜的解決方案可以幫助 Istio 用戶減輕痛苦,但理想情況下,這一切應該都可以正常運作 - 而且不僅適用於 Istio。幸運的是,Kubernetes 社群一直在努力直接在 Kubernetes 中解決這些問題。
在 Kubernetes 1.28 中,新增了原生 sidecar 支援的新功能,結束了五年多的持續工作。有了這個功能,我們所有的問題都可以在沒有變通方法的情況下解決!
當我們在「GitHub 問題名人堂」時,這兩個 問題 分別佔據了 Kubernetes 歷史上問題的第 1 名和第 6 名,並且終於被關閉了!
特別感謝參與完成這項工作的龐大團隊。
試用一下
雖然 Kubernetes 1.28 剛發布,但新的 SidecarContainers
功能是 Alpha 版(因此,預設為關閉),並且 Istio 中對該功能的支援尚未發布,我們今天仍然可以試用它 - 只是不要在生產環境中嘗試!
首先,我們需要啟動一個 Kubernetes 1.28 叢集,並啟用 SidecarContainers
功能
$ cat <<EOF | kind create cluster --name sidecars --image gcr.io/istio-testing/kind-node:v1.28.0 --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
SidecarContainers: true
EOF
然後我們可以下載最新的 Istio 1.19 預發布版本(因為 1.19 尚未發布)。我這裡使用的是 Linux。這是 Istio 的預發布版本,所以再次強調 - 不要在生產環境中嘗試!當我們安裝 Istio 時,我們將啟用原生 sidecar 支援的功能標誌,並開啟存取日誌,以便稍後演示。
$ TAG=1.19.0-beta.0
$ curl -L https://github.com/istio/istio/releases/download/$TAG/istio-$TAG-linux-amd64.tar.gz | tar xz
$ ./istioctl install --set values.pilot.env.ENABLE_NATIVE_SIDECARS=true -y --set meshConfig.accessLogFile=/dev/stdout
最後,我們可以部署一個工作負載
$ kubectl label namespace default istio-injection=enabled
$ kubectl apply -f samples/sleep/sleep.yaml
讓我們看看 Pod
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
sleep-7656cf8794-8fhdk 2/2 Running 0 51s
乍看之下一切正常... 如果我們深入了解,我們可以看到其中的奧妙。
$ kubectl get pod -o "custom-columns="\
"NAME:.metadata.name,"\
"INIT:.spec.initContainers[*].name,"\
"CONTAINERS:.spec.containers[*].name"
NAME INIT CONTAINERS
sleep-7656cf8794-8fhdk istio-init,istio-proxy sleep
在這裡,我們可以查看 Pod 中的所有 containers
和 initContainers
。
驚喜!istio-proxy
現在是一個 initContainer
。
更具體地說,它是一個設定了 restartPolicy: Always
的 initContainer
(一個新欄位,由 SidecarContainers
功能啟用)。這會告訴 Kubernetes 將其視為 sidecar。
這表示清單中稍後的 initContainers
以及所有正常的 containers
都會在代理容器準備好後才會啟動。此外,即使代理容器仍在執行,Pod 也會終止。
初始化容器流量
為了測試這一點,讓我們讓我們的 Pod 實際執行一些操作。在這裡,我們部署一個簡單的 Pod,它在 initContainer
中發送請求。通常,這會失敗。
apiVersion: v1
kind: Pod
metadata:
name: sleep
spec:
initContainers:
- name: check-traffic
image: istio/base
command:
- curl
- httpbin.org/get
containers:
- name: sleep
image: istio/base
command: ["/bin/sleep", "infinity"]
檢查代理容器,我們可以發現請求成功,並且通過了 Istio sidecar
$ kubectl logs sleep -c istio-proxy | tail -n1
[2023-07-25T22:00:45.703Z] "GET /get HTTP/1.1" 200 - via_upstream - "-" 0 1193 334 334 "-" "curl/7.81.0" "1854226d-41ec-445c-b542-9e43861b5331" "httpbin.org" ...
如果我們檢查 Pod,我們可以發現我們的 sidecar 現在在 check-traffic
initContainer
之前執行
$ kubectl get pod -o "custom-columns="\
"NAME:.metadata.name,"\
"INIT:.spec.initContainers[*].name,"\
"CONTAINERS:.spec.containers[*].name"
NAME INIT CONTAINERS
sleep istio-init,istio-proxy,check-traffic sleep
正在退出的 Pod
先前,我們提到當應用程式退出(Job
中常見)時,Pod 會永遠存活。幸運的是,這個問題也得到了解決!
首先,我們部署一個在 1 秒後退出且不會重新啟動的 Pod
apiVersion: v1
kind: Pod
metadata:
name: sleep
spec:
restartPolicy: Never
containers:
- name: sleep
image: istio/base
command: ["/bin/sleep", "1"]
我們可以觀察其進度
$ kubectl get pods -w
NAME READY STATUS RESTARTS AGE
sleep 0/2 Init:1/2 0 2s
sleep 0/2 PodInitializing 0 2s
sleep 1/2 PodInitializing 0 3s
sleep 2/2 Running 0 4s
sleep 1/2 Completed 0 5s
sleep 0/2 Completed 0 12s
在這裡,我們可以看到應用程式容器已退出,不久之後,Istio 的 sidecar 容器也退出。以前,Pod 會卡在 Running
狀態,而現在它可以轉換為 Completed
狀態。不再有殭屍 Pod 了!
Ambient 模式呢?
去年,Istio 宣布了 Ambient 模式 - 一種新的 Istio 資料平面模式,不依賴 sidecar 容器。因此,隨著 Ambient 模式的出現,這一切還有意義嗎?
我會說「是的」!
雖然在工作負載使用 Ambient 模式時,sidecar 的影響會減輕,但我認為幾乎所有大規模 Kubernetes 用戶在其部署中都有某種 sidecar。這可能是他們不想遷移到 Ambient 的 Istio 工作負載,他們尚未遷移的工作負載,或與 Istio 無關的事物。因此,雖然可能只有少數情況需要用到,但對於使用 sidecar 的情況來說,它仍然是一個巨大的改進。
你可能會想反過來問 - 如果我們所有的 sidecar 問題都解決了,為什麼我們還需要 Ambient 模式?在解決這些 sidecar 限制的同時,Ambient 仍然帶來了各種好處。例如,這篇部落格文章詳細介紹了為什麼將代理與工作負載分離是有利的。
自己試試看
我們鼓勵喜歡冒險的讀者在測試環境中親自試用!這些實驗性和 Alpha 版功能的回饋對於確保它們穩定並在推廣之前滿足期望至關重要。如果你嘗試過,請在 Istio Slack 中告訴我們你的想法!
特別是,Kubernetes 團隊有興趣了解更多關於
- 關閉順序的處理,尤其是當涉及多個 sidecar 時。
- 當 sidecar 容器崩潰時的回退重新啟動處理。
- 他們尚未考慮的邊緣情況。