Istio 數據平面 Pod 啟動過程詳解
本文將為你講解:
- Istio 中 sidecar 自動注入過程
- Istio 中的 init 容器啟動過程
- 啟用了 Sidecar 自動注入的 Pod 的啟動流程
下圖中展示了 Istio 數據平面中的 Pod 啟動完後的組件。
Istio 中的 sidecar 注入
Istio 中提供了以下兩種 sidecar 注入方式:
-
使用
istioctl
手動注入。 - 基於 Kubernetes 的 突變 webhook 准入控制器(mutating webhook addmission controller 的自動 sidecar 注入方式。
不論是手動注入還是自動注入,sidecar 的注入過程都需要遵循如下步驟:
- Kubernetes 需要了解待注入的 sidecar 所連接的 Istio 集羣及其配置;
- Kubernetes 需要了解待注入的 sidecar 容器本身的配置,如鏡像地址、啟動參數等;
- Kubernetes 根據 sidecar 注入模板和以上配置填充 sidecar 的配置參數,將以上配置注入到應用容器的一側;
使用下面的命令可以手動注入 sidecar。
istioctl kube-inject -f ${YAML_FILE} | kuebectl apply -f -
該命令會使用 Istio 內置的 sidecar 配置來注入,下面使用 Istio詳細配置請參考 Istio 官網 。
注入完成後您將看到 Istio 為原有 pod template 注入了 initContainer
及 sidecar proxy相關的配置。
Init 容器
Init 容器是一種專用容器,它在應用程序容器啟動之前運行,用來包含一些應用鏡像中不存在的實用工具或安裝腳本。
一個 Pod 中可以指定多個 Init 容器,如果指定了多個,那麼 Init 容器將會按順序依次運行。只有當前面的 Init 容器必須運行成功後,才可以運行下一個 Init 容器。當所有的 Init 容器運行完成後,Kubernetes 才初始化 Pod 和運行應用容器。
Init 容器使用 Linux Namespace,所以相對應用程序容器來説具有不同的文件系統視圖。因此,它們能夠具有訪問 Secret 的權限,而應用程序容器則不能。
在 Pod 啟動過程中,Init 容器會按順序在網絡和數據卷初始化之後啟動。每個容器必須在下一個容器啟動之前成功退出。如果由於運行時或失敗退出,將導致容器啟動失敗,它會根據 Pod 的 restartPolicy
指定的策略進行重試。然而,如果 Pod 的 restartPolicy
設置為 Always,Init 容器失敗時會使用 RestartPolicy
策略。
在所有的 Init 容器沒有成功之前,Pod 將不會變成 Ready
狀態。Init 容器的端口將不會在 Service中進行聚集。 正在初始化中的 Pod 處於 Pending
狀態,但應該會將 Initializing
狀態設置為 true。Init 容器運行完成以後就會自動終止。
關於 Init 容器的詳細信息請參考 Init 容器 - Kubernetes 中文指南/雲原生應用架構實踐手冊 。
Init 容器解析
Istio 在 pod 中注入的 Init 容器名為 istio-init
,我們在上面 Istio 注入完成後的 YAML 文件中看到了該容器的啟動命令是:
istio-iptables -p 15001 -z 15006 -u 1337 -m REDIRECT -i '*' -x "" -b '*' -d 15090,15020
我們再檢查下該容器的 Dockerfile
看看 ENTRYPOINT
是怎麼確定啟動時執行的命令。
# 前面的內容省略 # The pilot-agent will bootstrap Envoy. ENTRYPOINT ["/usr/local/bin/pilot-agent"]
我們看到 istio-init
容器的入口是 /usr/local/bin/istio-iptables
命令行,該命令行工具的代碼的位置在 Istio 源碼倉庫的 tools/istio-iptables
目錄。
注意:在 Istio 1.1 版本時還是使用 isito-iptables.sh
命令行來操作 IPtables。
Init 容器啟動入口
Init 容器的啟動入口是 istio-iptables
命令行,該命令行工具的用法如下:
$ istio-iptables [flags] -p: 指定重定向所有 TCP 流量的 sidecar 端口(默認為 $ENVOY_PORT = 15001) -m: 指定入站連接重定向到 sidecar 的模式,“REDIRECT” 或 “TPROXY”(默認為 $ISTIO_INBOUND_INTERCEPTION_MODE) -b: 逗號分隔的入站端口列表,其流量將重定向到 Envoy(可選)。使用通配符 “*” 表示重定向所有端口。為空時表示禁用所有入站重定向(默認為 $ISTIO_INBOUND_PORTS) -d: 指定要從重定向到 sidecar 中排除的入站端口列表(可選),以逗號格式分隔。使用通配符“*” 表示重定向所有入站流量(默認為 $ISTIO_LOCAL_EXCLUDE_PORTS) -o:逗號分隔的出站端口列表,不包括重定向到 Envoy 的端口。 -i: 指定重定向到 sidecar 的 IP 地址範圍(可選),以逗號分隔的 CIDR 格式列表。使用通配符 “*” 表示重定向所有出站流量。空列表將禁用所有出站重定向(默認為 $ISTIO_SERVICE_CIDR) -x: 指定將從重定向中排除的 IP 地址範圍,以逗號分隔的 CIDR 格式列表。使用通配符 “*” 表示重定向所有出站流量(默認為 $ISTIO_SERVICE_EXCLUDE_CIDR)。 -k:逗號分隔的虛擬接口列表,其入站流量(來自虛擬機的)將被視為出站流量。 -g:指定不應用重定向的用户的 GID。(默認值與 -u param 相同) -u:指定不應用重定向的用户的 UID。通常情況下,這是代理容器的 UID(默認值是 1337,即 istio-proxy 的 UID)。 -z: 所有進入 pod/VM 的 TCP 流量應被重定向到的端口(默認 $INBOUND_CAPTURE_PORT = 15006)。
以上傳入的參數都會重新組裝成
iptables
規則,關於該命令的詳細用法請訪問 tools/istio-iptables/pkg/cmd/root.go
。
該容器存在的意義就是讓 sidecar 代理可以攔截所有的進出 pod 的流量,15090 端口(Mixer 使用)和 15092 端口(Ingress Gateway)除外的所有入站(inbound)流量重定向到 15006 端口(sidecar),再攔截應用容器的出站(outbound)流量經過 sidecar 處理(通過 15001 端口監聽)後再出站。關於 Istio 中端口用途請參考 Istio 官方文檔 。
命令解析
這條啟動命令的作用是:
- 將應用容器的所有流量都轉發到 sidecar 的 15006 端口。
-
使用
istio-proxy
用户身份運行, UID 為 1337,即 sidecar 所處的用户空間,這也是istio-proxy
容器默認使用的用户,見 YAML 配置中的runAsUser
字段。 -
使用默認的
REDIRECT
模式來重定向流量。 - 將所有出站流量都重定向到 sidecar 代理(通過 15001 端口)。
因為 Init 容器初始化完畢後就會自動終止,因為我們無法登陸到容器中查看 iptables 信息,但是 Init 容器初始化結果會保留到應用容器和 sidecar 容器中。
Pod 啟動流程
啟用了 Sidecar 自動注入的 Pod 啟動流程如下:
- Init 容器先啟動,向 Pod 中注入 iptables 規則,進行透明流量攔截。
-
隨後,Kubernetes 會根據 Pod Spec 中容器的聲明順序依次啟動容器,但這是非阻塞的,無法保證第一個容器啟動完成後才啟動下一個。
istio-proxy
容器啟動時,pilot-agent
將作為 PID 1 號進程,它是 Linux 用户空間的第一個進程,負責拉起其他進程和處理殭屍進程。pilot-agent
將生成 Envoy bootstrap 配置並拉起envoy
進程;應用容器幾乎跟istio-proxy
容器同時啟動,為了防止 Pod 內的容器在還沒啟動好的情況而接收到外界流量,這時候就緒探針就派上用場了。Kubernetes 會在istio-proxy
容器的 15021 端口進行就緒檢查,直到isito-proxy
啟動完成後 kubelet 才會將流量路由到 Pod 內。 -
在 Pod 啟動完成後,
pilot-agent
將變為守護進程監視系統其他進程,除此之外,該進程還為 Envoy 提供 Bootstrap 配置、證書、健康檢查、配置熱加載、身份支持及進程生命週期管理等。
Pod 內容器啟動順序問題
在 Pod 啟動的過程中存在容器啟動順序問題,假設下面這種情況,應用容器先啟動,請求其他服務,這時候 istio-proxy
容器還沒啟動完成,那麼該請求將會失敗,如果你的應用的健壯性不足,甚至可能導致應用容器崩潰,進而 Pod 重啟。對於這種情況的解決方案是:
- 修改應用程序,增加超時重試。
-
增加應用容器中進程的啟動延遲,比如增加
sleep
時間。 -
在應用容器中增加一個
postStart
配置,檢測應用進程是否啟動完成,只有當檢測成功時,Kubernetes 才會將 Pod 的狀態標記為Running
。
總結
這篇文章帶領大家瞭解了 Istio 數據平面中的 Pod 啟動過程,還有因為 Pod 內容器啟動順序帶來的問題。
參考
- 自 2020 年以來全球的開源商業化軟件融資情況
- IstioCon 2022 回顧及錄像、PPT 分享
- Beyond Istio OSS —— Istio 服務網格的現狀及未來
- 如何在 Istio 中集成 SPRIRE?
- 什麼是零信任?
- 為什麼 Istio 要使用 SPIRE 做身份認證?
- 再見 KataCoda!
- 如何編譯 Istio?
- Istio 數據平面 Pod 啟動過程詳解
- Istio 中的各組件端口及功能詳解
- Istio sidecar 中的流量類型及 iptables 規則詳解
- Tetrate 公司開源項目介紹
- 跨越鴻溝:理解鴻溝理論
- 網易開源 Istio 擴展項目 Slime 簡介——基於 Istio 的智能服務網格管理器
- 服務網格現狀之我見
- 如何理解 Istio Ingress, 它與 API Gateway 有什麼區別?
- 如何調試 Kubernetes 中的微服務 ——proxy、sidecar 還是 service mesh?
- Jimmy Song:為什麼山寨幣持有者不關心比特幣 Taproot 升級?
- Zoom OBS B 站直播配置手冊
- Istio 開源四週年回顧與展望