如何通過Istio實現微服務特性

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在微服務架構中,應用程序是由多個相互連接的服務組成的,這些服務協同工作以實現所需的業務功能。所以,一個典型的企業級微服務架構如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/71image001-1624026324115.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最初,我們可能認爲使用微服務架構實現一個應用程序是很容易的事情。但是,要恰當地完成這一點並不容易,因爲我們會面臨一些新的挑戰,而這些挑戰是單體架構所未曾遇到的。舉例來講,這樣的挑戰包括容錯、服務發現、擴展性、日誌和跟蹤等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了應對這些挑戰,每個微服務都需要實現在Red Hat被稱爲“微服務特性(microservicility)”的內容。這個術語指的是除了業務邏輯之外,服務必須要實現的一個橫切性關注點的列表。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些關注點總結起來如下圖所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/27image002-1624026324115.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"業務邏輯可以使用任何語言(Java、Go或JavaScript)或任何框架(Spring Boot、Quarkus)來實現,但是圍繞着業務邏輯,我們應該實現如下的關注點:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"API"},{"type":"text","text":":服務可以通過一組預先定義的API操作進行訪問。例如,在採用RESTful Web API的情況下,會使用HTTP作爲協議。此外,API還可以使用像"},{"type":"link","attrs":{"href":"https:\/\/swagger.io\/","title":"","type":null},"content":[{"type":"text","text":"Swagger"}]},{"type":"text","text":"這樣的工具實現文檔化。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"發現(Discovery)"},{"type":"text","text":":服務需要發現其他的服務。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"調用(Invocation)"},{"type":"text","text":":在服務發現之後,需要使用一組參數來調用它,並且可能會返回一個響應。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"彈性(Elasticity)"},{"type":"text","text":":微服務架構很重要的特性之一就是每個服務都是有彈性的,這意味着它可以根據一些參數(比如系統的重要程度或當前的工作負載)獨立地進行擴展和伸縮。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"回彈性(Resiliency)"},{"type":"text","text":":在微服務架構中,我們在開發時應該要考慮到故障,特別是與其他服務進行通信的時候。在單體架構中,應用會作爲一個整體進行啓動和關閉。但是,當我們把應用拆分成微服務架構之後,應用就變成由多個服務組成的,所有的服務會通過網絡互相連接,這意味着應用的某些部分可能在正常運行,而其他部分可能已經出現了故障。在這種情況下,很重要的一點就是遏制故障,避免錯誤通過其他的服務進行傳播。回彈性(或稱爲應用回彈性)是指一個應用\/服務能夠對面臨的問題作出反應的能力,在出現問題的時候,依然能夠提供儘可能最好的結果。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"管道(Pipeline)"},{"type":"text","text":":服務應該能夠獨立部署,不需要任何形式的部署編排。基於這一點,每個服務應該有自己的部署管道。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"認證(Authentication)"},{"type":"text","text":":在微服務架構中,涉及到安全性時,很重要的一個方面就是如何認證\/授權內部服務之間的調用。Web token(以及通用的token)是在內部服務之間聲明安全性的首選方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"日誌(Logging)"},{"type":"text","text":":在單體應用中,日誌是很簡單的事情,因爲應用的所有組件都在同一個節點中運行。現在,組件以服務的形式分佈在多個節點上,因此,爲了全面瞭解日誌跟蹤的情況,我們需要一個統一的日誌系統\/數據收集器。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"監控(Monitoring)"},{"type":"text","text":":要保證基於微服務的應用正確運行,很重要的一個方面就是衡量系統的運行情況、理解應用的整體健康狀況並在出現問題的時候發出告警。監控是控制應用程序的重要方面。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"跟蹤(Tracing)"},{"type":"text","text":":跟蹤是用來可視化一個程序的流程和數據進展的。當我們需要檢查用戶在整個應用中的操作時,它對開發人員或運維人員尤其有用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Kubernetes正在成爲部署微服務的事實標準工具。它是一個開源的系統,用來自動化、編排、擴展和管理容器。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是在我們提到的十個微服務特性中,通過使用Kubernetes只能覆蓋其中的三個。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/15image006-1624026324115.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"**發現(Discovery)**是通過_Kubernetes Service_理念實現的。它提供了一種將_Kubernetes Pod_(作爲一個整體)進行分組的方式,使其具有穩定的虛擬IP和DNS名。要發現一個服務只需要發送請求的時候使用Kubernetes的服務名作爲主機名即可。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用Kubernetes **調用(Invocation)**服務是非常容易的,因爲平臺本身提供了所需的網絡來調用任意的服務。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"彈性(Elasticity)"},{"type":"text","text":"(或者說擴展性)是Kubernetes從一開始就考慮到的問題,例如,如果運行"},{"type":"codeinline","content":[{"type":"text","text":"kubectl scale deployment myservice --replicas=5"}]},{"type":"text","text":"命令的話,myservice deployment就會擴展至五個副本或實例。Kubernetes平臺會負責尋找合適的節點、部署服務並維持所需數量的副本一直處於運行狀態。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是,剩餘的微服務特性該怎麼處理呢?Kubernetes只涵蓋了其中的三個,那麼我們該如何實現剩餘的哪些呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在本系列的"},{"type":"link","attrs":{"href":"https:\/\/www.infoq.cn\/article\/MBAYoWrjCOAJK5QuqbcQ","title":"","type":null},"content":[{"type":"text","text":"第一篇文章"}]},{"type":"text","text":"中,我介紹了一種實現它們的方式,那就是使用Java將它們嵌入到服務內部。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在代碼內部實現橫切性關注點的服務如下圖所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/14image008-1624026324115.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"正如在前面的文章中所闡述的那樣,這種方式能夠正常運行並且具有很多的優勢,但是它也有一些缺點。我們介紹主要的幾個問題:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"服務的基礎代碼變成了業務邏輯(會給公司帶來價值)和基礎設施代碼(微服務所需)的混合體。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"微服務架構中的服務可能會使用不同的語言開發,比如服務A使用Java語言,服務B使用Go語言。多語言服務所帶來的挑戰在於學習如何爲每種語言實現這些微服務特性。例如,在Java中使用哪個庫來實現回彈性,在Go中使用哪個庫等等。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"就Java來講,對於每個微服務特性來講,我們可能都會添加新的庫(及其所有的傳遞性依賴),例如,爲了實現回彈性引入"},{"type":"link","attrs":{"href":"https:\/\/github.com\/resilience4j\/resilience4j","title":"","type":null},"content":[{"type":"text","text":"Resiliency4J"}]},{"type":"text","text":"、爲了實現跟蹤引入"},{"type":"link","attrs":{"href":"https:\/\/github.com\/jaegertracing\/jaeger-client-java","title":"","type":null},"content":[{"type":"text","text":"Jaeger"}]},{"type":"text","text":"或者爲了實現監控引入"},{"type":"link","attrs":{"href":"https:\/\/micrometer.io\/","title":"","type":null},"content":[{"type":"text","text":"Micrometer"}]},{"type":"text","text":"。儘管這麼做沒有什麼問題,但是我們在類路徑下加入不同種類的庫的過程中,會增加類路徑衝突的機率。除此之外,內存消耗和啓動時間也會隨之增加。最後同樣重要的是,在所有的Java服務之間維護這些庫的版本也是一個問題,我們要讓它們保持相同的版本。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"歸根到底,我們可能會想,爲什麼需要實現這些微服務特性呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在微服務架構中,應用程序是由相互連接的多個服務組成的,所有的服務相互協作以生成我們所需的業務功能。這些服務都是使用網絡互相連接在一起的,所以實際上我們實現了一個分佈式計算的模型。由於它是分佈式的,可觀察性(監控、跟蹤、日誌)就變得有些複雜了,因爲所有的數據分散在多個服務中。因爲網絡是不可靠的,或者網絡延遲不可能爲零,所以服務需要在面臨故障的時候具備回彈性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此,我們可以假定之所以需要微服務特性,是因爲在基礎設施層(我們需要使用網絡的分佈式服務通信,而不是單體)所做的決定。那麼我們爲什麼要在應用層面實現這些微服務特性,而不是在基礎設施層面實現呢?問題就在這裏,這個問題有一個很簡單的答案,那就是"},{"type":"text","marks":[{"type":"strong"}],"text":"服務網格"},{"type":"text","text":"。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"什麼是服務網格和Istio?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"服務網格是一個專用的基礎設施層,目的在於使得服務與服務之間的通信變得安全、快速和可靠。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"服務網格通常以輕量級網絡代理的形式實現並且會與服務代碼部署在一起,它會攔截服務所有進站\/出站的網絡流量。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/istio.io\/","title":"","type":null},"content":[{"type":"text","text":"Istio"}]},{"type":"text","text":"是一個適用於Kubernetes的開源服務網格實現。Istio採用的策略是集成一個網絡流量代理到Kubernetes Pod中,而這個過程是藉助"},{"type":"link","attrs":{"href":"https:\/\/istio.io\/latest\/docs\/setup\/additional-setup\/sidecar-injection\/","title":"","type":null},"content":[{"type":"text","text":"sidecar容器"}]},{"type":"text","text":"實現的。sidecar容器與服務容器運行在同一個Pod中。因爲它們運行在系統的Pod之中,所以兩個容器會共享IP、生命週期、資源、網絡和存儲。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/11image010-1624026324115.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Istio使用"},{"type":"link","attrs":{"href":"https:\/\/www.envoyproxy.io\/","title":"","type":null},"content":[{"type":"text","text":"Envoy Proxy"}]},{"type":"text","text":"作爲sidecar容器中的網絡代理,並且會配置Pod通過Envoy代理(sidecar容器)發送所有的入站\/出站流量。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在使用Istio的時候,服務之間的通信並不是直接進行的,而是通過sidecar容器(即Envoy)進行的,當服務A請求服務B的時候,請求會通過服務A的DNS發送到它的代理容器上。隨後,服務A的代理容器會發送請求至服務B的代理容器,代理容器最終會調用真正的服務B。響應過程則會遵循完全相反的路徑。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/9image012-1624026324115.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Envoy代理的sidecar容器實現瞭如下的特性:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"智能路由和跨服務的負載均衡。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"故障注入。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"回彈性:重試和斷路器。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可觀察性和遙測:指標與跟蹤。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"安全性:加密和授權。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"全局範圍(fleet-wide)的策略執行。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過下圖我們可以看出,sidecar容器實現的特性能夠非常好地匹配五個微服務特性:服務發現、回彈性、認證、監控和跟蹤。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/9image014-1624026324115.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在容器中實現微服務特性的邏輯有如下幾個好處:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"業務代碼與微服務特性完全隔離。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所有的服務會使用完全相同的實現,因爲它們使用的是同一個容器。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"它的代碼是獨立的。服務可以使用任意語言實現,但是這些橫切性的關注點始終是相同的。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所有服務的配置過程和參數是相同的。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是,Istio內部是如何運行的,我們爲什麼需要Istio,而不是直接使用Envoy代理呢?"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"架構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Envoy代理是一個輕量級的網絡代理,它可以單獨使用,但是如果有十個服務要部署的話,我們就需要配置十個Envoy代理。這個過程會變得有一些複雜和繁瑣。Istio簡化了這一過程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從架構上來講,Istio服務網格是由數據平面(data plane)和控制平面(control plane)組成的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"數據平面"},{"type":"text","text":"是由以sidecar形式部署的Envoy代理組成的。這個代理會攔截所有網絡之間的通信。它還會收集和報告所有網格流量的遙測數據。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"控制平面"},{"type":"text","text":"負責管理和配置Envoy代理。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下圖描述了這兩個組件:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/8image016-1624026324115.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"安裝Istio"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們需要一個安裝Istio的Kubernetes集羣。就本文來講,我們會使用"},{"type":"link","attrs":{"href":"https:\/\/minikube.sigs.k8s.io\/docs\/start\/","title":"","type":null},"content":[{"type":"text","text":"Minikube"}]},{"type":"text","text":",但是任意其他的Kubernetes集羣都是可以的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行如下的命令來啓動集羣:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"minikube start -p istio --kubernetes-version='v1.19.0' --vm-driver='virtualbox' --memory=4096\n\n [istio] minikube v1.17.1 on Darwin 11.3\n Kubernetes 1.20.2 is now available. If you would like to upgrade, specify: --kubernetes-version=v1.20.2\n minikube 1.19.0 is available! Download it: https:\/\/github.com\/kubernetes\/minikube\/releases\/tag\/v1.19.0\n To disable this notice, run: 'minikube config set WantUpdateNotification false'\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"✨  基於已有的profile並使用virtualbox驅動"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"❗  對於既有的minikube集羣,我們無法改變它的內存大小。如果需要的話,請先將該集羣刪除掉。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" Starting control plane node istio in cluster istio\n Restarting existing virtualbox VM for \"istio\" ...\n Preparing Kubernetes v1.19.0 on Docker 19.03.12 ...\n Verifying Kubernetes components...\n Enabled addons: storage-provisioner, default-storageclass\n Done! kubectl is now configured to use \"istio\" cluster and \"\" namespace by default\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Kubernetes集羣運行起來之後,我們就可以下載"},{"type":"codeinline","content":[{"type":"text","text":"istioctl "}]},{"type":"text","text":"CLI工具來安裝Istio到集羣中了。在本例中,我們會從"},{"type":"link","attrs":{"href":"https:\/\/github.com\/istio\/istio\/releases\/tag\/1.9.4","title":"","type":null},"content":[{"type":"text","text":"版本發佈"}]},{"type":"text","text":"頁面下載Istio 1.9.4。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"istioctl"}]},{"type":"text","text":"工具安裝完成之後,我們就可以將Istio部署到集羣之中了。Istio自帶了不同的"},{"type":"link","attrs":{"href":"https:\/\/istio.io\/latest\/docs\/setup\/additional-setup\/config-profiles\/","title":"","type":null},"content":[{"type":"text","text":"profiles"}]},{"type":"text","text":",但是就開始學習Istio而言,demo profile是最合適的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"istioctl install --set profile=demo -y"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Detected that your cluster does not support third party JWT authentication. Falling back to less secure first party JWT. See https:\/\/istio.io\/docs\/ops\/best-practices\/security\/#configure-third-party-service-account-tokens for details."}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"✔ Istio core installed"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"✔ Istiod installed"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"✔ Egress gateways installed"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"✔ Ingress gateways installed"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"✔ Addons installed"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"✔ Installation complete"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們要一直等到"},{"type":"codeinline","content":[{"type":"text","text":"istio-system"}]},{"type":"text","text":"命名空間中的所有Pod均處於running狀態。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl get pods -n istio-system\n\nNAME READY STATUS RESTARTS AGE\ngrafana-b54bb57b9-fj6qk 1\/1 Running 2 171d\nistio-egressgateway-68587b7b8b-m5b58 1\/1 Running 2 171d\nistio-ingressgateway-55bdff67f-jrhpk 1\/1 Running 2 171d\nistio-tracing-9dd6c4f7c-9gcx9 1\/1 Running 3 171d\nistiod-76bf8475c-xphgd 1\/1 Running 2 171d\nkiali-d45468dc4-4nbl4 1\/1 Running 2 171d\nprometheus-74d44d84db-86hdr 2\/2 Running 4 171d\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了發揮Istio的所有功能,網格中的Pod必須運行一個Istio sidecar代理。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們有兩種方式將Istio sidecar注入到Pod中:使用"},{"type":"codeinline","content":[{"type":"text","text":"istioctl"}]},{"type":"text","text":"命令手動注入或者在將Pod部署到配置好的命名空間時自動注入。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了簡單起見,我們通過執行如下命令,爲"},{"type":"codeinline","content":[{"type":"text","text":"default"}]},{"type":"text","text":"命名空間配置默認的自動化sidecar注入:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"kubectl label namespace default istio-injection=enabled"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"namespace\/default labeled"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,Istio已經安裝到了Kubernetes集羣中,並且爲在"},{"type":"codeinline","content":[{"type":"text","text":"default"}]},{"type":"text","text":"命名空間使用做好了準備。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在下面的章節中,我們將會看到如何“Istio化”應用並部署一個這樣的應用。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"應用概覽"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"應用是由兩個服務組成的,分別是book service和rating service。Book service返回一本圖書的信息及其評分。Rating service返回給定圖書的評分。我們有rating service的兩個版本:v1會爲所有的圖書返回一個固定的評分(也就是1),而v2會返回一個隨機的評分值。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/7image018-1624026735202.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"部署"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲已經啓用了sidecar注入,我們不需要對Kubernetes部署文件做任何變更。接下來,我們將這三個服務部署到“Istio化”的命名空間中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"舉例來說,_book service_的部署文件如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"---\napiVersion: v1\nkind: Service\nmetadata:\n labels:\n app.kubernetes.io\/name: book-service\n app.kubernetes.io\/version: v1.0.0\n name: book-service\nspec:\n ports:\n - name: http\n port: 8080\n targetPort: 8080\n selector:\n app.kubernetes.io\/name: book-service\n app.kubernetes.io\/version: v1.0.0\n type: LoadBalancer\n---\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n labels:\n app.kubernetes.io\/name: book-service\n app.kubernetes.io\/version: v1.0.0\n name: book-service\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io\/name: book-service\n app.kubernetes.io\/version: v1.0.0\n template:\n metadata:\n labels:\n app.kubernetes.io\/name: book-service\n app.kubernetes.io\/version: v1.0.0\n spec:\n containers:\n - env:\n - name: KUBERNETES_NAMESPACE\n valueFrom:\n fieldRef:\n fieldPath: metadata.namespace\n image: quay.io\/lordofthejars\/book-service:v1.0.0\n imagePullPolicy: Always\n name: book-service\n ports:\n - containerPort: 8080\n name: http\n protocol: TCP\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以看到,在文件中既沒有Istio相關的內容,也沒有sidecar容器的配置。Istio功能的注入默認會自動進行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們把應用部署到Kubernetes集羣中:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl apply -f rating-service\/src\/main\/kubernetes\/service.yml -n default\nkubectl apply -f rating-service\/src\/main\/kubernetes\/deployment-v1.yml -n default\nkubectl apply -f rating-service\/src\/main\/kubernetes\/deployment-v2.yml -n default\nkubectl apply -f book-service\/src\/main\/kubernetes\/deployment.yml -n default\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"幾秒鐘之後,應用就會啓動起來了。爲了進行校驗,我們運行如下的命令並觀察Pod所擁有的容器數量:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl get pods -n default\n\nNAME READY STATUS RESTARTS AGE\nbook-service-5cc59cdcfd-5qhb2 2\/2 Running 0 79m\nrating-service-v1-64b67cd8d-5bfpf 2\/2 Running 0 63m\nrating-service-v2-66b55746d-f4hpl 2\/2 Running 0 63m\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意,每個Pod都包含了兩個正在運行的容器,其中一個是服務本身,另外一個是Istio代理。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果描述這個Pod的話,我們會發現:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl describe pod rating-service-v2-66b55746d-f4hpl\n\nName: rating-service-v2-66b55746d-f4hpl\nNamespace: default\n…\nContainers:\n rating-service:\n Container ID: docker:\/\/cda8d72194ee37e146df7bf0a6b23a184b5bfdb36fed00d2cc105daf6f0d6e85\n Image: quay.io\/lordofthejars\/rating-service:v2.0.0\n…\n istio-proxy:\n Container ID: docker:\/\/7f4a9c1f425ea3a06ccba58c74b2c9c3c72e58f1d805f86aace3d914781e0372\n Image: docker.io\/istio\/proxyv2:1.6.13\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲我們使用了Minikube並且Kubernetes服務是LoadBalancer類型,所以要訪問應用需要Minikube的 IP和服務端口。爲了找到這些值,可以執行如下命令:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"minikube IP -p istio\n192.168.99.116\n\nkubectl get services -n default\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\nbook-service LoadBalancer 10.106.237.42 <pending> 8080:31304\/TCP 111m\nkubernetes ClusterIP 10.96.0.1 <none> 443\/TCP 132m\nrating LoadBalancer 10.109.106.128 <pending> 8080:31216\/TCP 95m\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來,我們可以對服務執行curl命令:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"curl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\ncurl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":3}\ncurl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\ncurl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":3}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從輸出我們可以看到評分值的變化,也就是對於同一個圖書的id,評分值會在1和3之間變化。默認情況下,Istio會使用round-robin方式平衡對服務的調用。在本例中,請求會在"},{"type":"codeinline","content":[{"type":"text","text":"rating:v1"}]},{"type":"text","text":"(返回固定的評分值1)和"},{"type":"codeinline","content":[{"type":"text","text":"rating:v2"}]},{"type":"text","text":"(在啓動的時候進行隨機的評分計算,在本例中,會對ID爲1的圖書返回3)之間進行平衡。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"應用現在已經部署好了,並且實現了“Istio化”,但是到目前爲止還沒有啓用任何的微服務特性。我們首先來創建一些Istio資源,以便於在Istio代理容器上啓用和配置微服務特性。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Istio微服務特性"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"服務發現"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"Kubernetes Service_實現了服務發現的理念。它提供了一種方式將一組_Kubernetes Pod"},{"type":"text","text":"(作爲一個整體)賦予一個穩定的虛擬IP和DNS名。Pod在訪問其他Pod的時候,可以使用_Kubernetes Service_名作爲主機名。這隻能允許我們實現基本的服務發現策略,但是我們可能會需要更高級的發現\/部署策略,比如金絲雀發佈、灰度發佈或者鏡像流量(shadowing traffic),此時Kubernetes Service就愛莫能助了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Istio能夠讓我們很容易地控制服務之間的網絡流量,這是通過兩個概念來實現的,即"},{"type":"codeinline","content":[{"type":"text","text":"DestinationRule"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"VirtualService"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"DestinationRule"}]},{"type":"text","text":"定義了在路由發生之後如何爲網絡流量提供服務的策略。在destination rule中我們可以配置的內容如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"網絡流量策略"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"負載均衡策略"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"連接池設置"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"mTLS"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"回彈性"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用標籤(label)指定服務的子集(subset),這些子集會在"},{"type":"codeinline","content":[{"type":"text","text":"VirtualService"}]},{"type":"text","text":"中用到。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們創建一個名爲"},{"type":"codeinline","content":[{"type":"text","text":"destination-rule-v1-v2.yml"}]},{"type":"text","text":"的文件來註冊兩個子集,其中一個用於_rating service v1_,另外一個用於_rating service v2_:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"apiVersion: networking.istio.io\/v1alpha3\nkind: DestinationRule\nmetadata:\n name: rating\nspec:\n host: rating\n subsets:\n - labels:\n app.kubernetes.io\/version: v1.0.0\n name: version-v1\n - labels:\n app.kubernetes.io\/version: v2.0.0\n name: version-v2\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這裏,我們將"},{"type":"codeinline","content":[{"type":"text","text":"host"}]},{"type":"text","text":"字段設置爲rating,因爲這是在_Kubernetes Service_中定義的DNS名。隨後,在"},{"type":"codeinline","content":[{"type":"text","text":"subsets"}]},{"type":"text","text":"部分,我們以"},{"type":"codeinline","content":[{"type":"text","text":"labels"}]},{"type":"text","text":"集的形式定義了多個子集,並將它們分組到一個“虛擬的”"},{"type":"codeinline","content":[{"type":"text","text":"name"}]},{"type":"text","text":"。例如,在前面的例子中,我們定義了兩個組,其中一個組用於rating service的version 1,另外一個組用於version 2。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl apply -f src\/main\/kubernetes\/destination-rule-v1-v2.yml -n default\ndestinationrule.networking.istio.io\/rating created\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"VirtualService"}]},{"type":"text","text":"能夠讓我們配置請求該如何路由至Istio服務網格的服務中。藉助virtual service,實現像A\/B測試、藍\/綠部署、金絲雀發佈或灰度發佈這樣的策略就會變得非常簡單。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們創建一個名爲"},{"type":"codeinline","content":[{"type":"text","text":"virtual-service-v1.yml"}]},{"type":"text","text":"的文件以發送所有的流量到v1:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"apiVersion: networking.istio.io\/v1alpha3\nkind: VirtualService\nmetadata:\n name: rating\nspec:\n hosts:\n - rating\n http:\n - route:\n - destination:\n host: rating\n subset: version-v1\n weight: 100\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在前面的文件中,我們配置所有到達rating主機的請求都會被髮送到version-v1子集所屬的Pod中。我們需要記住,子集是在"},{"type":"codeinline","content":[{"type":"text","text":"DestinationRule"}]},{"type":"text","text":"文件中創建的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl apply -f src\/main\/kubernetes\/virtual-service-v1.yml -n default\nvirtualservice.networking.istio.io\/rating created\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,我們可以再次向服務執行一些"},{"type":"codeinline","content":[{"type":"text","text":"curl"}]},{"type":"text","text":"命令,但是在輸出方面最大的差異在於所有的請求都發送到了_rating v1_中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"curl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\ncurl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\ncurl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"顯然,我們可以創建另外一個virtual service文件,使其指向rating v2:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"apiVersion: networking.istio.io\/v1alpha3\nkind: VirtualService\nmetadata:\n name: rating\nspec:\n hosts:\n - rating\n http:\n - route:\n - destination:\n host: rating\n subset: version-v2\n weight: 100\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl apply -f src\/main\/kubernetes\/virtual-service-v2.yml -n default\nvirtualservice.networking.istio.io\/rating configured\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這樣,所有的流量會發送至_rating_ v2:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"curl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":3}\ncurl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":3}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,"},{"type":"codeinline","content":[{"type":"text","text":"rating"}]},{"type":"text","text":"字段沒有被設置爲1,這是因爲所有的請求都被version 2處理了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過修改virtual service的"},{"type":"codeinline","content":[{"type":"text","text":"weight"}]},{"type":"text","text":"字段,我們就能實現"},{"type":"link","attrs":{"href":"https:\/\/www.getambassador.io\/docs\/edge-stack\/latest\/topics\/using\/canary\/","title":"","type":null},"content":[{"type":"text","text":"金絲雀發佈"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"apiVersion: networking.istio.io\/v1alpha3\nkind: VirtualService\nmetadata:\n name: rating\nspec:\n hosts:\n - rating\n http:\n - route:\n - destination:\n host: rating\n subset: version-v1\n weight: 75\n - destination:\n host: rating\n subset: version-v2\n weight: 25\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl apply -f src\/main\/kubernetes\/virtual-service-v1-v2-75-25.yml -n default\nvirtualservice.networking.istio.io\/rating configured\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,我們對應用執行一些"},{"type":"codeinline","content":[{"type":"text","text":"curl"}]},{"type":"text","text":"命令:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"curl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\ncurl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\ncurl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\ncurl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":3}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"rating v1的訪問次數要比rating v2更多,這遵循了在"},{"type":"codeinline","content":[{"type":"text","text":"weight"}]},{"type":"text","text":"字段中設置的佔比。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,我們移除virtual service資源,使其回到默認的行爲(也就是round-robin策略):"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl delete -f src\/main\/kubernetes\/virtual-service-v1-v2-75-25.yml -n default\nvirtualservice.networking.istio.io \"rating\" deleted\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"回彈性"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在微服務架構中,我們在開發時要始終考慮到可能出現的故障,在與其他的服務進行通信時更是如此。在單體應用中,我們的應用會作爲一個整體,要麼全部處於可用狀態,要麼全部處於宕機狀態,但是在微服務架構中,情況卻並非如此,因爲有些服務是可用的,而另外一些則可能已經宕機了。回彈性(或稱爲應用回彈性)是指一個應用\/服務能夠對面臨的問題作出反應的能力,在出現問題的時候,依然能夠提供儘可能最好的結果。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來我們看一下Istio如何幫助我們實現回彈性策略,以及如何配置它們。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"故障"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"rating service實現了一個特殊的端點,當它被訪問後會導致服務開始返回503 HTTP錯誤碼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"執行如下的命令(將Pod名替換爲你自己的),使服務rating v2在訪問的時候開始出現故障::"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl get pods -n default\n\nNAME READY STATUS RESTARTS AGE\nbook-service-5cc59cdcfd-5qhb2 2\/2 Running 4 47h\nrating-service-v1-64b67cd8d-5bfpf 2\/2 Running 4 47h\nrating-service-v2-66b55746d-f4hpl 2\/2 Running 4 47h\n\nkubectl exec -ti rating-service-v2-66b55746d-f4hpl -c rating-service -n default curl localhost:8080\/rate\/misbehave\n\nRatings endpoint returns 503 error.\n"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"重試"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前,Istio配置爲沒有virtual service,這意味着它會在兩個版本之間平衡請求。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們發送一些請求並校驗rating v2會失敗:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"curl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\n\ncurl 192.168.99.116:31304\/book\/1\n\ncurl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中有個請求沒有產生響應,這是因爲_rating v2_沒有返回合法的響應,而是產生了錯誤。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Istio支持重試,這是通過在"},{"type":"codeinline","content":[{"type":"text","text":"VirtualService"}]},{"type":"text","text":"資源中進行配置實現的。創建名爲"},{"type":"codeinline","content":[{"type":"text","text":"virutal-service-retry.yml"}]},{"type":"text","text":"的文件,其內容如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"apiVersion: networking.istio.io\/v1alpha3\nkind: VirtualService\nmetadata:\n name: rating\nspec:\n hosts:\n - rating\n http:\n - route:\n - destination:\n host: rating\n retries:\n attempts: 2\n perTryTimeout: 5s\n retryOn: 5xx\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"按照配置,如果rating service(不管哪個版本)返回"},{"type":"codeinline","content":[{"type":"text","text":"5XX"}]},{"type":"text","text":" HTTP錯誤碼的話,會自動進行兩次重試。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl apply -f src\/main\/kubernetes\/virtua-service-retry.yml -n default\nvirtualservice.networking.istio.io\/rating created\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來,我們發送一些請求並檢查輸出:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"curl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\n\ncurl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\n\ncurl 192.168.99.116:31304\/book\/1\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":1}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,我們可以看到,所有的請求都是由rating v1響應的。原因很簡單,當對rating service的請求發送至v1,會得到一個合法的響應。但是,如果請求被髮送到v2的時候,會出現錯誤並且會自動執行重試。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲調用是在兩個服務之間進行負載均衡的,所以重試請求會被髮送到v1,從而產生一個合法的響應。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於這樣的原因,上述的所有請求都會返回來自v1的響應。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"斷路器"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於處理網絡故障或偶爾出現的錯誤來說,自動重試是一個很好的方式,但是如果多個併發用戶向一個具有自動重試功能的故障系統發送請求時,會發生什麼呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們通過使用"},{"type":"link","attrs":{"href":"https:\/\/github.com\/JoeDog\/siege","title":"","type":null},"content":[{"type":"text","text":"Siege"}]},{"type":"text","text":"(一個HTTP負載測試工具)模擬這個場景,但首先,我們使用kubectl命令來探查一下rating v2的日誌:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl get pods -n default\n\nNAME READY STATUS RESTARTS AGE\nbook-service-5cc59cdcfd-5qhb2 2\/2 Running 4 47h\nrating-service-v1-64b67cd8d-5bfpf 2\/2 Running 4 47h\nrating-service-v2-66b55746d-f4hpl 2\/2 Running 4 47h\n\nkubectl logs rating-service-v2-66b55746d-f4hpl -c rating-service -n default\n\n…\nRequest 31\nRequest 32\nRequest 33\nRequest 34\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些日誌行展示了該服務所處理的請求數。目前,該服務處理了34個請求。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了模擬四個併發用戶,並且每個用戶發送十個請求到應用上,我們可以執行如下的siege命令:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"siege -r 10 -c 4 -v -d 1 192.168.99.116:31304\/book\/1\n\nHTTP\/1.1 200 0.04 secs: 39 bytes ==> GET \/book\/1\nHTTP\/1.1 200 0.03 secs: 39 bytes ==> GET \/book\/1\n\nTransactions: 40 hits\nAvailability: 100.00 %\nElapsed time: 0.51 secs\nData transferred: 0.00 MB\nResponse time: 0.05 secs\nTransaction rate: 78.43 trans\/sec\nThroughput: 0.00 MB\/sec\nConcurrency: 3.80\nSuccessful transactions: 40\nFailed transactions: 0\nLongest transaction: 0.13\nShortest transaction: 0.01\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然,這裏沒有錯誤發送給調用者,這是因爲有自動重試機制,但是我們再次探測一下rating v2的日誌:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl logs rating-service-v2-66b55746d-f4hpl -c rating-service -n default\n\n…\nRequest 56\nRequest 57\nRequest 58\nRequest 59\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"儘管rating v2不能產生一個合法的響應,但是服務依然被訪問了25次,這會對應用產生很大的影響,因爲:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"如果服務已經處於過載狀態的話,發送更多的請求對它的恢復來講並不是一個好主意。也許,最好的方式是將實例放到一個隔離區中。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"如果服務此時恰好因爲某個缺陷出現了故障,那麼重試並不會改善這種情況。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"對於每次重試,都會建立一個socket、分配一些文件描述符(file descriptor),還要通過網絡發送一些數據包,但最終得到的卻是故障。這個過程會影響在同一個節點中其他服務(CPU、內存、文件描述符等)或者網絡(增加無用的流量、延遲等)。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了解決這個問題,我們需要有一種方式能夠在出現重複執行失敗的時候,讓調用能夠自動地快速失敗。"},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/Circuit_breaker_design_pattern","title":"","type":null},"content":[{"type":"text","text":"斷路器(circuit breaker)"}]},{"type":"text","text":"設計模式和艙壁(bulkhead)模式是這個問題的解決方案。前者提供了在遇到併發錯誤的時候,快速失敗的策略,而後者則能限制併發執行的數量。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,創建一個名爲"},{"type":"codeinline","content":[{"type":"text","text":"destination-rule-circuit-breaker.yml"}]},{"type":"text","text":"的文件,內容如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"apiVersion: networking.istio.io\/v1alpha3\nkind: DestinationRule\nmetadata:\n name: rating\nspec:\n host: rating\n subsets:\n - labels:\n version: v1\n name: version-v1\n - labels:\n version: v2\n name: version-v2\n trafficPolicy:\n connectionPool:\n http:\n http1MaxPendingRequests: 3\n maxRequestsPerConnection: 3\n tcp:\n maxConnections: 3\n outlierDetection:\n baseEjectionTime: 3m\n consecutive5xxErrors: 1\n interval: 1s\n maxEjectionPercent: 100\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們要注意的第一件事情就是"},{"type":"codeinline","content":[{"type":"text","text":"DestinationRule"}]},{"type":"text","text":"配置了斷路器。除了配置斷路器之外,子集也需要指定。對併發連接的限制是在"},{"type":"codeinline","content":[{"type":"text","text":"connectionPool"}]},{"type":"text","text":"字段中實現的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要配置斷路器,我們需要使用"},{"type":"codeinline","content":[{"type":"text","text":"outlierDetection"}]},{"type":"text","text":"。就本例而言,如果在一秒鐘的時間窗口中發生了一次錯誤,斷路器將會打開,使服務暫時跳閘(trip)三分鐘。在這個時間之後,斷路器會處於半開狀態,這意味着會執行真實的邏輯。如果再次失敗的話,斷路器會保持打開的狀態,否則的話,它將會關閉。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl apply -f src\/main\/kubernetes\/destination-rule-circuit-breaker.yml\ndestinationrule.networking.istio.io\/rating configured\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們已經在Istio中配置完了斷路器模式,接下來,我們再次執行"},{"type":"codeinline","content":[{"type":"text","text":"siege"}]},{"type":"text","text":"命令並探查_rating v2_ v2的日誌。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"siege -r 10 -c 4 -v -d 1 192.168.99.116:31304\/book\/1\n\nHTTP\/1.1 200 0.04 secs: 39 bytes ==> GET \/book\/1\nHTTP\/1.1 200 0.03 secs: 39 bytes ==> GET \/book\/1\n\nTransactions: 40 hits\nAvailability: 100.00 %\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再次探查日誌。注意,在前面的運行中,我們已經到了Request 59。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl logs rating-service-v2-66b55746d-f4hpl -c rating-service -n default\n\n…\nRequest 56\nRequest 57\nRequest 58\nRequest 59\nRequest 60\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"_Rating v2 _只接收到了一個請求,因爲在第一次處理請求的時候返回了錯誤,斷路器就會打開,因此不會有更多的請求發送到rating v2上。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,我們已經看到了如何使用Istio實現回彈性。在這裏,我們並沒有在服務中實現相關的邏輯,將其與業務邏輯混在一起,而是讓sidecar容器實現了這些邏輯。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後,執行如下的命令,讓rating v2服務回到之前的狀態。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl exec -ti rating-service-v2-66b55746d-f4hpl -c rating-service curl localhost:8080\/rate\/behave\nBack to normal\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"認證"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在實現微服務架構的時候,我們可能會發現的一個問題就是如何保護內部服務之間的通信。我們是不是要使用mTLS?是不是要對請求進行認證?是否要對請求進行鑑權?所有這些問題的答案都是肯定的!接下來,我們將會一步一步地看一下Istio是如何幫助我們實現這些功能的。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"認證"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Istio會自動將代理和工作負載之間的所有網絡流量升級爲mTLS,這個過程不需要修改任何的服務代碼。與此同時,作爲開發人員,我們會使用HTTP協議實現服務。當服務被“Istio化”的時候,服務之間的通信會採用HTTPS。Istio會負責管理證書,擔任證書頒發機構並撤銷\/更新證書。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要校驗mTLS是否已啓用,我們可以使用istioctl工具執行如下的命令:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"istioctl experimental authz check book-service-5cc59cdcfd-5qhb2 -a\n\nLISTENER[FilterChain] HTTP ROUTE ALPN mTLS (MODE) AuthZ (RULES)\n\n...\nvirtualInbound[5] inbound|8080|http|book-service.default.svc.cluster.local istio,istio-http\/1.0,istio-http\/1.1,istio-h2 noneSDS: default yes (PERMISSIVE) no (none)\n\n…\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"book-service託管在了8080端口,並且以permissive策略配置了mTLS。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"授權"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來,我們看一下如何使用JSON Web Token("},{"type":"link","attrs":{"href":"https:\/\/jwt.io\/","title":"","type":null},"content":[{"type":"text","text":"JWT"}]},{"type":"text","text":")格式啓用Istio的終端用戶認證。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們要做的第一件事情是應用一個"},{"type":"codeinline","content":[{"type":"text","text":"RequestAuthentication"}]},{"type":"text","text":"資源。這個策略能夠確保如果"},{"type":"codeinline","content":[{"type":"text","text":"Authorization"}]},{"type":"text","text":"頭信息包含JWT token的話,它必須是合法的、沒有過期的、由正確的用戶頒發的並且沒有被篡改。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"apiVersion: \"security.istio.io\/v1beta1\"\nkind: \"RequestAuthentication\"\nmetadata:\n name: \"bookjwt\"\n namespace: default\nspec:\n selector:\n matchLabels:\n app.kubernetes.io\/name: book-service\n jwtRules:\n - issuer: \"[email protected]\"\n jwksUri: \"https:\/\/gist.githubusercontent.com\/lordofthejars\/7dad589384612d7a6e18398ac0f10065\/raw\/ea0f8e7b729fb1df25d4dc60bf17dee409aad204\/jwks.json\"\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中的關鍵字段包括:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"issuer"}]},{"type":"text","text":":token的合法頒發者。如果所提供的token沒有在"},{"type":"codeinline","content":[{"type":"text","text":"iss"}]},{"type":"text","text":" JWT字段指定該頒發者,那麼這個token就是非法的。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"jwksUri"}]},{"type":"text","text":":"},{"type":"codeinline","content":[{"type":"text","text":"jwks"}]},{"type":"text","text":"文件的URL,它指定了公鑰註冊的地址,用來校驗token的簽名。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl apply -f src\/main\/kubernetes\/request-authentication-jwt.yml -n default\nrequestauthentication.security.istio.io\/bookjwt created\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們現在使用一個非法的token來運行"},{"type":"codeinline","content":[{"type":"text","text":"curl"}]},{"type":"text","text":"命令:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"curl 192.168.99.116:31304\/book\/1 -H \"Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUU\"\n\nJwt verification fails\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲token是非法的,所以請求會被拒絕,並返回HTTP\/1.1 401 Unauthorized狀態碼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用合法的token重複前面的請求:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"curl 192.168.99.116:31304\/book\/1 -H \"Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUg\"\n\n{\"bookId\":1,\"name\":\"Book 1\",\"rating\":3}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,我們可以看到一個合法的響應了,因爲此時token是正確的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"到目前爲止,我們只是認證了請求(只需要一個合法的token),其實Istio還支持基於角色訪問控制(role-based access control,RBAC)模型的授權。我們接下來創建一個"},{"type":"codeinline","content":[{"type":"text","text":"AuthorizationPolicy"}]},{"type":"text","text":"策略,只允許具有合法JSON Web Token並且claim role設置爲customer的請求。創建名爲"},{"type":"codeinline","content":[{"type":"text","text":"authorization-policy-jwt.yml"}]},{"type":"text","text":"的文件:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"apiVersion: security.istio.io\/v1beta1\nkind: AuthorizationPolicy\nmetadata:\n name: require-jwt\n namespace: default\nspec:\n selector:\n matchLabels:\n app.kubernetes.io\/name: book-service\n action: ALLOW\n rules:\n - from:\n - source:\n requestPrincipals: [\"[email protected]\/[email protected]\"]\n when:\n - key: request.auth.claims[role]\n values: [\"customer\"]\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl apply -f src\/main\/kubernetes\/authorization-policy-jwt.yml\nauthorizationpolicy.security.istio.io\/require-jwt created\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後執行和上面一樣的curl命令:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"curl 192.168.99.116:31304\/book\/1 -H \"Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUg\"\n\nRBAC: access denied\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這一次的響應顯然不一樣了。儘管token是合法的,但是訪問被拒絕了,這是因爲token中並沒有值爲customer的claim role。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後,我們使用如下的token:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/7image020-1624051579986.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"curl 192.168.99.116:31304\/book\/1 -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjI1NDkwNTY4ODgsImlhdCI6MTU0OTA1Njg4OSwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJyb2xlIjoiY3VzdG9tZXIiLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.VM9VOHD2NwDjQ6k7tszB3helfAn5wcldxe950BveiFVg43pp7x5MWTjMtWQRmQc7iYul19PXsmGnSSOiQQobxdn2UnhHJeKeccCdX5YVgX68tR0R9xv_wxeYQWquH3roxHh2Xr2SU3gdt6s7gxKHrW7Zc4Z9bT-fnz3ijRUiyrs-HQN7DBc356eiZy2wS7O539lx3mr-pjM9PQtcDCDOGsnmwq1YdKw9o2VgbesfiHDDjJQlNv40wnsfpq2q4BgSmdsofAGwSNKWtqUE6kU7K2hvV2FvgwjzcB19bbRYMWxRG0gHyqgFy-uM5tsC6Cib-gPAIWxCdXDmLEiqIdjM3w""}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"{\"bookId\":1,\"name\":\"Book 1\",\"rating\":3}"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,我們看到了一個合法的響應,因爲此時token是正確的並且包含了一個合法的role值。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"可觀察性"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Istio自帶了四個組件以適應可觀察性的需求:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/prometheus.io\/","title":"","type":null},"content":[{"type":"text","text":"Prometheus"}]},{"type":"text","text":":用於監控。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/grafana.com\/","title":"","type":null},"content":[{"type":"text","text":"Grafana"}]},{"type":"text","text":":用於可視化。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/www.jaegertracing.io\/","title":"","type":null},"content":[{"type":"text","text":"Jaeger"}]},{"type":"text","text":" + "},{"type":"link","attrs":{"href":"https:\/\/zipkin.io\/","title":"","type":null},"content":[{"type":"text","text":"Zipkin"}]},{"type":"text","text":":用於跟蹤。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/kiali.io\/","title":"","type":null},"content":[{"type":"text","text":"Kiali"}]},{"type":"text","text":":用於爲應用提供一個全局的概覽。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以在"},{"type":"codeinline","content":[{"type":"text","text":"istio-system"}]},{"type":"text","text":"命名空間中看到所有的Pod:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl get pods -n istio-system\nNAME READY STATUS RESTARTS AGE\n\ngrafana-b54bb57b9-k5qbm 1\/1 Running 0 178m\nistio-egressgateway-68587b7b8b-vdr67 1\/1 Running 0 178m\nistio-ingressgateway-55bdff67f-hlnqw 1\/1 Running 0 178m\nistio-tracing-9dd6c4f7c-44xhk 1\/1 Running 0 178m\nistiod-76bf8475c-xphgd 1\/1 Running 7 177d\nkiali-d45468dc4-fl8j4 1\/1 Running 0 178m\nprometheus-74d44d84db-zmkd7 2\/2 Running 0 178m\n"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"監控"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Istio集成了"},{"type":"link","attrs":{"href":"https:\/\/prometheus.io\/","title":"","type":null},"content":[{"type":"text","text":"Prometheus"}]},{"type":"text","text":",用於發送與網絡流量和服務相關的各種信息。除此之外,它還提供了一個"},{"type":"link","attrs":{"href":"https:\/\/grafana.com\/grafana\/","title":"","type":null},"content":[{"type":"text","text":"Grafana"}]},{"type":"text","text":"實例來可視化所有收集到的數據。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要訪問Grafana,我們可以使用port-forward命令來將Pod暴露出來:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl port-forward -n istio-system grafana-b54bb57b9-k5qbm 3000:3000\nForwarding from 127.0.0.1:3000 -> 3000\nForwarding from [::1]:3000 -> 3000\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"打開瀏覽器並導航至"},{"type":"codeinline","content":[{"type":"text","text":"locahost:3000"}]},{"type":"text","text":"以訪問Grafana的儀表盤。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/4image022-1624051579986.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/kiali.io\/","title":"","type":null},"content":[{"type":"text","text":"Kiali"}]},{"type":"text","text":"是另外一個在Istio中運行的工具,它能夠管理Istio並觀察服務網格參數,比如服務是如何連接的、它們是如何執行的以及Istio資源是如何註冊的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要訪問Kiali,我們可以使用port-forward命令來將Pod暴露出來:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"kubectl port-forward -n istio-system kiali-d45468dc4-fl8j4 20001:20001\nForwarding from 127.0.0.1:20001 -> 20001\nForwarding from [::1]:20001 -> 20001\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"打開瀏覽器,訪問Istio儀表盤,然後導航至locahost:20001。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/2image024-1624051579986.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"跟蹤"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"跟蹤用來可視化一個程序的流程和數據進展。Istio會攔截所有的請求\/響應,並將它們發送至"},{"type":"link","attrs":{"href":"https:\/\/www.jaegertracing.io\/","title":"","type":null},"content":[{"type":"text","text":"Jaeger"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這裏,我們可以不用port-forward命令,而是使用"},{"type":"codeinline","content":[{"type":"text","text":"istioctl"}]},{"type":"text","text":"來暴露端口並自動打開頁面。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"istioctl dashboard jaeger"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/microservicilities-istio\/en\/resources\/3image026-1624051579986.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"結論"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開發和實現微服務架構要比開發單體應用更具挑戰性。我們相信,微服務特性能夠促使你在應用基礎設施方面正確地開發服務。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Istio在一個sidecar容器中實現了一些微服務特性,使得它們能夠跨所有的服務進行重用,獨立於應用所使用的編程語言。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除此之外,Istio方式能夠讓我們在不重新部署服務的前提下改變服務的行爲。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你計劃開發微服務並將它們部署到Kubernetes中,那麼Istio是一個切實可行的方案,因爲它能夠與Kubernetes無縫集成。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文中所用到的源碼可以在GitHub的"},{"type":"link","attrs":{"href":"https:\/\/github.com\/lordofthejars\/rating-service\/tree\/istio","title":"","type":null},"content":[{"type":"text","text":"倉庫"}]},{"type":"text","text":"中找到,本系列"},{"type":"link","attrs":{"href":"https:\/\/www.infoq.cn\/article\/MBAYoWrjCOAJK5QuqbcQ","title":"","type":null},"content":[{"type":"text","text":"第一篇文章"}]},{"type":"text","text":"的源碼也可以在GitHub的"},{"type":"link","attrs":{"href":"https:\/\/github.com\/lordofthejars\/microservicilities-quarkus","title":"","type":null},"content":[{"type":"text","text":"倉庫"}]},{"type":"text","text":"中找到。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"作者簡介:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Alex Soto"},{"type":"text","text":"是紅帽公司的開發者體驗總監。他對Java領域、軟件自動化充滿熱情,他相信開源軟件模式。Soto是"},{"type":"link","attrs":{"href":"https:\/\/www.manning.com\/books\/testing-java-microservices","title":"","type":null},"content":[{"type":"text","text":"Manning的《Testing Java Microservices》"}]},{"type":"text","text":"和"},{"type":"link","attrs":{"href":"https:\/\/www.oreilly.com\/library\/view\/quarkus-cookbook\/9781492062646\/","title":"","type":null},"content":[{"type":"text","text":"O’Reilly的《Quarkus Cookbook》"}]},{"type":"text","text":"兩本書的共同作者,他還是多個開源項目的貢獻者。自2017年以來,他一直是Java Champion,是國際演講者和Salle URL大學的教師。你可以在Twitter上關注他("},{"type":"link","attrs":{"href":"https:\/\/twitter.com\/alexsotob","title":"","type":null},"content":[{"type":"text","text":"Alex Soto ⚛"}]},{"type":"text","text":"️),隨時瞭解Kubernetes和Java領域的動態。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"原文鏈接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/www.infoq.com\/articles\/microservicilities-istio\/","title":null,"type":null},"content":[{"type":"text","text":"Implementing Microservicilites with Istio"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章