- 前言 -
在本教程中,我們将介紹服務網格的基礎知識,并了解它如何實作分布式系統架構。
我們将主要關注Istio,它是服務網格的一種具體實作。在此過程中,我們将介紹Istio的核心架構。
- 什麼是服務網絡 -
在過去的幾十年中,我們已經看到了單體應用程式開始拆分為較小的應用程式。此外,諸如Docker之類的容器化技術和諸如Kubernetes之類的編排系統加速了這一變化。
盡管在像Kubernetes這樣的分布式系統上采用微服務架構有許多優勢,但它也具有相當的複雜性。由于分布式服務必須互相通信,是以我們必須考慮發現,路由,重試和故障轉移。
還有其他一些問題,例如安全性和可觀察性,我們還必須注意以下問題:
現在,在每個服務中建立這些通信功能可能非常繁瑣,尤其是當服務範圍擴大且通信變得複雜時,更是如此。這正是服務網格可以為我們提供幫助的地方。基本上,服務網格消除了在分布式軟體系統中管理所有服務到服務通信的責任。
服務網格能夠通過一組網絡代理來做到這一點。本質上,服務之間的請求是通過與服務一起運作但位于基礎結構層之外的代理路由的:
這些代理基本上為服務建立了一個網狀網絡——是以得名為服務網格!通過這些代理,服務網格能夠控制服務到服務通信的各個方面。這樣,我們可以使用它來解決分布式計算的八個謬誤,這是一組斷言,描述了我們經常對分布式應用程式做出的錯誤假設。
- 服務網格的特征 -
現在,讓我們了解服務網格可以為我們提供的一些功能。請注意,實際功能清單取決于服務網格的實作。但是,總的來說,我們應該在所有實作中都期望其中大多數功能。
我們可以将這些功能大緻分為三類:流量管理,安全性和可觀察性。
流量管理
服務網格的基本特征之一是流量管理。這包括動态服務發現和路由。尤其影子流量和流量拆分功能,這些對于實作金絲雀釋出和A/B測試非常有用。
由于所有服務之間的通信都是由服務網格處理的,是以它還啟用了一些可靠性功能。例如,服務網格可以提供重試,逾時,速率限制和斷路器。這些現成的故障恢複功能使通信更加可靠。
安全性
服務網格通常還處理服務到服務通信的安全性方面。這包括通過雙向TLS(mTLS)強制進行流量加密,通過證書驗證提供身份驗證以及通過通路政策確定授權。
服務網格中還可能存在一些有趣的安全用例。例如,我們可以實作網絡分段,進而允許某些服務進行通信而禁止其他服務。而且,服務網格可以為稽核需求提供精确的曆史資訊。
可觀察性
強大的可觀察性是處理分布式系統複雜性的基本要求。由于服務網格可以處理所有通信,是以正确放置了它可以提供可觀察性的功能。例如,它可以提供有關分布式追蹤的資訊。
服務網格可以生成許多名額,例如延遲,流量,錯誤和飽和度。此外,服務網格還可以生成通路日志,為每個請求提供完整記錄。這些對于了解單個服務以及整個系統的行為非常有用。
- Istio 簡介 -
Istio是最初由IBM,Google和Lyft開發的服務網格的開源實作。它可以透明地分層到分布式應用程式上,并提供服務網格的所有優點,例如流量管理,安全性和可觀察性。
它旨在與各種部署配合使用,例如本地部署,雲托管,Kubernetes容器以及虛拟機上運作的服務程式。盡管Istio與平台無關,但它經常與Kubernetes平台上部署的微服務一起使用。
從根本上講,Istio的工作原理是以Sidcar的形式将Envoy的擴充版本作為代理布署到每個微服務中:
該代理網絡構成了Istio架構的資料平面。這些代理的配置和管理是從控制平面完成的:
控制平面基本上是服務網格的大腦。它為資料平面中的Envoy代理提供發現,配置和證書管理。
當然,隻有在擁有大量互相通信的微服務時,我們才能展現Istio的優勢。在這裡,sidecar代理在專用的基礎架構層中形成一個複雜的服務網格:
Istio在與外部庫和平台內建方面非常靈活。例如,我們可以将Istio與外部日志記錄平台,遙測或政策系統內建。
- 了解 Istio 元件 -
我們已經看到,Istio體系結構由資料平面和控制平面組成。此外,還有幾個使Istio起作用的核心元件。
在本節中,我們将詳細介紹這些核心元件。
資料平面
Istio的資料平面主要包括Envoy代理的擴充版本。Envoy是一個開源邊緣和服務代理,可幫助将網絡問題與底層應用程式分離開來。應用程式僅向localhost發送消息或從localhost接收消息,而無需了解網絡拓撲。
Envoy的核心是在OSI模型的L3和L4層運作的網絡代理。它通過使用可插入網絡過濾器鍊來執行連接配接處理。此外,Envoy支援用于基于HTTP的流量的附加L7層過濾器。而且,Envoy對HTTP/2和gRPC傳輸具有一流的支援。
Istio作為服務網格提供的許多功能實際上是由Envoy代理的基礎内置功能啟用的:
- 流量控制:Envoy通過HTTP,gRPC,WebSocket和TCP流量的豐富路由規則啟用細粒度的流量控制應用
- 網絡彈性:Envoy包括對自動重試,斷路和故障注入的開箱即用支援
- 安全性:Envoy還可以實施安全政策,并對基礎服務之間的通信應用通路控制和速率限制
Envoy在Istio上表現出色的另一個原因之一是它的可擴充性。Envoy提供了基于WebAssembly的可插拔擴充模型。這在定制政策執行和遙測生成中非常有用。此外,我們還可以使用基于Proxy-Wasm沙箱API的Istio擴充在Istio中擴充Envoy代理。
控制面
如上所述,控制平面負責管理和配置資料平面中的Envoy代理。在Istio架構中,控制面核心元件是istiod,Istiod負責将進階路由規則和流量控制行為轉換為特定于Envoy的配置,并在運作時将其傳播到Sidercar。
如果我們回顧一下Istio控制平面的架構,将會注意到它曾經是一組互相協作的獨立元件。它包括諸如用于服務發現的Pilot,用于配置的Galley,用于證書生成的Citadel以及用于可擴充性的Mixer之類的元件。由于複雜性,這些單獨的元件被合并為一個稱為istiod的單個元件。
從根本上來說,istiod仍使用與先前各個元件相同的代碼和API。例如,Pilot負責抽象特定于平台的服務發現機制,并将其合成為Sidecar可以使用的标準格式。是以,Istio可以支援針對多個環境(例如Kubernetes或虛拟機)的發現。
此外,istiod還提供安全性,通過内置的身份和憑據管理實作強大的服務到服務和最終使用者身份驗證。此外,借助istiod,我們可以基于服務身份來實施安全政策。該過程也充當證書頒發機構(CA)并生成證書,以促進資料平面中的互相TLS(MTLS)通信。
- Istio 工作原理 -
我們已經了解了服務網格的典型特征是什麼。此外,我們介紹了Istio架構及其核心元件的基礎。現在,是時候了解Istio如何通過其架構中的核心元件提供這些功能了。
我們将專注于我們之前經曆過的相同類别的功能。
流量管理
我們可以使用Istio流量管理API對服務網格中的流量進行精細控制。我們可以使用這些API将自己的流量配置添加到Istio。此外,我們可以使用Kubernetes自定義資源定義(CRD)定義API資源。幫助我們控制流量路由的關鍵API資源是虛拟服務和目标規則:
基本上,虛拟服務使我們可以配置如何将請求路由到Istio服務網格中的服務。是以,虛拟服務由一個或多個按順序評估的路由規則組成。評估虛拟服務的路由規則後,将應用目标規則。目标規則有助于我們控制到達目标的流量,例如,按版本對服務執行個體進行分組。
安全性
Istio為每個服務提供身份。與每個Envoy代理一起運作的Istio代理與istiod一起使用以自動進行密鑰和證書輪換:
Istio提供兩種身份驗證——對等身份驗證和請求身份驗證。對等身份驗證用于服務到服務的身份驗證,其中Istio提供雙向TLS作為全棧解決方案。請求身份驗證用于最終使用者身份驗證,其中Istio使用自定義身份驗證提供程式或OpenID Connect(OIDC)提供程式提供JSON Web令牌(JWT)驗證。
Istio還允許我們通過簡單地将授權政策應用于服務來實施對服務的通路控制。授權政策對Envoy代理中的入站流量實施通路控制。這樣,我們就可以在各種級别上應用通路控制:網格,命名空間和服務範圍。
可觀察性
Istio為網格網絡内的所有服務通信生成詳細的遙測,例如度量,分布式跟蹤和通路日志。Istio生成一組豐富的代理級名額,面向服務的名額和控制平面名額。
之前,Istio遙測體系結構将Mixer作為核心元件。但是從Telemetry v2開始,混音器提供的功能已替換為Envoy代理插件:
此外,Istio通過Envoy代理生成分布式跟蹤。Istio支援許多跟蹤後端,例如Zipkin,Jaeger,Lightstep和Datadog。我們還可以控制跟蹤速率的采樣率。此外,Istio還以一組可配置的格式生成服務流量的通路日志。
- Istio 實戰 -
上面我們已經講述了Istio原理和架構,接下來我們開始實戰部分。首先,我們将在Kubernetes叢集中安裝Istio。此外,我們将使用一個簡單的基于微服務的應用程式來示範Istio在Kubernetes上的功能。
安裝
有多種安裝Istio的方法,但最簡單的方法是下載下傳并解壓縮特定作業系統(例如Windows)的最新版本。提取的軟體包在bin目錄中包含istioctl用戶端二進制檔案。我們可以使用istioctl在目标Kubernetes叢集上安裝Istio:
istioctl install --set profile=demo -y
這會使用示範配置檔案将Istio元件安裝在預設的Kubernetes叢集上。我們還可以使用任何其他特定于供應商的配置檔案來代替示範。
最後,當我們在此Kubernetes叢集上部署任何應用程式時,我們需要訓示Istio自動注入Envoy sidecar代理:
kubectl label namespace default istio-injection=enabled
我們在這裡使用kubectl的前提是,我們的機器上已經有像Minikube這樣的Kubernetes叢集和Kubernetes CLI kubectl。
示例應用
為了示範,我們将想象一個非常簡單的線上下訂單應用程式。該應用程式包含三個微服務,它們互相互動以滿足最終使用者的訂購請求:
我們沒有讨論這些微服務的細節,但是使用Spring Boot和REST API可以很簡單地建立它們。最重要的是,我們為這些微服務建立了一個Docker鏡像,以便我們可以将它們部署在Kubernetes上。
部署
在像Minikube這樣的Kubernetes叢集上部署容器化的工作負載非常簡單。我們将使用Deployment和Service資源類型來聲明和通路工作負載。通常,我們在YAML檔案中定義它們:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: order-service
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
app: order-service
version: v1
spec:
containers:
- name: order-service
image: kchandrakant/order-service:v1
resources:
requests:
cpu: 0.1
memory: 200
---
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: order-service
對于訂單服務的“部署和服務”,這是一個非常簡單的定義。同樣,我們可以為庫存服務和運輸服務定義YAML檔案。
使用kubectl部署這些資源也非常簡單:
kubectl apply -f booking-service.yaml -f inventory-service.yaml -f shipping-service.yaml
由于我們已經為預設命名空間啟用了自動注入Envoy sidecar代理,是以一切都會由istiod來處理。或者,我們可以使用istioctl的kube-inject指令手動注入Envoy sidecar代理。
通路應用
現在,Istio主要負責處理所有的網狀網絡流量。是以,預設情況下,不允許進出網格的任何流量。Istio使用網關來管理來自網格的入站和出站流量。這樣,我們可以精确地控制進入或離開網格的流量。Istio提供了一些預配置的網關代理部署:istio-ingressgateway和istio-egressgateway。
我們将為我們的應用程式建立一個網關和一個虛拟服務來實作此目的:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: booking-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: booking
spec:
hosts:
- "*"
gateways:
- booking-gateway
http:
- match:
- uri:
prefix: /api/v1/booking
route:
- destination:
host: booking-service
port:
number: 8080
在這裡,我們利用了Istio提供的預設入口控制器。此外,我們已經定義了一個虛拟服務,将我們的請求路由到預訂服務。
同樣,我們也可以為來自網格的出站流量定義出口網關。
- Istio 的常見用例 -
現在,我們已經看到了如何使用Istio在Kubernetes上部署一個簡單的應用程式。但是,我們仍然沒有利用Istio為我們啟用的任何有趣功能。在本節中,我們将介紹服務網格的一些常見用例,并了解如何使用Istio為我們的簡單應用程式實作它們。
請求路由
我們可能要以特定方式處理請求路由的原因有多個。例如,我們可能會部署微服務的多個版本,例如運輸服務,并希望僅将一小部分請求路由到新版本。
我們可以使用虛拟服務的路由規則來實作這一點:
apiVersion: networking.istio.io/v1alpha3
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: shipping-service
spec:
hosts:
- shipping-service
http:
- route:
- destination:
host: shipping-service
subset: v1
weight: 90
- destination:
host: shipping-service
subset: v2
weight: 10
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: shipping-service
spec:
host: shipping-service
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
路由規則還允許我們基于諸如header參數之類的屬性來定義比對條件。此外,目的地字段指定與條件比對的流量的實際目的地。
熔斷
熔斷器基本上是一種軟體設計模式,用于檢測故障并封裝防止故障進一步級聯的邏輯。這有助于建立有彈性的微服務應用程式,以限制故障和延遲尖峰的影響。
在Istio中,我們可以使用DestinationRule中的trafficPolicy配置在調用諸如清單服務之類的服務時應用熔斷:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: inventory-service
spec:
host: inventory-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 1
http:
http1MaxPendingRequests: 1
maxRequestsPerConnection: 1
outlierDetection:
consecutive5xxErrors: 1
interval: 1s
baseEjectionTime: 3m
maxEjectionPercent: 100
在這裡,我們将DestinationRule配置為maxConnections為1,httpMaxPendingRequests為1,maxRequestsPerConnection為1。這實際上意味着,如果我們将并發請求數超過1,熔斷器将開始trap一些請求。
啟用雙向 TLS
雙向身份驗證是指雙方在諸如TLS之類的身份驗證協定中同時互相進行身份驗證的情況。預設情況下,具有代理的服務之間的所有流量在Istio中都使用互相TLS。但是,沒有代理的服務仍繼續以純文字格式接收流量。
雖然Istio将具有代理的服務之間的所有流量自動更新為雙向TLS,但這些服務仍可以接收純文字流量。我們可以選擇使用PeerAuthentication政策在整個網格範圍内實施雙向TLS:
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "default"
namespace: "istio-system"
spec:
mtls:
mode: STRICT
我們還提供了對每個命名空間或服務而不是在網格範圍内強制實施雙向TLS的選項。但是,特定于服務的PeerAuthentication政策優先于命名空間範圍的政策。
使用JWT進行通路控制
JSON Web令牌(JWT)是用于建立資料的标準,該資料的有效載荷中包含聲明許多聲明的JSON。為了在身份提供者和服務提供者之間傳遞經過身份驗證的使用者的身份和标準或自定義聲明,這一點已被廣泛接受。
我們可以在Istio中啟用授權政策,以允許通路基于JWT的預訂服務之類的服務:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: require-jwt
namespace: default
spec:
selector:
matchLabels:
app: booking-service
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["[email protected]/[email protected]"]
在這裡,AuthorizationPolicy強制所有請求具有有效的JWT,并将requestPrincipal設定為特定值。Istio通過組合聲明JWT的iss和sub來建立requestPrincipal屬性。
- 思考 -
是以,到目前為止,我們已經看到像Istio這樣的服務網格如何使我們更輕松地處理諸如微服務之類的分布式架構中的許多常見問題。但是盡管如此,Istio還是一個複雜的系統,會增加最終部署的複雜性。與其他所有技術一樣,Istio并非靈丹妙藥,必須謹慎使用。
我們應該始終使用服務網格嗎?
盡管我們已經看到了使用服務網格的足夠理由,但下面列舉了一些可能促使我們不使用它的原因:
- 服務網格處理所有服務到服務的通信,而部署和操作服務網格則需要支付額外的費用。對于較簡單的應用程式,這可能是不合理的
- 由于我們已經習慣于處理一些此類問題,例如應用程式代碼中的熔斷,是以可能導緻服務網格中的重複處理
- 越來越依賴于諸如服務網格之類的外部系統可能會損害應用程式的可移植性,尤其是因為沒有針對服務網格的行業标準
- 由于服務網格通常通過攔截通過代理的網格流量來工作,是以它可能會給請求增加不希望的延遲
- 服務網格增加了許多其他元件和配置,需要精确處理。這需要專業知識,并增加了學習曲線
- 最後,我們可能最終将操作邏輯(應在服務網格中存在)與業務邏輯(不應在服務網格中)混合在一起
是以,正如我們所看到的,服務網格的故事不僅僅涉及好處,但這并不意味着它們不是真的。對我們來說,重要的是要仔細評估我們的需求和應用程式的複雜性,然後權衡服務網格的好處和它們所增加的複雜性。
Istio的替代品有哪些?
盡管Istio非常受歡迎,并得到了業内一些上司者的支援,但它當然不是唯一的選擇。盡管我們在這裡無法進行全面的比較,但讓我們看一下Linkerd和Consul這兩個選項。
Linkerd是已為Kubernetes平台建立的開源服務網格。它也很受歡迎,目前在CNCF中具有孵化項目的地位。它的工作原理類似于Istio等任何其他服務網格。它還利用TCP代理來處理網格流量。Linkerd使用用Rust編寫的微型代理,稱為Linkerd代理。
總體而言,Linkerd并不比Istio複雜,因為它僅支援Kubernetes。但是,除此之外,Linkerd中可用的功能清單與Istio中可用的功能非常相似。Linkerd的核心架構也非常類似于Istio。基本上,Linkerd包含三個主要元件:使用者界面,資料平面和控制平面。
Consul是HashiCorp的服務網格的開源實作。它的好處是可以與HashiCorp的其他基礎架構管理産品套件很好地內建,以提供更廣泛的功能。Consul中的資料平面可以靈活地支援代理以及本機內建模型。它帶有内置代理,但也可以與Envoy一起使用。