教程|使用Istio實現一個Service Mesh以簡化微服務間的通訊模式

本文爲譯文,英文原文地址:kublr.com/blog/implem…html

本文轉載自:www.servicemesher.com/blog/hands-…git

更多 Service Mesh 文章請訪問:www.servicemesher.comgithub

本文爲該教程的第1部分。web

若是你以前沒有據說過Service Mesh,不用擔憂。雖然從可用文檔、公開討論和Github活躍度來看,它是一個相對較新的技術,與基於容器和微服務架構類似尚未被普遍採用,可是它將會對軟件架構帶來深遠影響。本文將幫助您瞭解Service Mesh的基礎知識和教程,以及如何實現它並從基礎架構獲益。redis

Service Mesh的兩個主要目標是容許洞察先前不可見的服務通訊層,並獲取對全部微服務間像動態服務發現、負債均衡、超時、回退、重試、斷路器、分佈式調用鏈路追蹤和安全策略的執行等通訊邏輯的徹底控制。更多細節請查看Istio流量審計和分佈式鏈路追蹤相關資料。數據庫

Kubernetes已經擁有開箱即用的「Service Mesh」。它的「service」資源,提供了針對指定須要的pod的服務發現功能和請求的負載均衡。經過在集羣的每一個主機上配置管理iptables規則使一個「service」生效,只容許輪詢式負載均衡途徑,沒有重試或回退邏輯,除此以外沒有其餘咱們可能想要的用一個現代的Service Mesh解決的功能。然而,若在集羣中實現一個功能齊全的Service Mesh系統(Linkerd、Istio或Conduit),將爲您提供如下可能性:windows

  • 容許在應用層上服務間經過簡單的http協議通訊而不用https:Service Mesh代理將在發送端管理HTTPS封裝並在接收端實現TLS終止,容許應用程序組件僅須要使用簡單的http、gRPC或其餘協議而不用去操心在傳輸途中的加密實現,Service Mesh代理將爲實現加密功能。
  • 執行安全策略:代理知道那些service能夠訪問另一些service和endpoint並拒絕未受權的流量。
  • 斷路器:訪問具備高延遲的過載service或者endpoint回退,防止更多的請求落在該service或endpoint上致使請求無響應。
  • 延遲感知負載平衡:而代替使用輪詢式負載均衡(忽略每一個目標延遲),使用根據每一個後端目標的響應時間更智能的負載均衡,這應該是現代服務網格的一個很是重要的特徵。
  • 負債均衡隊列深度:根據最少訪問量路由當前請求。Service Mesh精確知道全部已經發送請求,以及它們是正在處理仍是已經完成。它會根據該邏輯將新的傳入請求發送到具備最小隊列的節點進行處理。
  • 請求路由:把根據具備特定http頭標記的請求路由到負債均衡後面的特定節點。容許簡單的金絲雀部署測試和其餘創造性用例。這是Service Mesh提供的最強大功能之一。
  • 健康檢查,重試預算和驅逐行爲異常的節點
  • 度量標準和跟蹤:報告每一個target的請求量、延遲指標、成功率和錯誤率。

下面是兩種部署Service Mesh的方式:後端

做爲主機共享代理,Kubernetes術語中的DaemonSet。若是同一主機上存在許多容器,而且還可能利用鏈接池來提升吞吐量,則此類部署將使用較少的資源。可是,若是一個代理中的故障將搞垮該主機上的整個容器隊列,而不是破壞單個服務(若是它被用做sidecar代理)。api

做爲容器sidecar,將代理注入到每一個pod定義中與主服務一塊兒運行。若是使用像Linkerd這樣更加「重量級」的代理,這個部署將爲每一個pod增長約200MB的內存。但若是使用較新的Conduit,每一個pod只需10MB左右。Conduit尚未Linkerd的全部功能,因此咱們尚未看到二者的最終比較。一般,「每一個pod中一個sidecar」是一個不錯的選擇,這樣儘量的將代理故障限制在單個pod中,不要影響同一主機上的其餘pod。瀏覽器

爲何須要建立Service Mesh架構?讓咱們看一下不一樣類型的應用程序架構的兩個圖表來講明需求。

第一個示例是一個老式基於MVC架構的Web服務,是做爲單體架構all-in-one應用程序。可能天天服務數百萬個請求,但沒有複雜的功能,而且底層服務的通訊簡單明瞭:Nginx均衡Apache實例的全部流量,Apache又從數據庫/文件存儲中獲取數據並返回請求頁面。這個示例所採用的架構不會從服務網格中獲取太多收益。因爲單體應用沒有采用服務調用的方式,因此全部功能是耦合在一塊的,開發者沒有開發處理服務間路由和通訊的代碼。在單體應用,全部核心組件都位於同一臺機器上,不經過網絡進行通訊,沒有REST API或gRPC。全部「業務邏輯」都在一個應用程序中,在每一個Apache Web服務器上做爲總體部署。

第二個例子是一個基於現代微服務架構的應用程序,它有不少進程和幕後邏輯。它作了不少事情,好比學習訪問者模式和偏好來個性化他們在網站上的體驗,通知用戶他們最喜歡的topic更新,等等。您能夠想象在全部這些微服務之間發生的許多複雜過程,分佈在數千個容器和數百個節點上。請注意,咱們的插圖很是簡化。實際上,咱們顯示大型雲原生應用程序的真實架構中簡化了不少細節。

在這個實例程序中咱們的每一個微服務都有一些代碼用於處理彼此間的通訊,設置重試策略、超時、異常處理等等(在網絡故障的狀況下)。咱們還看到這是一個多語言環境,其中不一樣團隊使用Scala、Golang、Node.js或Python開發本身的服務組件。全部組件均可以經過REST API或gRPC相互通訊,每一個團隊都花費時間和精力在他們本身的組件中實現通訊邏輯,使用他們各自的語言選擇,所以他們不能共享彼此的庫和函數,至少能夠節省時間並使用插入應用程序的全部組件的統一解決方案做爲依賴。此外,查詢服務發現機制的函數(如Consul或ZooKeeper)或讀取外部傳遞給應用程序的一些配置,須要向Prometheus/InfluxDB報告延遲和響應相關指標。這包括有關緩存響應時間(redis或memcached緩存)的信息,該緩存響應時間一般位於另外一個節點上,或者做爲整個單獨的羣集,可能會過載並致使高延遲。除了團隊爆炸日誌和截止日期臨近以外,全部這些都是服務代碼的一部分,須要維護。開發人員不肯花時間在代碼的運維相關部分任務上,例如添加分佈式追蹤和監控指標(不喜歡排除故障和分析)或處理可能的網絡故障,實施回退和重試預算。

在這種環境中,Service Mesh將節省開發時間,並容許以統一的方式以集中式地控制通訊。那咱們如何將這種通訊層機制改成統一的「Service Mesh」?咱們把微服務間通訊、路由、服務發現、延遲指標、請求追蹤、和微服務中的一些類似代碼徹底抽取到服務外邊,搞一個可以處理這些甚至更多功能的單例進程爲每一個微服務去處理這些公共邏輯。幸運的是這些工具已經存在,像Twitter、Lyft、Netflix這樣的公司已經開源了本身的工具,其餘貢獻者也能夠基於這些庫開發本身的工具。目前爲止咱們有Linkerd、Conduit、Istio和Envoy供選擇。Istio基於Envoy構建的,它是一個控制平面,Envoy和Linkerd均可以用做它的數據平面代理。控制平面容許集羣運維人員以集中式地設置特定設置,而後將其分佈在數據平面代理上並從新配置它們。

Linkerd和Conduct由Buoyant開發,開發者是一些曾經在Twitter工做的工程師。目前Linkerd是最經常使用的Service Mesh之一,而Conduit是從頭開始專門爲Kubernetes構建的輕量級sidecar,很是快速且很是適合Kubernetes環境。在撰寫本文時,Conduit仍處於積極發展階段。

讓咱們看一下從依賴於應用程序的通訊邏輯到「Service Mesh」架構的變化。

最值得注意的是,全部代理均可以在同一個地方配置和更新,經過他們的控制平面(或經過某些存儲庫中的配置文件, 取決於所選的工具和部署方法),咱們能夠在數千個代理配置特定規則。所以,路由、負載均衡、度量指標收集、安全策略實施、斷路器、數據傳輸加密,全部這些操做都將嚴格遵循由集羣管理員應用的一系列規則。

Service Mesh適合您嗎?

乍一看,這種將微服務通訊機制分離到單獨的架構層的新概念引入了一個問題:是否值得配置和維護一整套複雜的特殊代理?要回答這個問題,您須要估算應用程序規模和複雜程度。若是您只有幾個微服務和數據存儲端點(例如,一個用於記錄的ElasticSearch集羣,一個用於度量的Prometheus集羣,具備兩個或三個主應用程序數據的數據庫),那麼實現服務網格可能對您的環境來講沒有太大必要。可是,若是您的應用程序組件分佈在數百或數千個節點上,而且具備20+微服務,採用Service Mesh你將受益不淺。

即便在較小的環境中,若是您但願將重試和斷路行爲與應用程序自己分離(例如,從管理鏈接和退出的代碼,以免重試致使其餘服務或數據庫過載),您可使用服務網格 從您的應用程序開發人員中刪除此網絡邏輯維護負擔,你可使用服務網格下降應用程序開發人員維護網絡邏輯的負擔。所以,他們將更多地關注業務邏輯,而不是參與管理和調整全部微服務的相互通訊。

運維團隊一旦配置服務網絡,就能夠集中調整,最大限度地減小在應用程序組件通訊上花費的精力。

Istio是一個集中全部Service Mesh特性的完美例子,它有幾個「主組件」來管理全部「數據平面」代理(這些代理能夠是Envoy或Linkerd,但默認狀況下,它是Envoy,這是咱們在教程中使用的內容,而Linkerd集成仍在進行中)。

如下是官方網站上Istio架構的圖表:

譯者注:圖中的istio-auth現已更名爲citadel

您能夠在官方文檔中閱讀更多內容,可是出於本教程的目的,如下是Istio組件及其功能的摘要:

控制平面

  • Pilot:向Envoy代理提供路由規則和服務發現信息。
  • Mixer:從每一個Envoy代理收集遙測並執行訪問控制策略。
  • Citadel:提供「服務間」和「用戶到服務」認證,而且能夠將未加密的流量基於TLS加密。很快就能提供訪問審覈信息(正在進行的工做)。

數據平面

  • Envoy:功能豐富的代理,由控制平面組件管理。攔截進出服務的流量,並按照控制平面中設置的規則應用所需的路由和訪問策略。

教程

在下面的教程中,咱們將使用Istio來演示一個最強大的功能:「按請求路由」。如前面說的那樣,它容許將選定HTTP頭標記的特定請求路由到僅可經過第7層代理實現的特定目標。沒有第4層負載均衡器或代理能夠實現該功能。

對於本教程,咱們假設您正在運行Kubernetes集羣(提示:您能夠在幾分鐘內遵循這些說明或啓動新集羣,或者使用「Kublr-in-a-box」經過幾個簡單的步驟設置本地羣集)。對於本教程,有1個主節點和2個工做節點的小型集羣應該足夠了。

教程第1階段:安裝Istio控制平面

按官方教程安裝在Kubernetes集羣中安裝控制平面。這個安裝步驟依賴你的本地環境(windows、Linux仍是MAC),因此咱們不能複製使用本地標準指令設置應用程序,咱們使用istioct和kubectl兩個CLI工具管理庫爾netes和istio。請安裝下面簡明扼要的描述去作(若是不起做用,請逐步使用官方說明):

  1. 設置kubernetes集羣(使用上面列出的方法,或使用您現有的測試/開發羣集)

  2. 下載kubectl並配置到環境環境(用它管理你的kubernetes環境)

  3. 下載istioctl並配置到環境變量(使用它把Envoy代理注入到每一個pod中設置路由和策略)下面是簡單安裝說明:

(1)在MAC或Linux命令行上實行

curl -L https://git.io/getLatestIstio | sh -
複製代碼

(2)在windows上下載istio.zip並解壓文件,將文件路徑配置到你的環境變量中

(3)切換到解壓環境上面文件解壓路徑中,並執行

kubectl apply -f install/kubernetes/istio-demo.yaml
複製代碼

另外一種安裝方式是使用Kublr安裝你的kubernetes集羣環境——一個簡單的方法是經過雲提供商(阿里雲騰訊雲awsazuregcp或者quick start)上拉起一個kubernetes集羣。 kublr

找到%USERPROFILE%/.kube/config文件拷貝到你的宿主機目錄下(~/.kube/config),調到以下頁面:

使用配置文件中的管理員帳號和密碼登錄到kubernetes dashboard,你應該可以看到這個儀表盤,點擊側邊欄顯示的default這個 namespace:

Istio組件將安裝到它們本身的namespace中。調到istio下載目錄,並執行命令:

kubectl apply -f install/kubernetes/istio-demo.yaml
複製代碼

你將看到一些列的組件被建立,詳情請看官方文檔或者你也能夠打開yaml文件查看相應組件,每一個資源都記錄在該文件中。而後咱們能夠瀏覽namespace並查看全部已成功建立的內容:

在組件建立期間點擊istio-system查看是否有錯誤或者issue,看起來應該和下面相似:

從圖中能夠看到有50個事件,你能滾動屏幕去看「成功」狀態,並注意有些地方可能存在錯誤。若是有錯誤,你能夠去github上提交issue。

咱們須要找到istio-ingress服務的入口,去了解那裏發送流量。回到kubernetes dashboard的側邊欄並跳轉到istio-system這個namespace下。若是建立後在這個namespace下不可見,刷新瀏覽器試試。點擊「Services」找到external endpoint,以下圖所示:

在咱們的例子中,這是AWS彈性負載均衡器,但你可能會看到IP地址,具體取決於集羣設置。咱們將使用此端點地址訪問咱們的演示Web服務。

教程第2階段:使用Envoy Sidecar部署演示Web服務

這是本教程中最好玩的部分。咱們來檢查一下這個Service Mesh的路由功能。首先咱們將像前面同樣經過藍綠髮布咱們的demo實例服務。將如下內容複製到名爲的my-websites.yaml文件中。

apiVersion: apps/v1beta1
kind: Deployment
metadata:
 name: web-v1
 namespace: default
spec:
 replicas: 1
 template:
 metadata:
 labels:
 app: website
 version: website-version-1
 spec:
 containers:
 - name: website-version-1
 image: aquamarine/kublr-tutorial-images:v1
 resources:
 requests:
 cpu: 0.1
 memory: 200
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
 name: web-v2
 namespace: default
spec:
 replicas: 1
 template:
 metadata:
 labels:
 app: website
 version: website-version-2
 spec:
 containers:
 - name: website-version-2
 image: aquamarine/kublr-tutorial-images:v2
 resources:
 requests:
 cpu: 0.1
 memory: 200
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
 name: web-v3
 namespace: default
spec:
 replicas: 1
 template:
 metadata:
 labels:
 app: website
 version: website-version-3
 spec:
 containers:
 - name: website-version-3
 image: aquamarine/kublr-tutorial-images:v3
 resources:
 requests:
 cpu: 0.1
 memory: 200
---
apiVersion: v1
kind: Service
metadata:
 name: website
spec:
 ports:
 - port: 80
 targetPort: 80
 protocol: TCP
 name: http
 selector:
 app: website
複製代碼

在你的pod和Envoy代理一塊兒使用時請注意,「app」這個label的存在(它用於請求跟蹤功能),在服務中「spec.ports.name」的值要拼寫正確(http、http二、grpc、redis、mongo),Enovy將像對待普通TCP同樣代理這些服務,你不能對這些服務使用L7路由功能。pod在集羣中只提供同一服務。從文件能夠看到這個服務有三個版本(v1/v2/v3)。服務的每一個版本都有對應的Deployment。

如今咱們添加針對此pod的Envoy代理配置到這個文件中。使用「istioctl kube-inject」命令,它將生成一個可供kubectl部署使用包含Envoy代理額外組件的新yaml文件,運行命令:

istioctl kube-inject -f my-websites.yaml -o my-websites-with-proxy.yaml
複製代碼

輸出文件將包含額外配置,你能查看my-websites-with-proxy.yaml文件。此命令採用預約義的ConfigMap 「istio-sidecar-injector」(它在定義istio以前已經定義)。併爲咱們的deployment定義添加了所需的sidecar配置和參數。當咱們部署新文件「my-websites-with-proxy.yaml」時,每一個pod將有兩個容器,一個咱們的實例程序,一個Envoy代理。運行下面命令部署咱們的服務程序和sidecar:

kubectl create -f my-websites-with-proxy.yaml
複製代碼

若是它按預期工做,您將看到此輸出:

deployment "web-v1" created
deployment "web-v2" created
deployment "web-v3" created
service "website" created
Let’s inspect the pods to see that the Envoy sidecar is present:  kubectl get pods
複製代碼

咱們能夠看到每一個pod有兩個容器,一個是網站容器,另外一個是代理sidecar:

咱們可以經過執行以下命令查看Envoy運行日誌:

kubectl logs <your pod name> istio-proxy
複製代碼

您將看到不少輸出,最後幾行與此相似:

add/update cluster outbound|80|version-1|website.default.svc.cluster.local starting warming
add/update cluster outbound|80|version-2|website.default.svc.cluster.local starting warming
add/update cluster outbound|80|version-3|website.default.svc.cluster.local starting warming
warming cluster outbound|80|version-3|website.default.svc.cluster.local complete
warming cluster outbound|80|version-2|website.default.svc.cluster.local complete
warming cluster outbound|80|version-1|website.default.svc.cluster.local complete
複製代碼

這意味着sidecar在pod中運行良好。

如今咱們須要部署最小的Istio配置資源,須要將路由流量到咱們的service和pod。請把下面的文件保存到website-routing.yaml文件。

---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
 name: website-gateway
spec:
 selector:
    # Which pods we want to expose as Istio router
    # This label points to the default one installed from file istio-demo.yaml
 istio: ingressgateway
 servers:
 - port:
 number: 80
 name: http
 protocol: HTTP
    # Here we specify which Kubernetes service names
    # we want to serve through this Gateway
 hosts:
 - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
 name: website-virtual-service
spec:
 hosts:
 - "*"
 gateways:
 - website-gateway
 http:
 - route:
 - destination:
 host: website
 subset: version-1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
 name: website
spec:
 host: website
 subsets:
 - name: version-1
 labels:
 version: website-version-1
 - name: version-2
 labels:
 version: website-version-2
 - name: version-3
 labels:
 version: website-version-3
複製代碼

該文件定義了Gateway、VirtualService和DestinationRule。這些是自定義Istio資源,用於管理和配置istio-ingressgateway pod的ingress行爲。咱們將在下一個教程中更深刻地描述它們,這些教程將闡述Istio配置的技術細節。如今,部署這些資源以便可以訪問咱們的示例網站:

kubectl create -f website-routing.yaml
複製代碼

下一步是訪問咱們的演示網站。咱們部署了三個版本,每一個都顯示不一樣的頁面文字和顏色,但目前咱們只能經過Istio ingress訪問v1。讓咱們訪問咱們的服務確保Web服務被部署了。

經過運行以下命令查看外部端點:

kubectl get services istio-ingressgateway -n istio-system
複製代碼

或者經過瀏覽istio-ingressgateway服務找到它,以下所示(咱們也在本教程的開頭看到過它)

img

經過點擊它訪問外部節點。您可能會看到多個連接,由於一個連接指向HTTPS,另外一個連接指向負載均衡器的HTTP端口。若是是這樣,請僅使用HTTP連接,由於咱們沒有爲本教程設置TLS,您應該看到演示網站的v1頁面:

爲咱們demo示例明確配置kubernetes service指向單一部署istio VirtualService。它指明Envoy將訪問網站的流量所有路由到v1版本(若是沒有Envoy路由策略,kubernetes將會在三本版本的pods輪詢請求)。您能夠經過更改VirtualService配置的如下部分並從新部署它來更改咱們看到的網站版本:

 http:
 - route:
 - destination:
 host: website
 subset: version-1
複製代碼

「subset」是咱們選擇要路由到的DestinationRule的正確地方。咱們將在下一個教程中深刻學習這些資源。

一般,當須要使用少許流量測試新版本的應用程序時(金絲雀部署)。vanilla Kubernetes方法使用新的Docker鏡像,相同的pod標籤,建立第二個deployment,將流量路由到有這個label標記的服務上。這不像Istio解決方案那樣靈活。您沒法輕鬆將10%的流量指向新deployment(爲了達到精確的10%,您須要根據所需的百分比保持兩個deployment之間的pod複製比例,例如9個「v1 pod」和1個「v2 pod」,或18個「v1 pod」和2個「v2 pod 」),而且不能使用HTTP頭標記來將請求路由到特定版本。

在咱們的下一篇文章中,與Istio一塊兒實踐的金絲雀部署,咱們將自定義http頭路由請求到正確的服務版本。經過這樣作,咱們將徹底控制流量,並將分析Zipkin儀表板中的分佈式追蹤結果。

Istio的部署十分依賴Kubernetes,爲了你們更好的理解 Kubernetes 原理,我推薦學習深刻剖析Kubernetes by 張磊,極客時間出品

ServiceMesher社區信息

微信羣:聯繫我入羣

社區官網:www.servicemesher.com

Slack:servicemesher.slack.com 須要邀請才能加入

Twitter: twitter.com/servicemesh…

GitHub:github.com/servicemesh…

更多Service Mesh諮詢請掃碼關注微信公衆號ServiceMesher。

相關文章
相關標籤/搜索