istio部署

charlieroro發表於2020-09-05

Istio的部署介紹

部署模型

當配置一個生產級別的Istio時,需要解決一些問題:如網格是單叢集使用,還是跨叢集使用?所有的服務會放到一個完全可達的網路中,還是需要閘道器來連線跨網路的服務?使用一個控制面(可能會跨叢集共享一個控制面),還是使用多個控制面來實現高可用(HA)?所有的叢集都連線到一個多叢集服務網格,還是聯合成一個多網格形態。

所有這些問題,以及他外因素,都代表了Istio部署的各個配置維度。

  1. 單叢集或多叢集
  2. 單網路或多網路
  3. 單控制面或多控制面
  4. 單網格或多網格

上述條件可以任意組合(雖然有些組合相比其他更加普遍,有些則不那麼受歡迎,如單叢集中的多網格場景)。

在一個涉及多叢集的生產環境中,可以混合使用部署模型。例如,可以使用多個控制面來做到HA。在一個3叢集環境中,可以將兩個叢集共享一個控制面,然後給第三個叢集在不同的網路中新增另外一個控制面。然後配置三個叢集共享各自的控制面,這樣所有的叢集就可以使用2個控制面來做到HA。

實際使用中,需要根據隔離性,效能,以及HA要求來選擇合適的部署模型。本章將描述部署Istio時的各種選擇和考量。

叢集模式

該模式下,應用的負載會執行在多個叢集中。為了隔離,效能或高可用,可以限定叢集的可用zone和region。

取決於具體要求,生產系統可以跨多個zone或region的多個叢集執行,利用雲負載均衡器來處理諸如本地性,zonal 或regional故障轉移之類的事情。

大多數場景下,叢集表示配置和終端發現的邊界。例如,每個kubernetes叢集都有一個API Server來管理叢集的配置,以及提供服務終端的資訊,如pod的啟停等。由於kubernetes的這種配置行為是基於單個叢集的,因此會將潛在的錯誤(如配置錯誤)限制在其所在的叢集中。

使用Istio可以在任意個叢集上配置一個服務網格。

單叢集

在最簡單的場景中,可以在單個叢集中部署單Istio網格。一個叢集通常會執行在一個獨立的網路中,但具體取決於基礎設施提供商。包含一個網路的單叢集模型會包含一個控制面,這就是istio最簡單的部署模型:

單叢集的部署比較簡單,但同時也缺少一些特性,如故障隔離和轉移。如果需要高可用,則應該使用多叢集模式。

多叢集

一個網格可以包含多個叢集。使用多叢集部署可以在一個網格中提供如下功能。

  • 故障隔離和轉移:當cluster-1當機後,使用cluster-2
  • 位置感知路由和故障轉移:傳送請求到最近的服務
  • 多種控制面模型:支援不同級別的可用性。
  • 團隊和專案隔離:每個團隊執行各自的叢集

多叢集部署提供了更大的隔離性和可靠性,但同時也增加了複雜性。如果系統需要高可用,則叢集可能會跨多個zone和region。

可以通過金絲雀配置來在單個叢集中修改或使用新的二進位制版本,這樣配置變更僅會影響一小部分的使用者流量。如果一個叢集出現問題,可以臨時把流量路由到臨近的叢集(直到問題解決)。

此外,可以根據網路和雲提供商支援的選項配置叢集間的通訊。例如,如果兩個叢集使用了相同的底層網路,那麼就可以通過簡單的防火牆規則實現叢集間的通訊。

網路模型

很多生產系統需要多個網路或子網來實現隔離和高可用。Istio支援將一個服務網格部署到多種型別的網路拓撲中。通過這種方式選擇符合現有網路拓撲的網路模型。

單網路

在最簡單場景下,服務網格會執行在一個完全連線的網路上,在單網路模型下,所有的負載示例能夠在沒有Istio網格的情況下實現互聯。

單個網路使Istio能夠在網格中以統一的方式配置服務使用者,並具有直接處理工作負載例項的能力。

多網路

多網路提供瞭如下新功能:

  • service endpoints提供了可交叉的IP或VIP
  • 跨邊界
  • 容錯功能
  • 擴充套件網路地址
  • 符合網路分段的標準

這種模式下,不同網路中的負載例項只能通過一個或多個Istio閘道器進行互聯。Istio使用分割槽服務發現來為使用者提供service endpoints的不同檢視。檢視取決於使用者的網路。

控制面模型

Istio網格使用控制面來配置網格內負載例項之間的通訊。通過複製控制面,工作負載可以連線到任何控制面來獲取配置。

最簡單的場景下,可在單叢集中執行網格的控制面:

像這樣具有自己的本地控制平面的叢集被稱為主叢集。

多叢集部署可以共享相同的控制面例項。這種情況下,控制面例項可以位於一個或多個主叢集中。沒有自己的控制面的叢集稱為遠端叢集。

一個完全由遠端叢集組成的服務網格可以通過外部控制面進行控制,而不需要通過執行在主叢集中的控制面進行控制。通過這種方式將istio在管理上進行了隔離,即將控制面和資料面服務進行了完全分割。

雲提供商的Managed Control Plane實際上就是一個外部控制面。

為了高可用,控制面可能需要跨多叢集,zone和region來部署。下圖中的服務網格在每個region中都使用了一個控制面。

使用上述模型具有如下優勢:

  • 提升可用性:如果一個控制面不可用,停機的範圍將僅限於該控制平面
  • 配置隔離:可以修改一個叢集,zone或region中的配置,而不會影響另外一個控制面的配置。

可以通過故障轉移來提升控制面的可靠性。當一個控制面例項變為不可用時,負載例項可以連線到其他可用的控制面例項上。叢集,zone和region中都可能發生故障遷移。下圖可以看到,當左側的控制面出問題後,由右側的控制面託管了Envoy代理(虛線)。

以下列表按可用性對控制平面的部署進行了排序:

  • 每個region一個叢集(低可用性)
  • 每個region多叢集
  • 一個zone一個叢集
  • 一個zone多個叢集
  • 每個叢集一個控制面(高可用性)

身份和信任模型

當在一個服務網格中建立負載例項時,istio會賦予該負載一個身份。

CA( certificate authority)會為網格中使用的身份建立和頒發證書,後續就可以使用CA為該身份建立和頒發證書時使用的公鑰對訊息傳送端進行校驗。trust bundle是Istio網格使用的所有CA公鑰的集合。任何人都可以使用網格的trust bundle校驗來自網格的服務。

網格中的信任

在單istio網格中,istio保證每個負載例項都有一個標識其身份的證書,使用trust bundle來識別網格和聯邦網格中的所有身份。CA僅負責為這些身份建立和簽發證書。該模型允許網格中的負載例項互聯。下圖展示了一個具有 certificate authority的服務網格。

網格之間的信任

如果一個網格中的服務需要呼叫另外一個網格中的服務,此時需要在兩個網格之間使用聯邦身份。為了實現聯邦身份的信任,需要交換網格的trust buncles(可以通過手動或自動方式,如SPIFFE Trust Domain Federation來交換trust bundles)

網格模型

Istio支援在一個網格或聯邦網格(也被稱為多網格)中部署所有的應用。

單網格

單網格是部署Istio的最簡單的方式。在一個網格中,服務名是唯一的。例如,一個foo名稱空間中,只能存在一個名為mysvc的服務。此外,負載例項共享同一個身份service account,因為該資源在名稱空間內是唯一的。

單網格可以部署在一個或多個叢集中,以及一個或多個網路上。在一個網格中,名稱空間用於tenancy(見下)。

多網格

多網格是網格聯邦的結果。

多網格提供瞭如下功能:

  • 組織邊界:業務線
  • 重用服務名稱或名稱空間:例如default名稱空間可以用於多種用途
  • 強隔離:將測試負載和生產負載進行隔離。

可以使用中間網格來連線網格聯邦。當使用聯邦時,每個網格都可以暴露一組所有參與的網格都能識別的服務和身份。

為了避免服務名衝突,可以給每個網格分配一個全域性唯一的網格ID,來保證每個服務的fully qualified domain name (FQDN)是有效的。

當聯邦中兩個網格沒有使用相同的信任域時,必須對這兩個網格的身份和trust bundles進行聯邦。檢視Multiple Trust Domains

租戶模式

在Istio中,租戶是一個共享使用者組,共享一組已部署的工作負載的訪問許可權和特權。通常需要從網路配置和策略層面來為不同的租戶隔離負載例項。

可以配置租戶模式來滿足組織的隔離需求:

  • 安全
  • 策略
  • 容量
  • 成本
  • 效能

Istio支援兩種型別的租戶:

Namespace tenancy

在一個網格中,Istio使用名稱空間作為租戶的單位。Istio也可以執行在沒有實現名稱空間租戶的環境中。在實現名稱空間租戶的環境中,可以保證僅允許一個團隊將負載部署在一個給定的名稱空間或一組名稱空間中。預設情況下,多個租戶名稱空間中的服務都可以互聯。

為了提升隔離性,可以選擇暴露到其他名稱空間中的服務。通過授權策略來暴露服務或限制訪問。

當使用多叢集時,每個叢集中的相同名稱的名稱空間被看作是相同的名稱空間。例如,cluster-1中的foo名稱空間中的Service B,以及cluster-2中的foo名稱空間中的Service B被認為是相同的服務,且Istio會在服務發現時合併endpoints,並在這些endpoints間執行負載均衡。下圖展示了具有相同名稱空間的兩個叢集

Cluster tenancy

Istio支援以叢集作為租戶的單位。這種情況下,可以給每個團隊指定特定的叢集或一組叢集來部署負載,並授權團隊成員。可以給成員分配不同的角色,如:

  • 叢集管理員
  • 開發人員

為了在Istio中使用叢集租戶,需要將每個叢集作為獨立的網格。此外,可以使用Istio將一組叢集作為單租戶。這樣每個團隊就可以擁有一個或多個叢集,而不是將所有的叢集配置為單網格。為了連線不同團隊的網格,可以將這些將這些網格聯邦為多網格。下圖展示了使用兩個叢集和名稱空間來隔離服務網格。

由於網格由不同的團隊或組織進行操作,因此服務命名很少會不同。例如,cluster-1foo名稱空間中的mysvccluster-2foo名稱空間中的mysvc服務並不是相同的服務。最常見的示例是Kubernetes中的場景,許多團隊將工作負載部署到default名稱空間。

當每個團隊都有各自的網格後,就可以使用多網格模型跨網格進行通訊。

效能和可靠性

Istio使用豐富的路由,負載均衡,服務到服務的認證,監控等簡化了部署服務的網路,且不需要修改應用程式碼。Istio力爭使用最少的資源開銷來提供這些便利,以及在增加最小的延遲下支撐更大規模的網格和更高的請求率。

Istio資料面元件,Envoy代理會處理流經系統的資料。Istio的控制面元件,Pilot,Galley和Citadel來配置資料面。資料面和控制面都有明顯的效能問題。

1.7的效能摘要

Istio負載測試網格包含1000個服務和2000個sidecar,每秒70000個網格範圍的請求。在對Istio1.7測試之後,得出如下結果:

  • 在每秒有1000個請求經過代理時,Envoy代理會使用0.5 vCPU50 MB記憶體
  • 如果部署時使用了Mixer,在每秒有1000個網格範圍的請求時,istio-telemetry服務會使用0.6 vCPU
  • Pilot使用1 vCPU 和1.5 GB記憶體
  • Envoy代理對90%的延遲增加了3.12毫秒。

控制面效能

Pilot會根據使用者的配置檔案和系統的當前狀態配置sidecar代理。在Kubernetes環境中,CRD和deployment構成了配置和系統狀態。Istio配置物件,如gateway和virtual service等提供了使用者可編輯的配置。為了生成代理的配置,Pilot處理來自Kubernetes環境和使用者配置的組合配置以及系統狀態。

控制平面支援成千上萬的服務,這些服務分佈在成千上萬個Pod中,並使用類似數量的由使用者編寫的virtual services和其他配置物件。Pilot的CPU和記憶體會隨著配置資料的變化和系統狀態而變化。CPU的使用包含如下因素:

  • deployment變化率
  • 配置變化率
  • 連線到Pilot的代理數目

但這部分是支援水平擴充套件的。

當啟用名稱空間租戶時,使用1vCPU和1.5GB記憶體的單個Pilot可以支援1000個服務,2000個sidecar。可以通過增加Pilot的數量來降低配置所有代理的時間。

資料面效能

資料面效能依賴很多因素,如:

  • 客戶端連線數
  • 目標請求率
  • 請求大小和響應大小
  • 代理worker的執行緒數
  • 協議
  • CPU cores
  • 代理過濾器的數目和型別,特別是Mixer的過濾器

延遲,吞吐量以及代理的CPU和記憶體消耗均根據上述因素進行衡量。

CPU和記憶體

由於sidecar代理會在資料路徑上做一些額外的工作,因此會消耗CPU和記憶體。如Istio 1.1中,在每秒1000個請求的情況下,一個代理會消耗0.6 vCPU。

代理的記憶體消耗取決於代理儲存的總配置狀態。大量listeners,clusters和routes可能會增加記憶體消耗。Istio 1.1引入了名稱空間隔離來限制傳送到一個代理的配置。在一個大的名稱空間中,一個代理大概會消耗50 MB的記憶體。

由於代理通常不會快取通過的資料,因此請求率不會影響記憶體消耗。

名稱空間的隔離是通過sidecar資源實現的。如何使用可以參見istio-namespace-isolation-tricks

延遲

由於Istio在資料路徑上注入了sidecar代理,因此延遲是一個需要重點考慮的因素。Istio會將身份驗證和Mixer過濾器新增到代理,每個額外的過濾器都會增加代理內部的路徑長度,並影響到延遲。

Envoy代理會收在客戶端接收到響應之後採集原始的遙測資料。對採集請求的遙測資料的時間不會計算在總的完成請求所需要的時間內。但由於worker忙於處理請求,因此worker可能不會立即處理下一個請求。這種處理會增加請求在佇列中等待的時間,並影響到平均值和尾部延遲。實際的尾部延遲取決於流量狀況。

Istio 1.7的延遲

在網格中,請求會通過客戶端的代理,然後到達服務端。1.7的預設配置中(即,telemetry V2),這兩個代理在基準資料平面延遲的90百分位和99百分位延遲上分別增加了大約3.12ms 和3.13ms。通過Istio benchmarkshttp/1.1協議得出如上結論,使用兩個代理worker,並啟用mutual TLS,通過16個客戶端連線來傳送每秒1000個請求,每個請求1KB。

在即將釋出的Istio版本中,將把Istio策略和Istio遙測功能作為TelemetryV2新增到代理中。通過這種方式來減少流經系統的資料量,從而減少CPU使用量和延遲。

P90 latency vs client connections without jitter

image-20200905201003085

P99 latency vs client connections without jitter

P90 latency vs client connections with jitter

P99 latency vs client connections with jitter

  • baseline 客戶端Pod直接呼叫服務端Pod,不經過sidecar
  • none_both 使用Istio代理,但不配置Istio過濾器
  • v2-stats-wasm_both 客戶端和服務端的sidecar都配置似乎用telemetry v2 v8
  • v2-stats-nullvm_both 客戶端和服務端的sidecar預設都配置似乎用telemetry v2 nullvm
  • v2-sd-full-nullvm_both 使用配置的 telemetry v2 nullvm暴露Stackdriver metrics,訪問日誌
  • v2-sd-nologging-nullvm_both 與上面系統,但不暴露訪問日誌

Benchmarking 工具

Istio使用如下工具來進行benchmarking:

  • fortio.org - 恆定吞吐量的負載測試工具
  • blueperf - 真實的雲原生應用程式
  • isotope - 具有可配置拓撲的合成應用程式

Pods 和Services

作為網格的一部分,kubernetes的pod和service必須滿足如下要求:

  • 關聯的Service:一個pod必須對應至少一個kubernetes service,即使pod沒有暴露任何埠。如果一個pod對應多個kubernetes services,那麼這些services無法為不同的協議使用相同的埠號,如HTTP和TCP。
  • 應用的UID:確保pods不能以使用者ID (UID)值為1337的身份執行應用程式
  • NET_ADMINNET_RAW capabilities:如果叢集強制使用pod安全策略,則必須給pod新增 NET_ADMINNET_RAW capabilities。如果使用了Istio CNI 外掛,則可以不遵守該要求。
  • Deployments 使用 appversion labels:建議Deployments 使用appversion labels。appversion labels會給istio採集的metrics和遙測資料新增上下文資訊
    • app label:每個deployment應該包含不同的app label。app label用於在分散式跟蹤中新增上下文資訊。
    • version label:指定特定deployment對應的應用版本。
  • 命名service埠:可以選擇使用命名服務埠來指定協議。更多細節參見Protocol Selection

要求的pod capabilities

如果叢集使用了pod安全策略,除非使用了Istio CNI外掛,否則pod必須允許NET_ADMINNET_RAW capabilities。Envoy代理的initialization容器會使用這些capabilities。

為了校驗pod是否允許NET_ADMINNET_RAW capabilities,需要校驗pod對應的service account是否可以使用pod安全策略來允許NET_ADMINNET_RAW capabilities。如果沒有在pod的deployment中指定service account,那麼pod會使用其所在名稱空間的default service account。

使用如下命令可以列出一個service accout的capabilities,替換<your namespace><your service account>

# for psp in $(kubectl get psp -o jsonpath="{range .items[*]}{@.metadata.name}{'\n'}{end}"); do if [ $(kubectl auth can-i use psp/$psp --as=system:serviceaccount:<your namespace>:<your service account>) = yes ]; then kubectl get psp/$psp --no-headers -o=custom-columns=NAME:.metadata.name,CAPS:.spec.allowedCapabilities; fi; done

例如可以使用如下命令來校驗default名稱空間中的default service account。

# for psp in $(kubectl get psp -o jsonpath="{range .items[*]}{@.metadata.name}{'\n'}{end}"); do if [ $(kubectl auth can-i use psp/$psp --as=system:serviceaccount:default:default) = yes ]; then kubectl get psp/$psp --no-headers -o=custom-columns=NAME:.metadata.name,CAPS:.spec.allowedCapabilities; fi; done

如果在capabilities列表中看到 NET_ADMINNET_ADMIN*,則說明該pod允許執行Isti init容器,否則需要配置許可權

相關文章