Istio 提供強大的流量管理能力,讓開發者得以精細控制服務間的通訊。本文從設定 Gateway 開始,逐步引導讀者理解 Istio 的核心概念。透過建立 Gateway 資源,我們可以將外部流量匯入 Kubernetes 叢集。然而,單純的 Gateway 並不足以處理複雜的路由需求,因此需要搭配 VirtualService 進行更精確的流量導向。VirtualService 允許開發者定義服務的存取方式和路由規則,例如根據主機名稱或路徑將流量導向不同的服務版本。此外,ServiceEntry 則能將外部服務納入 Istio 的管理範圍,讓開發者得以應用流量管理、故障注入等功能於外部服務。
使用 Istio Gateway 管理流量
在設定好 GATEWAY 變數後,您可以嘗試存取它,但連線將被拒絕:
$ curl -v $GATEWAY
* Trying 10.99.132.130...
* TCP_NODELAY set
* Connection failed
* connect to 10.99.132.130 port 80 failed: Connection refused
* Failed to connect to 10.99.132.130 port 80: Connection refused
* Closing connection 0
curl: (7) Failed to connect to 10.99.132.130 port 80: Connection refused
這是因為 ingress gateway 需要一個 Gateway 資源來知道如何路由請求。Ingress 和 Gateway 資源在服務網格的邊緣運作,用於啟用進入叢集的流量。
建立 Istio Gateway 資源
以下是一個最小的 Istio Gateway 資源範例:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- '*'
這個範例建立了一個 Istio Gateway 資源,選擇器為 istio: ingressgateway。在 Istio 安裝過程中,會建立一個帶有 istio=ingressgateway 標籤的 istio-ingressgateway pod,而具有匹配選擇器 istio=ingressgateway 的 Gateway 資源會將路由組態新增到 istio-ingressgateway pod 中。
程式碼解密:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- '*'
apiVersion和kind定義了資源的 API 版本和型別。metadata部分定義了資源的名稱。spec部分定義了資源的規格,包括選擇器和伺服器組態。selector指定了 Gateway 資源要關聯的 ingress gateway pod。servers部分定義了要代理的請求的主機和埠。
使用真實網域名稱
在真實世界中,hosts 欄位會被設定為實際的網域名稱(例如 www.example.com),叢集服務將透過該網域名稱被存取。* 只應在測試和本地場景中使用,而不應在生產環境中使用。
佈署 Gateway 資源
讓我們將自己的 Gateway 資源佈署到預設名稱空間:
cat <<EOF | kubectl create -f -
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- '*'
EOF
處理請求
現在,讓我們嘗試向 $GATEWAY 端點傳送請求:
$ curl -v $GATEWAY
* Trying 10.99.132.130...
* TCP_NODELAY set
* Connected to 10.99.132.130 (10.99.132.130) port 80 (#0)
> GET / HTTP/1.1
> Host: 10.99.132.130
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< date: Fri, 09 Oct 2020 21:50:08 GMT
< server: istio-envoy
< content-length: 0
<
* Connection #0 to host 10.99.132.130 left intact
* Closing connection 0
這次,我們收到了 HTTP 404 回應。請求到達了 ingress gateway,但 gateway 不知道如何路由請求。
檢視 Istio Ingress Gateway Pod 日誌
讓我們檢視 Istio ingress gateway pod 的日誌,以檢視傳入的請求:
$ kubectl get pod --selector="istio=ingressgateway" --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
istio-system istio-ingressgateway-7bd5586b79-nzbm8 1/1 Running 0 11m
$ kubectl logs istio-ingressgateway-7bd5586b79-nzbm8 -n istio-system
...
[2020-10-09T21:50:08.971Z] "GET / HTTP/1.1" 404 - "-" "-" 0 0 0 - "192.168.99.1" "curl/7.64.1" "697452d4-08c9-9370-a3c2-2cbca13b34c5" "10.99.132.130" "-" - - 172.17.0.5:8080 192.168.99.1:58015 - default
....
這告訴我們,傳入的流量確實到達了 ingress gateway。
Virtual Services
由於我們將在書中大量討論服務,讓我們先對術語做一個快速說明。單詞“service”有多個不同的含義,取決於上下文。在本文中,當提到 Kubernetes Service 資源時,我將使用“Kubernetes service”,而當提到 Istio Virtual Service 資源時,我將使用“Virtual service”。
Istio 的 Virtual Service 資源用於組態請求在網格內的路由方式。Virtual Service 是本文中將大量使用的資源之一。
Virtual Service 範例
以下是一個 Istio Virtual Service 資源範例:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloweb
spec:
hosts:
- 'helloweb.dev'
gateways:
- gateway
http:
- route:
- destination:
host: helloweb.default.svc.cluster.local
port:
number: 3000
在 Virtual Service 中,hosts 是客戶端嘗試連線到服務時使用的地址。在我們的例子中,我們將使用 helloweb.dev 作為主機。使用實際的主機名而不是星號(*)將允許我們同時佈署和存取多個服務透過 gateway。
程式碼解密:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloweb
spec:
hosts:
- 'helloweb.dev'
gateways:
- gateway
http:
- route:
- destination:
host: helloweb.default.svc.cluster.local
port:
number: 3000
hosts定義了客戶端存取服務時使用的主機名。gateways指定了允許流量透過的 Gateway 資源名稱。http部分定義了 HTTP 請求的路由規則。route部分指定了請求的目的地,包括主機和埠。
Istio 流量管理深度解析
在 Kubernetes 環境中,Istio 提供了一套完整的流量管理機制,讓開發者能夠精確控制服務間的通訊。流量管理的核心在於如何有效地引導和管理服務間的流量,以確保系統的穩定性和可擴充套件性。
虛擬服務(VirtualService)組態詳解
虛擬服務是 Istio 流量管理的關鍵資源之一,它允許開發者定義服務的存取方式以及流量的路由規則。虛擬服務的主要功能包括:
- 定義服務的主機名稱和閘道器
- 組態 HTTP 流量的路由規則
- 支援多個目的地(destination)的設定
虛擬服務範例
以下是一個基本的虛擬服務組態範例,它將流量路由到 helloweb.default.svc.cluster.local 服務的 3000 連線埠:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloweb
spec:
hosts:
- 'helloweb.dev'
gateways:
- gateway
http:
- route:
- destination:
host: helloweb.default.svc.cluster.local
port:
number: 3000
#### 內容解密:
hosts欄位指定了虛擬服務的主機名稱,在此例中為helloweb.dev。gateways欄位指定了虛擬服務所使用的閘道器,在此例中為gateway。http.route.destination欄位定義了流量的路由規則,將流量導向helloweb.default.svc.cluster.local服務的 3000 連線埠。
服務條目(ServiceEntry)組態詳解
服務條目允許開發者將外部服務納入 Istio 的服務網格中,從而能夠對外部服務應用流量管理、故障注入等功能。
服務條目範例
以下是一個服務條目的組態範例,它將 api.themoviedb.org 納入服務網格:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: themoviedb-api
spec:
hosts:
- api.themoviedb.org
ports:
- number: 443
name: https
protocol: HTTPS
resolution: DNS
location: MESH_EXTERNAL
#### 內容解密:
hosts欄位指定了外部服務的主機名稱,在此例中為api.themoviedb.org。ports欄位定義了外部服務的連線埠和協定,在此例中使用 HTTPS 協定連線至 443 連線埠。resolution欄位指定了解析外部服務 IP 的方式,在此例中使用 DNS 解析。location欄位指定了外部服務的位置,在此例中為MESH_EXTERNAL,表示該服務位於服務網格之外。
電影網站範例佈署與驗證
本文將透過佈署一個電影網站範例來說明如何使用 Istio 管理外部服務的存取。首先,需要在 themoviedb.org 取得 API 金鑰。然後,使用以下 YAML 檔案佈署電影網站:
apiVersion: apps/v1
kind: Deployment
metadata:
name: movieweb
spec:
replicas: 3
selector:
matchLabels:
app: movieweb
template:
metadata:
labels:
app: movieweb
spec:
containers:
- name: movieweb
image: learnistio/movie-web:1.0.0
env:
- name: THEMOVIEDB_API_KEY
value: '<API_KEY_HERE>'
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: movieweb
spec:
selector:
app: movieweb
ports:
- port: 3000
name: http
#### 內容解密:
- 此 YAML 檔案定義了一個名為
movieweb的 Deployment 和 Service。 THEMOVIEDB_API_KEY環境變數需替換為實際的 API 金鑰。
接著,佈署虛擬服務和服務條目以組態流量路由和外部服務存取:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: movieweb
spec:
hosts:
- '*'
gateways:
- gateway
http:
- route:
- destination:
host: movieweb.default.svc.cluster.local
port:
number: 3000
---
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: themoviedb-api
spec:
hosts:
- api.themoviedb.org
ports:
- number: 443
name: https
protocol: HTTPS
resolution: DNS
location: MESH_EXTERNAL
#### 內容解密:
- 虛擬服務組態將所有到達
gateway的流量路由到moviewebService。 - 服務條目組態允許
moviewebService 存取外部的api.themoviedb.org。
完成佈署後,可以透過瀏覽器或 curl 命令存取電影網站,驗證 Istio 的流量管理和外部服務存取功能。
服務流量管理:基礎流量分割技術解析
在前面的章節中,我們主要關注單一版本的服務佈署,並介紹瞭如何允許外部請求進入叢集,以及如何使用服務入口資源讓服務網格能夠存取外部服務和API。然而,在大多數實際案例中,叢集內通常會有多個服務同時執行並相互通訊。這些服務可能會以不同的速度進行演進,導致出現多個不同版本的服務。在這種情況下,如何安全地發布新版本的服務,並確保其與現有版本具有相同的穩定性和功能性,成為了一個重要的課題。
流量分割技術的應用場景
流量分割技術可以幫助我們解決上述問題。本文將示範如何佈署新版本的服務,並透過逐步釋放新版本到生產環境的過程,同時將風險降至最低。
為了示範流量分割,我們將使用前面介紹的 Hello Web 和 Greeter 服務的兩個不同版本。
透過權重進行流量分割
Istio允許我們透過為每個服務版本分配權重來路由請求。這些權重代表了應該被路由到特定服務版本的輸入請求的百分比。
目前,服務之間的流量流動如圖3.4所示。流量從網際網路進入負載平衡器和閘道器,然後到達helloweb Kubernetes服務。helloweb Kubernetes服務再將流量負載平衡到所有標有app: helloweb標籤的Pod上。在Hello web Pod內,我們透過DNS名稱(http://greeter-service.default.svc.cluster.local:3000)呼叫Greeter服務。這個DNS名稱是在Kubernetes服務佈署時自動建立的。然後,Kubernetes服務會將流量負載平衡到所有標有app: greeter-service標籤的Pod上。
佈署多版本服務
要佈署第二個版本的Greeter服務,我們需要:
建立一個全新的Kubernetes佈署,並為其設定
version: v2標籤,以及app: greeter-service標籤。這個佈署使用了一個不同的Docker映像,其中包含了v2版本的服務。由於我們已經佈署了Kubernetes的greeter-service,因此不需要再佈署另一個Kubernetes服務。我們也不應該重新命名服務或佈署不同版本的服務,因為Hello Web依賴於DNS名稱(例如
http://greeter-service:3000)來呼叫它。
greeter-service Kubernetes服務的選擇器定義如下:
selector:
app: greeter-service
這意味著它並不知道greeter服務的版本資訊。如果我們佈署了v2版本的greeter服務並重新載入hello web,我們將會隨機收到來自v1或v2 Pod的回應。
使用Istio進行流量控制
為瞭解決上述問題,我們需要定義多個目的地,以便將請求路由到不同的服務版本。這正是Istio的VirtualService資源可以做到的。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: greeter-service
spec:
hosts:
- greeter-service
http:
- route:
- destination:
host: greeter-service.default.svc.cluster.local
port:
number: 3000
- destination:
host: greeter-service.default.svc.cluster.local
port:
number: 3000
然而,這樣做還不夠,因為我們沒有區分不同的服務版本。為此,我們需要使用Istio的DestinationRule資源。透過這個資源和子集的概念,我們可以根據Kubernetes Pod上的標籤來區分不同的服務版本。
以下是greeter服務的DestinationRule範例:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: greeter-service
spec:
host: greeter-service
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
內容解密:
- apiVersion和kind:指定了Istio的API版本和資源型別(在本例中為DestinationRule)。
- metadata:提供了資源的後設資料,如名稱。
- spec:定義了資源的具體組態。
- host:指定了目標服務的主機名。
- subsets:定義了服務的不同子集,每個子集根據特定的標籤進行區分。
- name:子集的名稱。
- labels:用於區分不同子集的標籤。
透過結合VirtualService和DestinationRule,我們可以實作對不同版本服務的精細流量控制,從而安全地發布新版本的服務。