Istio 資料平面 Pod 啟動過程詳解

語言: CN / TW / HK

本文將為你講解:

  • Istio 中 sidecar 自動注入過程
  • Istio 中的 init 容器啟動過程
  • 啟用了 Sidecar 自動注入的 Pod 的啟動流程

下圖中展示了 Istio 資料平面中的 Pod 啟動完後的元件。

Istio 資料平面 Pod 內部元件

Istio 中的 sidecar 注入

Istio 中提供了以下兩種 sidecar 注入方式:

不論是手動注入還是自動注入,sidecar 的注入過程都需要遵循如下步驟:

  1. Kubernetes 需要了解待注入的 sidecar 所連線的 Istio 叢集及其配置;
  2. Kubernetes 需要了解待注入的 sidecar 容器本身的配置,如映象地址、啟動引數等;
  3. 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 啟動流程如下:

  1. Init 容器先啟動,向 Pod 中注入 iptables 規則,進行透明流量攔截。
  2. 隨後,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 內。
  3. 在 Pod 啟動完成後, pilot-agent 將變為守護程序監視系統其他程序,除此之外,該程序還為 Envoy 提供 Bootstrap 配置、證書、健康檢查、配置熱載入、身份支援及程序生命週期管理等。

Pod 內容器啟動順序問題

在 Pod 啟動的過程中存在容器啟動順序問題,假設下面這種情況,應用容器先啟動,請求其他服務,這時候 istio-proxy 容器還沒啟動完成,那麼該請求將會失敗,如果你的應用的健壯性不足,甚至可能導致應用容器崩潰,進而 Pod 重啟。對於這種情況的解決方案是:

  • 修改應用程式,增加超時重試。
  • 增加應用容器中程序的啟動延遲,比如增加 sleep 時間。
  • 在應用容器中增加一個 postStart 配置,檢測應用程序是否啟動完成,只有當檢測成功時,Kubernetes 才會將 Pod 的狀態標記為 Running

總結

這篇文章帶領大家瞭解了 Istio 資料平面中的 Pod 啟動過程,還有因為 Pod 內容器啟動順序帶來的問題。

參考