詳細教程丨如何利用Rancher和Kong實現服務網格?
- 2021 年 6 月 4 日
- 筆記
- Kubernetes
服務網格(Service mesh)是當前新興的架構模式,越來越受到人們的青睞。與Kubernetes一起,服務網格可以形成一個強大的平台,它可以解決在微服務集群或服務基礎設施上發現的高度分散式環境中出現的技術需求。服務網格是一個專門的基礎設施層,用於促進微服務之間的服務到服務通訊。
服務網格解決了基於微服務的應用中典型的通訊需求,包括加密隧道、健康檢查、斷路器、負載均衡以及流量許可。如果離開微服務來解決這些需求,會導致開發過程中產生高昂的費用和耗時。
在本文中,我們將對服務網格架構模式解決的最常見的微服務通訊需求進行概述。
微服務動態和內在挑戰
當你意識到微服務實現了相當多的與最初分配給它們的業務邏輯無關的程式碼時,問題就出現了。此外,有可能你有多個微服務在非標準化的流程中實現了類似的功能。換句話說,微服務開發團隊應該專註於業務邏輯,並將低級通訊能力留給特定的層。
繼續推進我們的方案,需要考慮微服務的內在動態。在給定的時間內,你可能由於以下幾個原因而擁有一個微服務的多個實例:
- 吞吐量(Throughput):根據傳入的請求,你可能擁有更多或更少的微服務實例
- 金絲雀發布
- 藍綠部署
- A/B測試
簡而言之,微服務到微服務的通訊有特定的需求和問題需要解決。以下圖片展示了這一方案:
該圖示描述了幾個技術挑戰。顯然,Microservice 1的主要職責是均衡所有Microservice 2實例之間的負載。因此,Microservice 1必須弄清楚我們在請求時刻有多少個Microservice 2實例。換句話說,Microservice 1必須實現服務發現和負載均衡。
另一方面,Microservice 2必須實現一些服務註冊功能以告知Microservice 1何時有全新的實例。
想要擁有一個完全動態的環境,以下這些功能應該是微服務開發的一部分:
- 流量控制:負載均衡的自然演變。我們想指定應該發送到每個Microservice 2實例的請求數量。 在Microservice
1和2之間加密通訊 - 藉助斷路器和健康檢查以解決和克服網路問題
總而言之,主要問題是開發團隊花費了大量資源編寫十分複雜的程式碼,而這些程式碼與微服務預期交付的業務邏輯不直接相關。
有潛力的解決方案
如何將所有微服務都可以調用的外部標準化組件中的所有非功能和操作功能外部化?例如,下圖編譯了所有功能,這些功能不屬於給定的微服務。因此,在確定所有功能之後,我們需要決定在哪裡實現它們。
Solution #1 :將所有功能封裝在一個library中
開發者將負責調用library提供的函數來解決微服務通訊需求。
這個解決方案有幾個缺點:
這是一個緊密耦合的解決方案,意味著微服務高度依賴於library
這個模式對於分布和升級新版本的library來說並不容易
這不符合微服務多語言的原則,因為這會將不同的程式語言應用於不同的上下文。
Solution #2:透明代理(Transparent Proxy)
這個解決方案實現了同樣的功能集合。但是,採用了一種非常不同的方法:每個微服務都有一個特定的組件,扮演代理的角色,負責處理它的傳入和傳出流量。代理解決了我們之前描述的庫的缺點,具體如下:
- 代理是透明的,這意味著微服務不會意識到它正在附近運行並實現了與其他微服務進行通訊所需的所有功能。
- 由於它是一個透明的代理,開發者不需要改變程式碼來引用代理。因此,從微服務開發的角度來看,升級代理將是一個並不會對開發流程造成太大影響。
- 代理可以使用微服務使用的不同技術和程式語言進行開發。
服務網格架構模式
雖然透明代理的方法給微服務開發團隊和微服務通訊需求帶來了一些好處,但仍有一些缺失的部分:
- 代理只是執行策略來實現通訊需求,例如負載均衡、金絲雀發布等。
- 由什麼來負責定義這樣的策略,並在所有運行的代理上發布呢?
解決方案架構需要另一個組件,這些組件將被管理員用來定義策略,它將負責向代理傳播策略。
以下圖片展示了最終架構,也就是服務網格模式:
如你所見,該模式包含了我們所描述的兩個主要組件。
- 數據平面:也被稱為sidecar,它扮演著透明代理的角色。同樣,每個微服務都會有自己的數據平面,攔截所有的入站和出站流量,並應用之前描述的策略。
- 控制平面:由管理員用來定義策略並發布到數據平面。
一些重要的事情需要注意:
- 這是一個 “push-based “的架構。數據平面不做 “調用 “來獲取策略——那將會消耗網路。
- 數據平面通常向控制平面或特定的基礎設施報告使用指標。
手把手教你使用Rancher、Kong和Kong Mesh
Kong提供了一個企業級的綜合服務連接平台,其包括了API gateway、Kubernetes ingress controller以及服務網格實現。該平台允許用戶部署多個環境,如本地、混合雲、多區域以及多雲環境。
讓我們藉助運行在獨立於雲架構(cloud-agnostic)的Kubernetes集群上的金絲雀發布來實現服務網格,該集群可能包括GKE集群或任何其他的Kubernetes發行版。服務網格將由Kong Mesh實現,並由Kong for Kubernetes作為Kubernetes Ingress Controller。一般而言,ingress controller負責定義進入你的Kubernetes集群的入口點,暴露部署在其內部的微服務,並對其實行消費策略。
首先,確保你已經安裝Rancher以及正在運行一個由Rancher管理的Kubernetes集群。在登錄到Rancher之後,選在我們將要使用的Kubernetes集群,在本例中為「kong-rancher」。點擊Cluster Explorer。你將會重定向到以下頁面:
現在,讓我們從服務網格開始:
1、 Kong Mesh Helm Chart
回到Rancher Cluster Manger主頁並再次選擇你的集群。點擊菜單欄的「Tools」選項然後點擊Catalogs,以創建一個新的catalog。點擊Add Catalog按鈕,將Kong Mesh的Helm chart收錄其中(//kong.github.io/kong-mesh-charts/)。
選擇Global作為範圍,Helm v3作為Helm版本。
現在點擊Apps和Launch來查看在Catalog中可用的Kong Mesh。請注意,Kong作為Rancher的合作夥伴默認提供了Kong for Kubernetes的Helm chart:
2、 安裝Kong Mesh
點擊頂部菜單欄Namespaces選項並創建一個「kong-mesh-system」命名空間。
將滑鼠移到kong-rancher頂部菜單選項上,點擊kong-rancher活動集群。
點擊Launch kubetcl
創建一個名為「license.json」的文件,用於存放你從Kong Mesh收到的license。格式如下:
{「license」:
{「version」:1,「signature」:「6a7c81af4b0a42b380be25c2816a2bb1d761c0f906ae884f93eeca1fd16c8b5107cb6997c958f45d247078ca50a25399a5f87d546e59ea3be28284c3075a9769」,「payload」:
{「customer」:「Kong_SE_Demo_H1FY22」,「license_creation_date」:「2020-11-30」,「product_subscription」:「Kong Enterprise Edition」,「support_plan」:「None」,「admin_seats」:「5」,「dataplanes」:「5」,「license_expiration_date」:「2021-06-30」,「license_key」:「XXXXXXXXXXXXX」}}}
現在使用以下命令創建一個Kubernetes通用密鑰:
kubectl create secret generic kong-mesh-license -n kong-mesh-system --from-file=./license.json
關閉kubectl會話,點擊Default項目以及頂部菜單欄的Apps。點擊Launch按鈕並選擇kong-mesh Helm chart。
點擊Use an existing namespace並選擇我們剛剛創建的那個。這有幾個參數(//artifacthub.io/packages/helm/kong-mesh/kong-mesh)來配置Kong Mesh,但我們將保留所有默認值。點擊Launch之後,你應該看到Kong Mesh應用程式部署完成。
你可以再次使用Rancher Cluster Explorer來檢查安裝。點擊左側菜單的Pods並選擇kong-mesh-system的命名空間。
你也可以像這樣使用kubectl:
NAMESPACE NAME READY STATUS RESTARTS AGE
cattle-system cattle-cluster-agent-785fd5f54d-r7x8r 1/1 Running 0 75m
fleet-system fleet-agent-77c78f9c74-f97tv 1/1 Running 0 75m
kong-mesh-system kuma-control-plane-5b9c6f4598-nvq8q 1/1 Running 0 16m
kube-system event-exporter-gke-666b7ffbf7-n9lfl 2/2 Running 0 76m
kube-system fluentbit-gke-xqsdv 2/2 Running 0 76m
kube-system gke-metrics-agent-gjrqr 1/1 Running 0 76m
kube-system konnectivity-agent-4c4hf 1/1 Running 0 76m
kube-system kube-dns-66d6b7c877-tq877 4/4 Running 0 76m
kube-system kube-dns-autoscaler-5c78d65cd9-5hcxs 1/1 Running 0 76m
kube-system kube-proxy-gke-c-kpwnf-default-0-be059c1c-49qp 1/1 Running 0 76m
kube-system l7-default-backend-5b76b455d-v6dvg 1/1 Running 0 76m
kube-system metrics-server-v0.3.6-547dc87f5f-qntjf 2/2 Running 0 75m
kube-system prometheus-to-sd-fdf9j 1/1 Running 0 76m
kube-system stackdriver-metadata-agent-cluster-level-68d94db6-64n4r 2/2 Running 1 75m
3、 微服務部署
我們的Service Mesh部署是基於一個簡單的微服務到微服務的通訊場景。由於我們運行的是金絲雀發布,被調用的微服務有兩個版本:
「magnanimo」:通過Kong暴露Kubernetes ingress controller。
「benigno」:提供了一個 「hello」 endpoint,在這個端點中,它呼應了當前的datetime。它有一個金絲雀發布,會發送一個稍微不同的響應。
下圖展示了這一架構:
創建一個帶有sidecar注入注釋的命名空間。你可以再次使用Rancher Cluster Manager:選擇你的集群,然後單擊Projects/Namespaces。點擊Add Namespace。輸入 「kong-mesh-app」 作為名稱,並包含一個帶有 「kuma.io/sidecar-injection」 鍵和 「enabled」 作為其值的注釋。
當然,你也可以選擇使用kubectl
kubectl create namespace kong-mesh-app
kubectl annotate namespace kong-mesh-app kuma.io/sidecar-injection=enabled
Submit the following declaration to deploy Magnanimo injecting the Kong Mesh data plane
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: magnanimo
namespace: kong-mesh-app
spec:
replicas: 1
selector:
matchLabels:
app: magnanimo
template:
metadata:
labels:
app: magnanimo
spec:
containers:
- name: magnanimo
image: claudioacquaviva/magnanimo
ports:
- containerPort: 4000
---
apiVersion: v1
kind: Service
metadata:
name: magnanimo
namespace: kong-mesh-app
labels:
app: magnanimo
spec:
type: ClusterIP
ports:
- port: 4000
name: http
selector:
app: magnanimo
EOF
使用Rancher Cluster Manager檢查你的部署。將滑鼠移動至kong-rancher菜單上,點擊Default項目,可以看到當前的部署情況:
點擊magnanimo檢查部署的細節,包括其pods:
點擊magnanimo pod,檢查其內部運行的容器。
我們可以看到,pod有兩個運行的容器:
- magnanimo:微服務實際運行的地方。
- kuma-sidecar:在部署的時候注入,作為Kong Mesh的數據平面。
同理,部署Benigno的時候,也有自己的sidecar:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: benigno-v1
namespace: kong-mesh-app
spec:
replicas: 1
selector:
matchLabels:
app: benigno
template:
metadata:
labels:
app: benigno
version: v1
spec:
containers:
- name: benigno
image: claudioacquaviva/benigno
ports:
- containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
name: benigno
namespace: kong-mesh-app
labels:
app: benigno
spec:
type: ClusterIP
ports:
- port: 5000
name: http
selector:
app: benigno
EOF
And finally, deploy Benigno canary release. Notice that the canary release will be abstracted by the same Benigno Kubernetes Service created before:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: benigno-v2
namespace: kong-mesh-app
spec:
replicas: 1
selector:
matchLabels:
app: benigno
template:
metadata:
labels:
app: benigno
version: v2
spec:
containers:
- name: benigno
image: claudioacquaviva/benigno\_rc
ports:
- containerPort: 5000
EOF
使用以下命令檢查部署和Pods:
$ kubectl get pod --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
cattle-system cattle-cluster-agent-785fd5f54d-r7x8r 1/1 Running 0 75m
fleet-system fleet-agent-77c78f9c74-f97tv 1/1 Running 0 75m
kong-mesh-app benigno-v1-fd4567d95-drnxq 2/2 Running 0 110s
kong-mesh-app benigno-v2-b977c867b-lpjpw 2/2 Running 0 30s
kong-mesh-app magnanimo-658b67fb9b-tzsjp 2/2 Running 0 5m3s
kong-mesh-system kuma-control-plane-5b9c6f4598-nvq8q 1/1 Running 0 16m
kube-system event-exporter-gke-666b7ffbf7-n9lfl 2/2 Running 0 76m
kube-system fluentbit-gke-xqsdv 2/2 Running 0 76m
kube-system gke-metrics-agent-gjrqr 1/1 Running 0 76m
kube-system konnectivity-agent-4c4hf 1/1 Running 0 76m
kube-system kube-dns-66d6b7c877-tq877 4/4 Running 0 76m
kube-system kube-dns-autoscaler-5c78d65cd9-5hcxs 1/1 Running 0 76m
kube-system kube-proxy-gke-c-kpwnf-default-0-be059c1c-49qp 1/1 Running 0 76m
kube-system l7-default-backend-5b76b455d-v6dvg 1/1 Running 0 76m
kube-system metrics-server-v0.3.6-547dc87f5f-qntjf 2/2 Running 0 75m
kube-system prometheus-to-sd-fdf9j 1/1 Running 0 76m
kube-system stackdriver-metadata-agent-cluster-level-68d94db6-64n4r 2/2 Running 1 75m
$ kubectl get service --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.0.16.1 <none> 443/TCP 79m
kong-mesh-app benigno ClusterIP 10.0.20.52 <none> 5000/TCP 4m6s
kong-mesh-app magnanimo ClusterIP 10.0.30.251 <none> 4000/TCP 7m18s
kong-mesh-system kuma-control-plane ClusterIP 10.0.21.228 <none> 5681/TCP,5682/TCP,443/TCP,5676/TCP,5678/TCP,5653/UDP 18m
kube-system default-http-backend NodePort 10.0.19.10 <none> 80:32296/TCP 79m
kube-system kube-dns ClusterIP 10.0.16.10 <none> 53/UDP,53/TCP 79m
kube-system metrics-server ClusterIP 10.0.20.174 <none> 443/TCP 79m
你也可以使用Kong Mesh控制台來檢查微服務和數據平面。在Terminal上運行以下命令:
kubectl port-forward service/kuma-control-plane -n kong-mesh-system 5681
重定向你的瀏覽器到//localhost:5681/gui。點擊Skip to Dashboard和All Data Plane Proxies:
啟動一個循環,看看金絲雀發布的運行情況。注意服務已經被部署為ClusterIP類型,所以你需要用 「port-forward」直接暴露它們。下一步將展示如何用Ingress Controller暴露服務。
在本地terminal上運行:
kubectl port-forward service/magnanimo -n kong-mesh-app 4000
打開另一個Terminal,開始循環。請求要到Magnanimo提供的4000埠。路徑「/hw2 」將請求路由到Benigno服務,它後面有兩個endpoint,與Benigno兩個版本有關:
while [1]; do curl //localhost:4000/hw2; echo; done
你應該看到類似下方的結果:
Hello World, Benigno: 2020-11-20 12:57:05.811667
Hello World, Benigno: 2020-11-20 12:57:06.304731
Hello World, Benigno, Canary Release: 2020-11-20 12:57:06.789208
Hello World, Benigno: 2020-11-20 12:57:07.269674
Hello World, Benigno, Canary Release: 2020-11-20 12:57:07.755884
Hello World, Benigno, Canary Release: 2020-11-20 12:57:08.240453
Hello World, Benigno: 2020-11-20 12:57:08.728465
Hello World, Benigno: 2020-11-20 12:57:09.208588
Hello World, Benigno, Canary Release: 2020-11-20 12:57:09.689478
Hello World, Benigno, Canary Release: 2020-11-20 12:57:10.179551
Hello World, Benigno: 2020-11-20 12:57:10.662465
Hello World, Benigno: 2020-11-20 12:57:11.145237
Hello World, Benigno, Canary Release: 2020-11-20 12:57:11.618557
Hello World, Benigno: 2020-11-20 12:57:12.108586
Hello World, Benigno, Canary Release: 2020-11-20 12:57:12.596296
Hello World, Benigno, Canary Release: 2020-11-20 12:57:13.093329
Hello World, Benigno: 2020-11-20 12:57:13.593487
Hello World, Benigno, Canary Release: 2020-11-20 12:57:14.068870
4、 控制金絲雀發布的成本
正如我們所見,兩個Benigno微服務發布的請求使用了循環策略。也就是說,我們無法控制金絲雀發布的花銷。Service Mesh允許我們定義何時以及如何將金絲雀發布暴露給我們的consumer(在本例中指Magnanimo微服務)。
要定義一個策略來控制流向兩個版本的流量,需要使用下面這個聲明。它說90%的流量應該流向當前版本,而只有10%的流量應該重定向到金絲雀發布。
cat <<EOF | kubectl apply -f -
apiVersion: kuma.io/v1alpha1
kind: TrafficRoute
mesh: default
metadata:
namespace: default
name: route-1
spec:
sources:
- match:
kuma.io/service: magnanimo\_kong-mesh-app\_svc\_4000
destinations:
- match:
kuma.io/service: benigno\_kong-mesh-app\_svc\_5000
conf:
split:
- weight: 90
destination:
kuma.io/service: benigno\_kong-mesh-app\_svc\_5000
version: v1
- weight: 10
destination:
kuma.io/service: benigno\_kong-mesh-app\_svc\_5000
version: v2
EOF
應用聲明之後,你應該看到如下結果:
Hello World, Benigno: 2020-11-20 13:05:02.553389
Hello World, Benigno: 2020-11-20 13:05:03.041120
Hello World, Benigno: 2020-11-20 13:05:03.532701
Hello World, Benigno: 2020-11-20 13:05:04.021804
Hello World, Benigno: 2020-11-20 13:05:04.515245
Hello World, Benigno, Canary Release: 2020-11-20 13:05:05.000644
Hello World, Benigno: 2020-11-20 13:05:05.482606
Hello World, Benigno: 2020-11-20 13:05:05.963663
Hello World, Benigno, Canary Release: 2020-11-20 13:05:06.446599
Hello World, Benigno: 2020-11-20 13:05:06.926737
Hello World, Benigno: 2020-11-20 13:05:07.410605
Hello World, Benigno: 2020-11-20 13:05:07.890827
Hello World, Benigno: 2020-11-20 13:05:08.374686
Hello World, Benigno: 2020-11-20 13:05:08.857266
Hello World, Benigno: 2020-11-20 13:05:09.337360
Hello World, Benigno: 2020-11-20 13:05:09.816912
Hello World, Benigno: 2020-11-20 13:05:10.301863
Hello World, Benigno: 2020-11-20 13:05:10.782395
Hello World, Benigno: 2020-11-20 13:05:11.262624
Hello World, Benigno: 2020-11-20 13:05:11.743427
Hello World, Benigno: 2020-11-20 13:05:12.221174
Hello World, Benigno: 2020-11-20 13:05:12.705731
Hello World, Benigno: 2020-11-20 13:05:13.196664
Hello World, Benigno: 2020-11-20 13:05:13.680319
5、 安裝Kong for Kubernetes
讓我們回到Rancher中安裝我們的Kong for Kubernetes Ingress Controller,並控制服務網格的暴露。在Rancher Catalog頁面中,點擊Kong圖標。接受默認值,然後點擊Launch:
你應該看到Kong和Kong Mesh這兩個應用程式都已經部署完成:
再次使用kubectl檢查安裝:
$ kubectl get pod --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
cattle-system cattle-cluster-agent-785fd5f54d-r7x8r 1/1 Running 0 84m
fleet-system fleet-agent-77c78f9c74-f97tv 1/1 Running 0 83m
kong-mesh-app benigno-v1-fd4567d95-drnxq 2/2 Running 0 10m
kong-mesh-app benigno-v2-b977c867b-lpjpw 2/2 Running 0 8m47s
kong-mesh-app magnanimo-658b67fb9b-tzsjp 2/2 Running 0 13m
kong-mesh-system kuma-control-plane-5b9c6f4598-nvq8q 1/1 Running 0 24m
kong kong-kong-754cd6947-db2j9 2/2 Running 1 72s
kube-system event-exporter-gke-666b7ffbf7-n9lfl 2/2 Running 0 85m
kube-system fluentbit-gke-xqsdv 2/2 Running 0 84m
kube-system gke-metrics-agent-gjrqr 1/1 Running 0 84m
kube-system konnectivity-agent-4c4hf 1/1 Running 0 84m
kube-system kube-dns-66d6b7c877-tq877 4/4 Running 0 84m
kube-system kube-dns-autoscaler-5c78d65cd9-5hcxs 1/1 Running 0 84m
kube-system kube-proxy-gke-c-kpwnf-default-0-be059c1c-49qp 1/1 Running 0 84m
kube-system l7-default-backend-5b76b455d-v6dvg 1/1 Running 0 85m
kube-system metrics-server-v0.3.6-547dc87f5f-qntjf 2/2 Running 0 84m
kube-system prometheus-to-sd-fdf9j 1/1 Running 0 84m
kube-system stackdriver-metadata-agent-cluster-level-68d94db6-64n4r 2/2 Running 1 84m
$ kubectl get service --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.0.16.1 <none> 443/TCP 85m
kong-mesh-app benigno ClusterIP 10.0.20.52 <none> 5000/TCP 10m
kong-mesh-app magnanimo ClusterIP 10.0.30.251 <none> 4000/TCP 13m
kong-mesh-system kuma-control-plane ClusterIP 10.0.21.228 <none> 5681/TCP,5682/TCP,443/TCP,5676/TCP,5678/TCP,5653/UDP 24m
kong kong-kong-proxy LoadBalancer 10.0.26.38 35.222.91.194 80:31867/TCP,443:31039/TCP 78s
kube-system default-http-backend NodePort 10.0.19.10 <none> 80:32296/TCP 85m
kube-system kube-dns ClusterIP 10.0.16.10 <none> 53/UDP,53/TCP 85m
kube-system metrics-server ClusterIP 10.0.20.174 <none> 443/TCP 85m
6、 創建Ingress
通過下面的聲明,我們將通過一個Ingress和它的路由 「/route1」 來暴露Magnanimo微服務。
cat <<EOF | kubectl apply -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: route1
namespace: kong-mesh-app
annotations:
konghq.com/strip-path: "true"
spec:
rules:
- http:
paths:
- path: /route1
backend:
serviceName: magnanimo
servicePort: 4000
EOF
現在,臨時的 「port-forward」 暴露機制可以被正式的Ingress所取代。而我們的循環也可以開始消耗Ingress,結果如下:
while [1]; do curl //35.222.91.194/route1/hw2; echo; done