萬字長文從 0 詳解 Istio

在本教程中,我們將介紹服務網格的基礎知識,並瞭解它如何實現分佈式系統架構。

我們將主要關注 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 在 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: ["testing@baeldung.com/testing@baeldung.io"]

在這裏,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 一起使用。

除了 Kubernetes,Consul 還可以與 Nomad 等其他平臺一起使用。Consul 通過在每個節點上運行 Consul 代理以執行運行狀況檢查來工作。這些代理與一臺或多臺存儲和複製數據的 Consul 服務器通信。儘管它提供了服務網格(如 Istio)的所有標準功能,但它是部署和管理的更復雜的系統。

總結

總而言之,在本教程中,我們介紹了服務網格模式的基本概念以及它提供給我們的功能。特別是,我們詳細介紹了 Istio。這涵蓋了 Istio 的核心架構及其基本組件。此外,我們詳細介紹了一些常見用例的安裝和使用 Istio 的細節。

作者:唐建法

來源:Mongoing 中文社區

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Ajvn4mv2M4ghuV95ErBqhA