在現代雲端與微服務環境中,無論你使用 Java、NodeJS、Golang 或任何其他程式語言開發應用程式,最終都需要透過網路與其他服務通訊。然而,網路對應用程式來説是一個充滿挑戰的環境。服務發現、逾時處理、重試機制、斷路器、安全性等問題,都需要妥善解決。
Istio 正是為解決這些挑戰而生的開放原始碼服務網格,它能協助處理雲端和微服務環境中的服務間連線問題,而與不受程式語言或框架的限制。Istio 建立在名為 Envoy 的開放原始碼代理之上,這為 Istio 的功能奠定了堅實的基礎。
雲原生架構面臨的挑戰
當我們嘗試加速開發並利用雲平台和容器等新技術時,會遇到一些放大的舊問題。例如,網路本質上並不可靠,當我們建立更大、更分散的系統時,網路必須成為應用程式設計的核心考量。
這引發了一個問題:應用程式是否應該實作網路彈性功能,如重試、逾時和斷路器?如何實作一致的網路可觀測性?應用層安全性又該如何處理?
彈性、安全性和指標收集是跨領域關注點,並非應用程式特有的功能。更重要的是,這些並非能讓業務脫穎而出的差異化流程。開發人員是大型 IT 系統中的關鍵資源,他們的時間最好用於編寫能以差異化方式提供業務價值的功能。應用程式網路、安全性和指標收集雖然必要,但並不具差異化。我們希望能以不受語言和框架限制的方式實作這些功能,並將其作為策略應用。
服務網格的定義與價值
服務網格是一種用於描述去中心化應用程式網路基礎設施的術語,它能讓應用程式安全、彈性、可觀測與可控制。它描述了一種架構,由資料平面(使用應用層代理來代表應用程式管理網路流量)和控制平面(用於管理代理)組成。這種架構讓我們能在應用程式之外建立重要的應用程式網路功能,而不依賴特定的程式語言或框架。
Istio 是服務網格的開放原始碼實作。它最初由 Lyft、Google 和 IBM 的人員建立,現在已發展成一個充滿活力、開放、多元的社群,包括來自 Lyft、Red Hat、VMWare、Solo.io、Aspen Mesh、Salesforce 等公司的個人。Istio 讓我們能夠建立可靠、安全的雲原生系統,並在大多數情況下無需更改應用程式碼就能解決安全性、策略管理和可觀測性等難題。
Istio 的資料平面由服務代理組成,這些代理根據 Envoy 代理,與應用程式一起執行。它們充當應用程式之間的中介,並根據控制平面傳送的設定影響網路行為。
使用應用程式函式庫解決這些挑戰
最早解決如何在雲環境中執行應用程式和服務的組織是大型網際網路公司,它們中的許多公司開創了我們今天所知道的雲基礎設施。這些公司投入大量時間和資源來為特定語言建立函式庫和框架,這些函式庫和框架幫助解決了在雲原生架構中執行服務的挑戰。
例如,Google 建立了 Stubby 等框架,Twitter 建立了 Finagle,而 Netflix 在 2012 年將其微服務函式庫開放原始碼給社群。以 NetflixOSS 為例,針對 Java 開發人員的函式庫處理了雲原生關注點:
- Hystrix — 斷路和隔艙
- Ribbon — 客戶端負載平衡
- Eureka — 服務註冊和發現
- Zuul — 動態邊緣代理
然而,這種方法有幾個缺點:
- 語言限制:由於這些函式庫針對特定語言(如 Java),它們只能用於該語言的專案。
- 隱含約束:使用這些函式庫會引入圍繞與系統其餘部分互動的未定義協定的隱含約束。
- 多語言環境挑戰:當引入新語言或框架時,需要尋找類別似的函式庫或包,這可能導致不一致的實作。
- 維護困難:維護跨多種程式語言和框架的函式庫需要大量紀律,很難做對。
將這些關注點推向基礎設施
這些基本的應用程式網路關注點並不特定於任何特定應用程式、語言或框架。重試、逾時、客戶端負載平衡、斷路等也不是差異化的應用功能。我們真正想要的是一種與技術無關的方式來實作這些關注點,並減輕應用程式自行實作的負擔。
應用感知的服務代理
使用代理是將這些橫向關注點移入基礎設施的一種方式。代理是一個中間基礎設施元件,可以處理連線並將其重定向到適當的後端。我們經常使用代理(無論是否知道)來處理網路流量、執行安全性和負載平衡工作到後端伺服器。
然而,對於這個問題,我們需要一個能夠代表我們的服務執行應用程式網路的應用程式感知代理。為此,這個服務代理需要理解應用程式建構,如訊息和請求,而不像更傳統的基礎設施代理那樣只理解連線和封包。換句話説,我們需要一個第 7 層代理。
認識 Envoy 代理
Envoy 是一個在開放原始碼社群中崛起的服務代理,它是一個多功能、高效能與功能強大的應用層代理。Envoy 是在 Lyft 開發的,作為該公司 SOA 基礎設施的一部分,能夠實作重試、逾時、斷路、客戶端負載平衡、服務發現、安全性和指標收集等網路關注點,而不需要任何明確的語言或框架依賴。Envoy 在應用程式之外實作所有這些功能。
Envoy 的強大之處不僅限於這些應用層彈性方面。Envoy 還捕捉許多應用程式網路指標,如每秒請求數、失敗數、斷路事件等。透過使用 Envoy,我們可以自動獲得服務之間發生的情況的可見性,這正是我們開始看到許多意外複雜性的地方。
我們可以在應用程式旁邊佈署服務代理,以獲得這些功能(彈性和可觀測性),這些功能在應用程式之外,但具有非常特定於應用程式的精確度。在這種模型中,希望與系統其餘部分通訊的應用程式首先將其請求傳遞給 Envoy,然後 Envoy 處理與上游的通訊。
服務代理還可以收集分散式追蹤跨度,以便我們可以將特定請求所採取的所有步驟拼接在一起。我們可以看到每個步驟花了多長時間,並尋找系統中潛在的瓶頸或錯誤。如果所有應用程式都透過自己的代理與外部世界通訊,並且所有進入應用程式的流量都透過我們的代理,我們就能為應用程式獲得一些重要功能,而無需更改任何應用程式碼。這個代理 + 應用程式組合形成了稱為服務網格的通訊匯流排的基礎。
什麼是服務網格是一種分散式應用程式基礎設施,負責以透明、外部處理方式代表應用程式處理網路流量。服務代理形成資料平面,所有流量都透過它處理和觀察。資料平面負責建立、保護和控制透過網格的流量。資料平面的行為由控制平面設定。控制平面是網格的大腦,為操作者提供 API 來操作網路行為。
服務網格承擔了透過實作重試、逾時和斷路器等功能使服務通訊對故障具有彈性的責任。它還能夠透過處理服務發現、自適應和區域感知負載平衡以及健康檢查等事項來處理不斷發展的基礎設施拓撲。由於所有流量都流經網格,操作者可以明確控制和引導流量。
服務網格的另一個優勢是能夠捕捉有關網路行為的詳細訊號,追蹤請求峰值、延遲、吞吐量、故障等指標。最後,由於服務網格控制著應用程式之間網路通訊的兩端,它可以執行強大的安全性,如具有相互認證的傳輸層加密。
服務網格為服務操作者提供所有這些功能,幾乎不需要或根本不需要應用程式碼更改、依賴或侵入。有些功能需要與應用程式碼進行輕微合作,但我們可以避免大型、複雜的函式庫依賴。使用服務網格,無論你使用什麼應用程式框架或程式語言來構建應用程式,這些功能都會一致與正確地實作,讓服務團隊能夠快速、安全與自信地實作和交付系統變更。
Istio 服務網格介紹
Istio 是由 Google、IBM 和 Lyft 建立的服務網格的開放原始碼實作。它幫助你以透明的方式為服務架構增加彈性和可觀測性。使用 Istio,應用程式不必知道它們是服務網格的一部分:每當它們與外部世界互動時,Istio 都會代表它們處理網路。無論你使用的是微服務、單體應用還是介於兩者之間的任何東西,Istio 都能帶來許多好處。
Istio 的資料平面使用 Envoy 代理,並幫助你設定應用程式,使服務代理(Envoy)的例項與之一起佈署。Istio 的控制平面由幾個元件組成,這些元件為終端使用者/操作者提供 API、為代理提供設定 API、安全設定、策略宣告等。
Istio 最初是為在 Kubernetes 上執行而構建的,但從佈署平台不可知的角度編寫。這意味著你可以在 Kubernetes、OpenShift 甚至傳統佈署環境(如虛擬機器)等佈署平台上使用根據 Istio 的服務網格。
Istio 與企業服務匯流排的關係
SOA 時代的企業服務匯流排(ESB)在精神上與服務網格有一些相似之處。如果我們看 ESB 在 SOA 早期的描述方式,我們甚至會看到一些類別似的語言:
企業服務匯流排(ESB)是 SOA 邏輯架構中的無聲夥伴。它在架構中的存在對 SOA 應用程式的服務是透明的。然而,ESB 的存在對於簡化呼叫服務的任務至關重要——使服務在需要的地方使用,而不依賴於定位這些服務和透過網路傳輸服務請求以呼叫這些服務的細節。
在這個 ESB 描述中,我們看到它應該是一個無聲的夥伴,這意味著應用程式不應該知道它。對於服務網格,我們期望類別似的行為。服務網格應該對應用程式透明。ESB 也「對於簡化呼叫服務的任務至關重要」。對於 ESB,這包括協定調解、訊息轉換和根據內容的路由。服務網格不負責 ESB 做的所有事情,但它確實透過重試、逾時和斷路提供請求彈性,並提供服務發現和負載平衡等服務。
總體而言,服務網格和 ESB 之間有幾個顯著差異:
- ESB 在組織中引入了一個新的孤島,作為企業內服務整合的守門人。
- 它是一個非常集中的佈署/實作。
- 它混合了應用程式網路和服務調解關注點。
- 它通常根據複雜的專有供應商軟體。
Istio 與 API 閘道器的關係
Istio 和服務網格技術與 API 閘道器也有一些相似之處和差異。API 閘道器基礎設施用於 API 管理套件中,為組織的公共 API 提供導向公眾的端點。它的角色是為這些公共 API 提供安全性、速率限制、配額管理和指標收集,並且整體 API 管理解決方案繫結,該解決方案包括 API 計劃規範、使用者註冊、計費和其他操作關注點。
在服務網格中,代理與服務共存,不需要額外的跳轉。它們也是去中心化的,因此每個應用程式都可以為其特定工作負載設定其代理,而不受嘈雜鄰居場景的影響。由於每個代理都與其相應的應用程式例項一起存在,它可以在應用程式不知道或不主動參與的情況下保護端對端的傳輸機制。
Istio 在分散式架構中的位置
你應該根據你面臨的問題和需要的功能來選擇實作中使用的技術。像 Istio 這樣的技術,以及服務網格一般,是強大的基礎設施功能,涉及分散式架構的許多領域——但它們並不適合也不應該考慮用於你可能遇到的每個問題。
理想的雲架構會將不同的關注點從實作的每一層分離出來:
- 應用層:內容轉換、呼叫順序和協調、拆分/聚合、內容路由
- 服務網格層:網路彈性、相互 TLS、網路遙測收集、負載平衡、服務發現
- 佈署平台層:例項放置、擴充套件/自動擴充套件、資源使用、作業排程、健康
Istio 在架構的較低層是你的佈署自動化基礎設施。這負責將程式碼佈署到你的平台(容器、Kubernetes、公共雲、VM 等)。Istio 不侵犯或規定你應該使用什麼佈署自動化工具。
在更高層次上,你有應用程式業務邏輯:業務必須編寫的差異化程式碼以保持競爭力。這些程式碼包括業務領域以及知道要呼叫哪些服務以及以什麼順序呼叫、如何處理服務互動回應(例如何將它們聚合在一起)以及在出現流程故障時該怎麼做。Istio 不實作或替換任何業務邏輯。它不進行服務協調、業務負載轉換、負載豐富、拆分/聚合或規則計算。這些功能最好留給應用程式內的函式庫和框架。
Istio 扮演著佈署平台和應用程式碼之間的連線組織的角色。它的角色是促進將複雜的網路程式碼從應用程式中取出。它可以根據作為請求一部分的外部中繼資料(HTTP 標頭等)進行根據內容的路由。它可以根據服務和請求中繼資料比對進行精細的流量控制和路由。它還可以保護傳輸並解除安裝安全令牌驗證,並執行由服務操作者定義的配額和使用策略。
第一步:在 Kubernetes 上佈署 Istio
讓我們使用 Kubernetes 容器平台佈署 Istio 和我們的範例應用程式。Kubernetes 是一個非常強大的容器平台,能夠在一組稱為 Kubernetes 節點的主機器上排程和協調容器。這些節點是能夠執行容器的主機器,但 Kubernetes 處理這些機制。
安裝 Istio
首先,我們需要存取 Kubernetes 發行版。在本文中,我們使用 Docker Desktop,它在你的主機電腦上提供了一個能夠執行 Docker 和 Kubernetes 的精簡 VM。
接下來,我們要將 Istio 安裝到我們的 Kubernetes 發行版中。我們使用 istioctl
命令列工具來安裝 Istio。為此,從 Istio 發布頁面下載 Istio 發行版,並選擇適合你作業系統的版本。
下載發行版後,將壓縮檔案解壓到一個目錄中。從那裡,你可以探索發行版的內容,包括範例、安裝資源和適用於你的作業系統的二進位命令列介面。
讓我們使用 istioctl
CLI 工具執行演示安裝:
istioctl install --set profile=demo -y
執行此命令後,你可能需要等待幾分鐘,讓 Docker 映像正確下載並佈署成功。一旦一切就緒,你可以執行 kubectl 命令列出 istio-system 名稱空間中的所有 Pod。
瞭解 Istio 控制平面
Istio 的控制平面責任在 istiod 元件中實作。istiod(有時稱為 Istio Pilot)負責將使用者/操作者指定的高階 Istio 設定轉換為每個資料平面服務代理的特定設定。
例如,透過設定資源,我們可以指定如何允許流量進入叢集,如何將其路由到服務的特定版本,如何在進行新佈署時轉移流量,以及服務呼叫者應如何處理逾時、重試和斷路等彈性方面。istiod 接受這些設定,解釋它們,並將它們作為特定於服務代理的設定公開。
Istio 的另一個核心功能是能夠為每個工作負載例項分配身份,並加密服務之間呼叫的傳輸,因為它位於請求路徑的兩端(發起和終止)。為此,Istio 使用 X.509 證書來加密流量。工作負載身份嵌入在這些證書中,遵循 SPIFFE 規範。這使 Istio 能夠提供強大的相互認證(mTLS),而應用程式不需要了解證書、公鑰/私鑰等。
入口和出口閘道器
為了讓我們的應用程式和服務提供有意義的功能,它們需要與叢集外的應用程式互動。這些可能是現有的單體應用程式、現成的軟體、訊息佇列、資料函式庫和第三方合作夥伴系統。為此,操作者需要設定 Istio 以允許流量進入叢集,並非常具體地説明允許哪些流量離開叢集。
提供此功能的 Istio 元件是 istio-ingressgateway 和 istio-egressgateway。這些元件實際上是能夠理解 Istio 設定的 Envoy 代理。雖然它們在技術上不是控制平面的一部分,但它們在任何實際使用服務網格的情況下都是不可或缺的。
在服務網格中佈署你的第一個應用程式
讓我們佈署一個由 Web 應用和目錄服務組成的範例應用程式。首先,我們在 Kubernetes 中建立一個名稱空間,用於佈署我們的服務:
kubectl create namespace istioinaction
kubectl config set-context $(kubectl config current-context) --namespace=istioinaction
接下來,我們標記 istioinaction 名稱空間以啟用自動注入:
kubectl label namespace istioinaction istio-injection=enabled
現在讓我們建立目錄佈署:
kubectl apply -f services/catalog/kubernetes/catalog.yaml
如果我們詢問 Kubernetes 佈署了哪些 Pod,我們會看到類別似這樣的內容:
NAME READY STATUS RESTARTS AGE
catalog-7c96f7cc66-flm8g 2/2 Running 0 1m
請注意 Ready 列中的 2/2:這意味著 Pod 中有兩個容器,兩個都處於 Ready 狀態。其中一個容器是應用程式容器,在這種情況下是 catalog。另一個容器是 istio-proxy 邊車。
接下來,我們佈署 webapp 服務,它聚合來自其他服務的資料,並在瀏覽器中以視覺方式顯示:
kubectl apply -f services/webapp/kubernetes/webapp.yaml
最後,我們使用 Istio 入口閘道器來公開我們的 webapp 服務:
kubectl apply -f ch2/ingress-gateway.yaml
探索 Istio 的強大功能:彈性、可觀測性和流量控制
Istio 可觀測性
由於 Istio 服務代理位於連線的兩端(每個服務都有自己的服務代理),Istio 可以收集大量關於應用程式之間發生的情況的遙測和洞察。Istio 的服務代理作為邊車與每個應用程式一起佈署,因此它收集的洞察來自應用程式的「外部處理」。在大多數情況下,這意味著應用程式不需要特定於函式庫或框架的實作來實作這種級別的可觀測性。
Istio 為兩大類別可觀測性建立遙測。第一個是頂線指標,或者説是每秒請求數、故障數和尾部延遲百分位數等。瞭解這些值可以提供對系統中問題開始出現的位置的很好洞察。其次,Istio 可以促進分散式追蹤,如 OpenTracing.io。Istio 可以將跨度傳送到分散式追蹤後端,而應用程式不必擔心。這樣,我們可以深入瞭解特定服務互動期間發生的情況,檢視延遲發生的位置,並取得有關整體呼叫延遲的訊息。
頂級指標
讓我們首先看我們可以開箱即用的一些 Istio 可觀測性功能。在前面的部分中,我們增加了兩個 Kubernetes 佈署,並為它們注入了 Istio 邊車代理。然後我們增加了一個 Istio 入口閘道器,以便我們可以從叢集外部存取我們的服務。為了取得指標,我們將使用 Prometheus 和 Grafana。
Istio 預設附帶一些我們之前安裝的範例附加元件或支援元件。如前面部分所述,這些來自 Istio 安裝的元件僅用於演示目的。對於生產設定,你應該按照各自的檔案安裝每個支援元件。
讓我們使用 istioctl 將 Grafana 轉發到我們的本地機器,以便我們可以檢視儀錶板:
istioctl dashboard grafana
Istio 有一套開箱即用的儀錶板,提供有關在 Istio 中執行的服務的一些基本詳細訊息。使用這些儀錶板,我們可以檢視我們安裝並在網格中執行的服務以及一些 Istio 控制平面元件。
使用開放追蹤的分散式追蹤
我們可以使用 Istio 來處理大部分繁重的工作,以便開箱即用地獲得分散式追蹤。Istio 安裝附帶的附加元件之一是 Jaeger 追蹤儀錶板,我們可以這樣開啟它:
istioctl dashboard jaeger
Istio 彈性
正如我們所討論的,透過網路通訊以幫助完成其業務邏輯的應用程式必須意識到並考慮分散式計算的謬誤:它們需要處理網路不可預測性。在過去,我們嘗試透過在應用程式中執行重試、逾時、斷路等操作來包含大量這種網路變通程式碼。Istio 可以讓我們避免將這種網路程式碼直接寫入應用程式,並為服務網格中的所有應用程式提供一致的預設彈性期望。
這種彈性方面之一是在間歇性/暫時性網路錯誤中重試請求。例如,如果網路出現故障,我們的應用程式可能會看到這些錯誤,並透過重試請求繼續。
使用 Istio VirtualService,我們可以指定關於與網格中的服務互動的規則。以下是 catalogVirtualService 定義的範例:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: catalog
spec:
hosts:
- catalog
http:
- route:
- destination:
host: catalog
retries:
attempts: 3
perTryTimeout: 2s
使用這個定義,我們指定對目錄服務的請求有資格重試最多三次,每次嘗試的超時為兩秒。如果我們實施這個規則,我們可以使用 Istio 在遇到故障時自動重試。
Istio 流量路由
我們將在本文中探討的最後一個 Istio 功能是能夠對服務網格中的請求進行非常精細的控制,無論它們在呼叫圖中有多深。
假設我們想要為目錄服務增加一些新功能。在這個例子中,我們將在負載中增加一個標誌,以指示特定目錄專案是否有可用的影像。我們希望向能夠處理這種變化的終端呼叫者公開這些訊息。
V1 版本的目錄服務在其回應中具有以下屬性:
{
"id": 1,
"color": "amber",
"department": "Eyewear",
"name": "Elinor Glasses",
"price": "282.00"
}
對於 V2 版本的目錄,我們增加了一個名為 imageUrl 的新屬性:
{
"id": 1,
"color": "amber",
"department": "Eyewear",
"name": "Elinor Glasses",
"price": "282.00",
"imageUrl": "http://lorempixel.com/640/480"
}
原則上,我們希望佈署目錄的新版本,但我們也希望精細控制向誰公開它(發布)。能夠以減少在生產中破壞事物的機會並讓付費客戶處於我們冒險行為的前沿的方式將佈署與發布分開是很重要的。
使用 Istio,我們可以精細控制哪些流量進入我們服務的 V1,哪些請求進入 V2。我們使用 Istio 的 DestinationRule 概念按版本分割我們的服務:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: catalog
spec:
host: catalog
subsets:
- name: version-v1
labels:
version: v1
- name: version-v2
labels:
version: v2
使用這個 DestinationRule,我們表示目錄服務的兩個不同版本。我們根據 Kubernetes 中佈署的標籤指定組。任何標記為 version: v2 的 Kubernetes Pod 都屬於 Istio 知道的目錄服務的 v2 組。
接下來,我們可以建立一個規則,説明將所有流量路由到目錄的 v1:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: catalog
spec:
hosts:
- catalog
http:
- route:
- destination:
host: catalog
subset: version-v1
我們還可以根據請求標頭進行更精細的控制:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: catalog
spec:
hosts:
- catalog
http:
- match:
- headers:
x-dark-launch:
exact: "v2"
route:
- destination:
host: catalog
subset: version-v2
- route:
- destination:
host: catalog
subset: version-v1
使用這個設定,當我們在呼叫中包含 x-dark-launch: v2
標頭時,我們會看到來自 catalog-v2 服務的回應;所有其他流量都進入 catalog-v1。在這裡,我們使用 Istio 根據個別請求精細控制對服務的流量。
Istio 的資料平面:Envoy 代理
Envoy 是一個代理,所以在我們繼續之前,我們應該非常清楚什麼是代理。代理是網路架構中的中間元件,位於客戶端和伺服器之間的通訊中間。位於中間使其能夠提供額外的功能,如安全性、隱私和策略。
Envoy 代理是一個特定的應用層代理,我們可以將其插入到應用程式的請求路徑中,以提供服務發現、負載平衡和健康檢查等功能。Envoy 可以理解應用程式在與其他服務通訊時可能使用的第 7 層協定。例如,開箱即用,Envoy 理解 HTTP 1.1、HTTP 2、gRPC 和其他協定,並可以增加請求級別超時、重試、每次重試超時、斷路和其他彈性功能等行為。
Envoy 的核心功能
Envoy 有許多對服務間通訊有用的功能。為了幫助理解這些功能和能力,你應該在高層次上熟悉以下 Envoy 概念:
- 監聽器:向外部世界公開一個應用程式可以連線的連線埠。例如,連線埠 80 上的監聽器接受流量並對該流量應用任何設定的行為。
- 路由:關於如何處理進入監聽器的流量的路由規則。例如,如果請求進來並比對 /catalog,將該流量引導到目錄叢集。
- 叢集:Envoy 可以路由流量的特定上游服務。例如,catalog-v1 和 catalog-v2 可以是單獨的叢集,路由可以指定關於如何將流量引導到目錄服務的 v1 或 v2 的規則。
Envoy 實作了幾種高階負載平衡演算法,應用程式可以利用這些演算法。Envoy 的負載平衡演算法的一個更有趣的功能是區域感知負載平衡。在這種情況下,Envoy 足夠聰明,除非滿足某些標準並提供更好的流量平衡,否則保持流量不跨越任何區域邊界。
Envoy 還支援根據百分比的流量分割/轉移。這使敏捷團隊能夠使用降低風險的持續交付技術,如金絲雀發布。雖然它們將風險降低到較小的使用者池,但金絲雀發布仍然處理實時使用者流量。
Envoy 還可以製作流量的副本,並以發射後忘記模式將該流量影射到 Envoy 叢集。你可以將這種影射能力視為類別似於流量分割,但上游叢集看到的請求是實時流量的副本;因此,我們可以將影射流量路由到服務的新版本,而不會真正影響實時生產流量。這對於使用生產流量測試服務更改而不影響客戶是一個非常強大的功能。
Envoy 與 Istio 的配合
Envoy 為我們在前面章節中介紹的大多數 Istio 功能提供了大部分繁重的工作。Istio 使用 Envoy 作為其資料平面,並使用 Envoy 的動態設定功能。這允許 Istio 管理大量 Envoy 代理,每個代理都有自己的潛在複雜設定。
在雲環境中執行微服務涉及許多挑戰:網路不可靠性、服務可用性、難以理解的流量流、流量加密、應用程式健康和效能等。
這些困難透過在每個應用程式中使用函式庫實作的模式(如服務發現、客戶端負載平衡和重試)得到緩解。需要額外的函式庫和服務來建立和分發指標和追蹤,以獲得對服務的可觀測性。
服務網格是一種基礎設施,代表應用程式以透明、外部處理方式實作這些跨領域關注點。Istio 是服務網格的一種實作,由以下部分組成:
- 資料平面,由與應用程式一起佈署的服務代理組成,透過實作策略、管理流量、生成指標和追蹤等來補充應用程式。
- 控制平面,為操作者提供 API 來操作資料平面的網路行為。
Istio 使用 Envoy 作為其服務代理,因為它的多功能性和可以動態設定的能力。
透過 Istio,我們可以解決微服務架構中的許多挑戰,包括服務發現、負載平衡、彈性、可觀測性和安全性,而無需更改應用程式碼。這使開發團隊能夠專注於業務邏輯,而將這些跨領域關注點委託給基礎設施。
Istio 的 Envoy 代理與閘道器
Envoy 代理是一個強大的工具,能夠協助應用程式處理應用層級的行為。作為 Istio 的資料平面,Envoy 能夠一致與正確地解決雲端可靠性挑戰,包括網路故障、拓撲變化和彈性問題。
Envoy 使用動態 API 進行執行時控制,這正是 Istio 所利用的功能。它還能夠揭露許多關於應用程式使用情況和代理內部運作的強大指標與資訊。
Envoy 的功能與支援基礎設施
雖然 Envoy 作為代理非常適合服務網格的使用場景,但要充分發揮其價值,它需要支援基礎設施或元件。這些支援元件提供使用者設定、安全策略和執行時設定,形成控制平面。Istio 的 istiod 控制平面元件實作了 xDS API,用於動態設定服務代理。
Istio 抽象了服務登入檔,並提供 Envoy 的 xDS API 實作。當 Istio 佈署在 Kubernetes 上時,它使用 Kubernetes 的服務登入檔進行服務發現,而 Envoy 代理完全不需要了解這些實作細節。
Envoy 能夠產生大量指標和遙測資料,Istio 會設定資料平面將這些資料傳送到像 Prometheus 這樣的時間序列系統。Envoy 還可以將分散式追蹤資料傳送到 OpenTracing 引擎,Istio 可以設定 Envoy 將這些資料傳送到適當的位置,例如 Jaeger 或 Zipkin。
此外,Envoy 可以終止和發起 TLS 流量到網格中的服務。為此,我們需要支援基礎設施來建立、簽署和輪換證書。Istio 透過 istiod 元件提供這些功能。
總結來説,Istio 的元件和 Envoy 代理共同構成了一個強大的服務網格實作。兩者都擁有蓬勃發展的社群,並針對下一代服務架構進行了最佳化。
Istio 閘道器:將流量引入叢集
流量入口概念
網路社群使用「入口點」(ingress points) 這個術語來描述透過明確建立的入口點連線網路。入口指的是源自網路外部並打算到達網路內部端點的流量首先被路由到一個入口點,該入口點作為進入本地網路的流量的守門員。
虛擬 IP:簡化服務存取
當我們想要將網域名稱對映到服務時,直接對映到單一例項或端點(單一 IP)的方法可能非常脆弱。如果該特定服務例項出現故障,客戶端將看到許多錯誤,直到我們將 DNS 對映更改為具有正常工作端點的新 IP 地址。
更好的方法是將網域名稱對映到代表我們服務的虛擬 IP 地址,並將流量轉發到我們的實際服務例項。虛擬 IP 繫結到一種稱為反向代理的入口點。反向代理負責將請求分發到後端服務,並不對應於任何特定服務。
虛擬主機:從單一存取點提供多個服務
我們還可以使用單個虛擬 IP 表示多個不同的主機名。例如,我們可以讓 prod.istioinaction.io 和 api.istioinaction.io 都解析到同一個虛擬 IP 地址。這意味著對這兩個主機名的請求都將到達同一個虛擬 IP,因此同一個入口反向代理將路由請求。
在單個入口點託管多個不同服務稱為虛擬主機託管。我們需要一種方法來決定特定請求應該路由到哪個虛擬主機組。使用 HTTP/1.1,我們可以使用 Host 標頭;使用 HTTP/2,我們可以使用 :authority 標頭;使用 TCP 連線,我們可以依賴 TLS 的伺服器名稱指示(SNI)。
Istio 入口閘道器
Istio 有一個入口閘道器的概念,它扮演網路入口點的角色,負責保護和控制從叢集外部發起的流量進入叢集。此外,Istio 的入口閘道器處理負載平衡和虛擬主機路由。
Istio 使用單個 Envoy 代理作為入口閘道器。Envoy 不僅是一個能夠的服務到服務代理,還可以用於負載平衡和將流量從服務網格外部路由到在其內部執行的服務。
指定 Gateway 資源
要在 Istio 中設定入口閘道器,我們使用 Gateway 資源並指定我們希望開放的連線埠以及這些連線埠允許的虛擬主機。
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: coolstore-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "webapp.istioinaction.io"
使用虛擬服務進行閘道器路由
當流量進入閘道器時,我們需要一種方法將其引導到服務網格內的特定服務;為此,我們使用 VirtualService 資源。在 Istio 中,VirtualService 資源定義了客戶端如何透過其完全限定網域名稱與特定服務通訊,哪些版本的服務可用,以及其他路由屬性。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: webapp-vs-from-gw
spec:
hosts:
- "webapp.istioinaction.io"
gateways:
- coolstore-gateway
http:
- route:
- destination:
host: webapp
port:
number: 8080
Istio 入口閘道器與 Kubernetes Ingress 的比較
Istio 確實支援 Kubernetes Ingress v1 資源,但 Kubernetes Ingress v1 規範有顯著的限制:
- Kubernetes Ingress v1 是一個非常簡單的規範,導向 HTTP 工作負載,僅考慮連線埠 80 和連線埠 443 作為入口點。
- Kubernetes Ingress v1 資源嚴重規範不足,沒有通用的方式來指定複雜的流量路由規則。
- 由於規範不足,大多數供應商選擇透過佈署上的特定註解來公開設定,這些註解在供應商之間各不相同與不可移植。
Istio 決定為構建入口模式提供一個全新的方案,特別是將第 4 層(傳輸)和第 5 層(工作階段)屬性與第 7 層(應用程式)路由關注點分開。Istio Gateway 處理 L4 和 L5 關注點,而 VirtualService 處理 L7 關注點。
Istio 入口閘道器與 API 閘道器的比較
API 閘道器允許組織將消費一組服務的客戶端從這些服務的實作細節中抽象出來。API 閘道器需要能夠使用不同的安全挑戰(OpenID Connect、OAuth 2.0、LDAP)識別客戶端,轉換訊息,提供複雜的業務級速率限制,並具有自助註冊或開發者門戶。Istio 的入口閘道器不提供這些開箱即用的功能。
保護閘道器流量
使用 TLS 的 HTTP 流量
為了防止中間人(MITM)攻擊並加密進入服務網格的所有流量,我們可以在 Istio 閘道器上設定 TLS,以便任何傳入流量都透過 HTTPS 提供。
要為入口流量啟用 HTTPS,我們需要指定閘道器應使用的正確私鑰和證書。證書基本上是伺服器的公鑰,已由評價良好的機構(也稱為證書頒發機構,CA)簽名。
首先,我們需要建立包含證書和金鑰的 Kubernetes secret:
kubectl create -n istio-system secret tls webapp-credential \
--key ch4/certs/3_application/private/webapp.istioinaction.io.key.pem \
--cert ch4/certs/3_application/certs/webapp.istioinaction.io.cert.pem
然後,我們可以設定 Istio Gateway 資源以使用這些證書和金鑰:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: coolstore-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "webapp.istioinaction.io"
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: webapp-credential
hosts:
- "webapp.istioinaction.io"
HTTP 重定向到 HTTPS
如果我們想強制所有流量始終使用 TLS,我們可以修改 Gateway 資源以強制 HTTP 流量重定向:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: coolstore-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "webapp.istioinaction.io"
tls:
httpsRedirect: true
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: webapp-credential
hosts:
- "webapp.istioinaction.io"
使用相互 TLS 的 HTTP 流量
在標準 TLS 中,伺服器向客戶端傳送其公共證書,客戶端驗證其信任簽署伺服器證書的 CA。使用相互 TLS (mTLS),客戶端也傳送其公共證書,伺服器驗證其信任該證書。
要設定 istio-ingressgateway
使用視覺化工具掌握 Istio 服務網格行為
在前一篇文章中,我們建立了 Istio 可觀察性的基礎,探討瞭如何從服務網格中收集和聚合指標。本文將進一步深入,介紹如何運用視覺化工具來解讀這些資料,以便更好地理解服務網格中的行為模式和問題。
服務網格的複雜性使得純粹依靠原始資料來診斷問題變得困難。透過視覺化工具,我們可以將抽象的資料轉化為直觀的圖表和關係圖,讓問題診斷和效能最佳化變得更加高效。
Grafana:視覺化 Istio 服務和控制平面指標
設定 Grafana 環境
在我們的環境中,我們使用了 kube-prometheus 作為觀察工具集,而不是 Istio 自帶的簡單版本。這提供了更完整的監控能力。首先,讓我們確認 kube-prometheus 已正確安裝:
kubectl get po -n prometheus
你應該能看到類別似以下的輸出,包含 Grafana 的 Pod:
NAME READY STATUS AGE
prom-grafana-5ff645dfcc-qp57d 2/2 Running 21s
prom-kube-prometheus-stack-operator-5498b9f476-j6hjc 1/1 Running 21s
prometheus-prom-kube-prometheus-stack-prometheus-0 2/2 Running 17s
接下來,我們需要將 Grafana 服務轉發到本地,以便存取其介面:
kubectl -n prometheus port-forward svc/prom-grafana 3000:80
使用以下憑證登入 Grafana:
- 使用者名:admin
- 密碼:prom-operator
匯入 Istio 的 Grafana 儀錶板
Istio 提供了一系列預設設定的 Grafana 儀錶板,這些儀錶板是理解服務網格行為的絕佳起點。雖然這些儀錶板不再是官方發行版的一部分,但我們可以手動匯入它們:
cd ch8/
kubectl -n prometheus create cm istio-dashboards \
--from-file=pilot-dashboard.json=dashboards/pilot-dashboard.json \
--from-file=istio-workload-dashboard.json=dashboards/istio-workload-dashboard.json \
--from-file=istio-service-dashboard.json=dashboards/istio-service-dashboard.json \
--from-file=istio-performance-dashboard.json=dashboards/istio-performance-dashboard.json \
--from-file=istio-mesh-dashboard.json=dashboards/istio-mesh-dashboard.json \
--from-file=istio-extension-dashboard.json=dashboards/istio-extension-dashboard.json
建立完 ConfigMap 後,我們需要為其增加標籤,使 Grafana 能夠識別:
kubectl label -n prometheus cm istio-dashboards grafana_dashboard=1
等待片刻後,點選 Grafana 介面左上角的 Home 選項,你應該能看到可用的 Istio 儀錶板列表。
檢視控制平面指標
點選「Istio Control Plane Dashboard」可以檢視控制平面的指標圖表。這些圖表展示了 CPU、記憶體使用情況、goroutines 數量以及控制平面錯誤、設定同步問題和活躍的資料平面連線等關鍵訊息。
控制平面儀錶板的一個重要指標是「Pilot Push Time」,它顯示了 pilot_proxy_convergence_time
指標,用於測量將變更分發到代理所需的時間。這是評估控制平面效能的關鍵指標。
檢視資料平面指標
要檢視特定服務的資料平面指標,可以點選「Istio Service Dashboard」,然後選擇特定服務,如 webapp.istioinaction
。這些圖表顯示了服務的請求量、延遲、錯誤率等關鍵指標。
這些儀錶板使用 Istio 標準指標填充,你可以根據需要調整它們或增加新的圖表。如果需要啟用自定義指標或特定的 Envoy 指標,可以參考前一篇文章中的相關內容。