istio-控制 Ingress 流量 (Gateway VirtualService)
控制 Ingress 流量
到目前為止,Istio提供了一個簡單的API來進行流量管理,該API包括了四種資源:RouteRule,DestinationPolicy,EgressRule和Ingress(直接使用了Kubernets的Ingress資源)。藉助此API,使用者可以輕鬆管理Istio服務網格中的流量。該API允許使用者將請求路由到特定版本的服務,為彈性測試注入延遲和失敗,新增超時和斷路器等等,所有這些功能都不必更改應用程式本身的程式碼。
雖然目前API的功能已被證明是Istio非常引人注目的一部分,但使用者的反饋也表明,這個API確實有一些缺點,尤其是在使用它來管理包含數千個服務的非常大的應用程式,以及使用HTTP以外的協議時。 此外,使用Kubernetes Ingress資源來配置外部流量的方式已被證明不能滿足需求。
為了解決上述缺陷和其他的一些問題,Istio引入了新的流量管理API v1alpha3,新版本的API將完全取代之前的API。 儘管v1alpha3和之前的模型在本質上是基本相同的,但它並不向後相容的,基於舊API的模型需要進行手動轉換。 Istio接下來的幾個版本中會提供一個新舊模型的轉換工具。
為了證明該非相容升級的必要性,v1alpha3 API經歷了漫長而艱苦的社群評估過程,以希望新的API能夠大幅改進,並經得起時間考驗。 在本文中,我們將介紹新的配置模型,並試圖解釋其後面的一些動機和設計原則。
設計原則
路由模型的重構過程中遵循了一些關鍵的設計原則:
- 除支援宣告式(意圖)配置外,也支援顯式指定模型依賴的基礎設施。例如,除了配置入口閘道器(的功能特性)之外,負責實現 入口閘道器功能的元件(Controller)也可以在模型指定。
- 編寫模型時應該“生產者導向”和“以Host為中心”,而不是通過組合多個規則來編寫模型。 例如,所有與特定Host關聯的規則被配置在一起,而不是單獨配置。
- 將路由與路由後行為清晰分開。
v1alpha3中的配置資源
在一個典型的網格中,通常有一個或多個用於終結外部TLS連結,將流量引入網格的負載均衡器(我們稱之為gateway)。 然後流量通過邊車閘道器(sidecar gateway)流經內部服務。 應用程式使用外部服務的情況也很常見(例如訪問Google Maps API),一些情況下,這些外部服務可能被直接呼叫;但在某些部署中,網格中所有訪問外部服務的流量可能被要求強制通過專用的出口閘道器(Egress gateway)。 下圖描繪了閘道器在網格中的使用情況。
考慮到上述因素,v1alpha3引入了以下這些新的配置資源來控制進入網格,網格內部和離開網格的流量路由。
- Gateway
- VirtualService
- DestinationRule
- ServiceEntry
VirtualService,DestinationRule和ServiceEntry分別替換了原API中的RouteRule,DestinationPolicy和EgressRule。 Gateway是一個獨立於平臺的抽象,用於對流入專用中間裝置的流量進行建模。
下圖描述了跨多個配置資源的控制流程。 不同配置資源之間的關係
Gateway
Gateway用於為HTTP / TCP流量配置負載均衡器,並不管該負載均衡器將在哪裡執行。 網格中可以存在任意數量的Gateway,並且多個不同的Gateway實現可以共存。 實際上,通過在配置中指定一組工作負載(Pod)標籤,可以將Gateway配置繫結到特定的工作負載,從而允許使用者通過編寫簡單的Gateway Controller來重用現成的網路裝置。
對於入口流量管理,您可能會問: 為什麼不直接使用Kubernetes Ingress API ? 原因是Ingress API無法表達Istio的路由需求。 Ingress試圖在不同的HTTP代理之間取一個公共的交集,因此只能支援最基本的HTTP路由,最終導致需要將代理的其他高階功能放入到註解(annotation)中,而註解的方式在多個代理之間是不相容的,無法移植。
Istio Gateway 通過將L4-L6配置與L7配置分離的方式克服了Ingress的這些缺點。 Gateway只用於配置L4-L6功能(例如,對外公開的埠,TLS配置),所有主流的L7代理均以統一的方式實現了這些功能。 然後,通過在Gateway上繫結VirtualService的方式,可以使用標準的Istio規則來控制進入Gateway的HTTP和TCP流量。
例如,下面這個簡單的Gateway配置了一個Load Balancer,以允許訪問host bookinfo.com的https外部流量入mesh中:
-
apiVersion: networking.istio.io/v1alpha3
-
kind: Gateway
-
metadata:
-
name: bookinfo-gateway
-
spec:
-
servers:
-
- port:
-
number: 443
-
name: https
-
protocol: HTTPS
-
hosts:
-
- bookinfo.com
-
tls:
-
mode: SIMPLE
-
serverCertificate: /tmp/tls.crt
-
privateKey: /tmp/tls.key
要為進入上面的Gateway的流量配置相應的路由,必須為同一個host定義一個VirtualService(在下一節中描述),並使用配置中的gateways欄位繫結到前面定義的Gateway 上:
-
apiVersion: networking.istio.io/v1alpha3
-
kind: VirtualService
-
metadata:
-
name: bookinfo
-
spec:
-
hosts:
-
- bookinfo.com
-
gateways:
-
- bookinfo-gateway # <---- bind to gateway
-
http:
-
- match:
-
- uri:
-
prefix: /reviews
-
route:
-
...
Gateway可以用於建模邊緣代理或純粹的內部代理,如第一張圖所示。 無論在哪個位置,所有閘道器都可以用相同的方式進行配置和控制。
VirtualService
用一種叫做“Virtual services”的東西代替路由規則可能看起來有點奇怪,但對於它配置的內容而言,這事實上是一個更好的名稱,特別是在重新設計API以解決先前模型的可擴充套件性問題之後。
實際上,發生的變化是:在之前的模型中,需要用一組相互獨立的配置規則來為特定的目的服務設定路由規則,並通過precedence欄位來控制這些規則的順序;在新的API中,則直接對(虛擬)服務進行配置,該虛擬服務的所有規則以一個有序列表的方式配置在對應的VirtualService 資源中。
例如,之前在Bookinfo 應用程式的reviews服務中有兩個RouteRule資源,如下所示:
-
apiVersion: config.istio.io/v1alpha2
-
kind: RouteRule
-
metadata:
-
name: reviews-default
-
spec:
-
destination:
-
name: reviews
-
precedence: 1
-
route:
-
- labels:
-
version: v1
-
---
-
apiVersion: config.istio.io/v1alpha2
-
kind: RouteRule
-
metadata:
-
name: reviews-test-v2
-
spec:
-
destination:
-
name: reviews
-
precedence: 2
-
match:
-
request:
-
headers:
-
cookie:
-
regex: "^(.*?;)?(user=jason)(;.*)?$"
-
route:
-
- labels:
-
version: v2
在v1alph3,可以在單個VirtualService資源中提供相同的配置:
-
apiVersion: networking.istio.io/v1alpha3
-
kind: VirtualService
-
metadata:
-
name: reviews
-
spec:
-
hosts:
-
- reviews
-
http:
-
- match:
-
- headers:
-
cookie:
-
regex: "^(.*?;)?(user=jason)(;.*)?$"
-
route:
-
- destination:
-
host: reviews
-
subset: v2
-
- route:
-
- destination:
-
host: reviews
-
subset: v1
正如你所看到的, 和reviews服務相關的兩個規則集中寫在了一個地方。這個改變乍一看可能覺得並沒有什麼特別的優勢, 然而,如果仔細觀察這個新模型,會發現它和之前的API之間存在著根本的差異,這使得v1alpha3功能更加強大。
首先,請注意VirtualService的目標服務是使用hosts欄位(實際上是重複欄位)指定的,然後再在每個路由的destination欄位中指定。 這是與以前模型的重要區別。
VirtualService描述了一個或多個使用者可定址目標到網格內實際工作負載之間的對映。在上面的示例中,這兩個地址是相同的,但實際上使用者可定址目標可以是任何用於定位服務的,具有可選萬用字元字首或CIDR字首的DNS名稱。 這對於應用從單體架構到微服務架構的遷移過程特別有用,單體應用被拆分為多個獨立的微服務後,採用VirtaulService可以繼續把多個微服務對外暴露為同一個目標地址,而不需要服務消費者進行修改以適應該變化。
例如,以下規則允許服務消費者訪問Bookinfo應用程式的reviews和ratings服務,就好像它們是http://bookinfo.com/(虛擬)服務的一部分:
-
apiVersion: networking.istio.io/v1alpha3
-
kind: VirtualService
-
metadata:
-
name: bookinfo
-
spec:
-
hosts:
-
- bookinfo.com
-
http:
-
- match:
-
- uri:
-
prefix: /reviews
-
route:
-
- destination:
-
host: reviews
-
- match:
-
- uri:
-
prefix: /ratings
-
route:
-
- destination:
-
host: ratings
-
...
實際上在`VirtualService`中hosts部分設定只是虛擬的目的地,因此不一定是已在網格中註冊的服務。這允許使用者為在網格內沒有可路由條目的虛擬主機的流量進行建模。 通過將VirtualService繫結到同一Host的Gateway配置(如前一節所述 ),可向網格外部暴露這些Host。
除了這個重大的重構之外, VirtualService還包括其他一些重要的改變:
- 可以在VirtualService配置中表示多個匹配條件,從而減少對冗餘的規則設定。
- 每個服務版本都有一個名稱(稱為服務子集)。 屬於某個子集的一組Pod/VM在DestinationRule定義,具體定義參見下節。
- 通過使用帶萬用字元字首的DNS來指定VirtualService的host,可以建立單個規則以作用於所有匹配的服務。 例如,在Kubernetes中,在’VirtualService’中使用*.foo.svc.cluster.local作為host,可以對foo名稱空間中的所有服務應用相同的重寫規則。
DestinationRule
DestinationRule配置將流量轉發到服務時應用的策略集。 這些策略應由由服務提供者撰寫,用於描述斷路器,負載均衡設定,TLS設定等。 除了下述改變外,DestinationRule與其前身DestinationPolicy大致相同。
DestinationRule的host可以包含萬用字元字首,以允許單個規則應用於多個服務。
DestinationRule定義了目的host的子集subsets (例如:命名版本)。 這些subset用於`VirtualService`的路由規則設定中,可以將流量導向服務的某些特定版本。 通過這種方式為版本命名後,可以在不同的virtual service中明確地引用這些命名版本的ubset,簡化Istio代理髮出的統計資料,並可以將subsets編碼到SNI頭中。 為reviews服務配置策略和subsets的DestinationRule可能如下所示:
-
apiVersion: networking.istio.io/v1alpha3
-
kind: DestinationRule
-
metadata:
-
name: reviews
-
spec:
-
host: reviews
-
trafficPolicy:
-
loadBalancer:
-
simple: RANDOM
-
subsets:
-
- name: v1
-
labels:
-
version: v1
-
- name: v2
-
labels:
-
version: v2
-
trafficPolicy:
-
loadBalancer:
-
simple: ROUND_ROBIN
-
- name: v3
-
labels:
-
version: v3
注意,與DestinationPolicy不同的是,可在單個DestinationRule中指定多個策略(例如上面例項中的預設策略和v2版本特定的策略)。
ServiceEntry
ServiceEntry用於將附加條目新增到Istio內部維護的服務登錄檔中。 它最常用於對訪問網格外部依賴的流量進行建模,例如訪問Web上的API或遺留基礎設施中的服務。
所有以前使用EgressRule進行配置的內容都可以通過ServiceEntry輕鬆完成。 例如,可以使用類似這樣的配置來允許從網格內部訪問一個簡單的外部服務:
-
apiVersion: networking.istio.io/v1alpha3
-
kind: ServiceEntry
-
metadata:
-
name: foo-ext
-
spec:
-
hosts:
-
- foo.com
-
ports:
-
- number: 80
-
name: http
-
protocol: HTTP
也就是說,ServiceEntry比它的前身具有更多的功能。首先,ServiceEntry不限於外部服務配置,它可以有兩種型別:網格內部或網格外部。網格內部條目只是用於向網格顯式新增服務,新增的服務與其他內部服務一樣。採用網格內部條目,可以把原本未被網格管理的基礎設施也納入到網格中(例如,把虛機中的服務新增到基於Kubernetes的服務網格中)。網格外部條目則代表了網格外部的服務。對於這些外部服務來說,mTLS身份驗證是禁用的,並且策略是在客戶端執行的,而不是在像內部服務請求一樣在伺服器端執行策略。
由於ServiceEntry配置只是將服務新增到網格內部的服務登錄檔中,因此它可以像登錄檔中的任何其他服務一樣,與VirtualService和/或DestinationRule一起使用。例如,以下DestinationRule可用於啟動外部服務的mTLS連線:
-
apiVersion: networking.istio.io/v1alpha3
-
kind: DestinationRule
-
metadata:
-
name: foo-ext
-
spec:
-
name: foo.com
-
trafficPolicy:
-
tls:
-
mode: MUTUAL
-
clientCertificate: /etc/certs/myclientcert.pem
-
privateKey: /etc/certs/client_private_key.pem
-
caCertificates: /etc/certs/rootcacerts.pem
除了擴充套件通用性以外,ServiceEntry還提供了其他一些有關EgressRule改進,其中包括:
- 一個ServiceEntry可以配置多個服務端點,這在之前需要採用多個EgressRules來實現。
- 現在可以配置服務端點的解析模式(NONE,STATIC或DNS)。
- 此外,我們正在努力解決另一個難題:目前需要通過純文字埠訪問安全的外部服務(例如http://google.com:443)。該問題將會在未來幾周內得到解決,屆時將允許從應用程式直接訪問https://google.com。請繼續關注解決此限制的Istio補丁版本(0.8.x)。
建立和刪除v1alpha3路由規則
由於一個特定目的地的所有路由規則現在都儲存在單個VirtualService資源的一個有序列表中,因此為該目的地新增新的規則不需要再建立新的RouteRule,而是通過更新該目的地的VirtualService資源來實現。
舊的路由規則:
$ istioctl create -f my-second-rule-for-destination-abc.yaml
v1alpha3路由規則:
$ istioctl replace -f my-updated-rules-for-destination-abc.yaml
刪除路由規則也使用istioctl replace完成,當然刪除最後一個路由規則除外(刪除最後一個路由規則需要刪除VirtualService)。
在新增或刪除引用服務版本的路由時,需要在該服務相應的DestinationRule更新subsets 。 正如你可能猜到的,這也是使用istioctl replace完成的。
總結
Istio v1alpha3路由API具有比其前身更多的功能,但不幸的是新的API並不向後相容,舊的模型升級需要一次手動轉換。 Istio 0.9以後將不再支援RouteRule,DesintationPolicy和EgressRule這些以前的配置資源 。Kubernetes使用者可以繼續使用Ingress配置邊緣負載均衡器來實現基本的路由。 但是,高階路由功能(例如,跨兩個版本的流量分割)則需要使用Gateway ,這是一種功能更強大,Istio推薦的Ingress替代品。
致謝
感謝以下人員為新版本的路由模型重構和實現工作做出的貢獻(按字母順序)
Frank Budinsky (IBM)
Zack Butcher (Google)
Greg Hanson (IBM)
Costin Manolache (Google)
Martin Ostrowski (Google)
Shriram Rajagopalan (VMware)
Louis Ryan (Google)
Isaiah Snell-Feikema (IBM)
Kuat Yessenov (Google)
原文
Introducing the Istio v1alpha3 routing API
參考:https://istio.io/zh/docs/tasks/traffic-management/ingress/
轉載:https://zhaohuabing.com/2018/06/04/introducing-the-istio-v1alpha3-routing-api/#原文