1 Istio介紹
1.1 Istio介紹
官方文檔:https://istio.io/docs/concepts/what-is-istio/ 中文官方文檔:https://istio.io/zh/docs/concepts/what-is-istio/ Github地址:https://github.com/istio/istio/releases
官當解釋:
An open platform to connect, secure, control and observe services.
翻譯過來,就是連接、安全加固、控制和觀察服務的開放平台 。 開放平台就是指它本身是開源的,服務對應的是微服務,也可以粗略地理解為單個應用。
-
連接( Connect ):智能控制服務之間的調用流量,能夠實現灰度升級、 AB 測試和 藍綠 部署等功能
-
安全加固( Secure ):自動為服務之間的調用提供認證、授權和加密。
-
控制( Control ):應用用戶定義的 policy ,保證資源在消費者中公平分配。
-
觀察( Observe ):查看服務運行期間的各種數據,比如日志、監控和 tracing ,了解服務的運行情況。
Istio是 ServiceMesh 的產品化落地, 可以通過在現有 的 服務器新增部署邊車代理 (sidecar-proxy),應用程序不用改代碼 或者只需要改很少的代碼,就能實現 如下 基礎功能
-
幫助微服務之間建立連接,幫助研發團隊更好的管理與監控微服務,並使得系統架構更加安全
-
幫助微服務分層解耦,解耦后的 proxy 層能夠更加專注於提供基礎架構能力,例如:
-
服務發現 (discovery)
-
負載均衡 (load balancing)
-
故障恢復 (failure recovery)
-
服務度量 (metrics)
-
服務監控 (monitoring)
-
A/B 測試 (A/B testing)
-
灰度發布 (canary limiting)
-
限流限速 (rate limiting)
-
訪問控制 (access control)
-
身份認證 (end-to-end authentication)
-
1)服務注冊和發現
RPC:RPC Remote Procedure Call )遠程過程調用,簡單的理解是一個節點請求另一個節點提供的服務
2)負載均衡
把前端的請求分發到后台多個服務器
3)故障恢復
出現故障具備自恢復的能力
4)服務度量
對於HTTP HTTP/2 和 GRPC 流量, Istio 生成以下指標:
-
請求計數( istio_requests_total ):這是一個用於累加每個由 Istio 代理所處理請求的COUNTER 指標。
-
請求持續時間( istio_request_duration_seconds ):這是一個用於測量請求的持續時間的
-
DISTRIBUTION指標。
-
請求大小( istio_request_bytes ):這是一個用於測量 HTTP 請求 body 大小的 DISTRIBUTION指標。
-
響應大小( istio_response_bytes ):這是一個用於測量 HTTP 響應 body 大小的 DISTRIBUTION指標。
對於TCP 流量, Istio 生成以下指標:
-
Tcp 發送字節數( istio_tcp_sent_bytes_total ):這是一個用於測量在 TCP 連接下響應期間發送的總字節數的 COUNTER 指標。
-
Tcp 接收字 節數( istio_tcp_received_bytes_total ):這是一個用於測量在 TCP 連接下請求期間接收的總字節數的 COUNTER 指標。
-
Tcp 打開連接數( istio_tcp_connections_opened_total ):這是一個用於累加每個打開連接的COUNTER 指標。
-
Tcp 關閉連接數 (istio_tcp_connections_closed_total) : 這是一個用於累加每個關閉連接的COUNTER 指標。
5)灰度發布
灰度發布也叫金絲雀發布,起源是,礦井工人發現,金絲雀對瓦斯氣體很敏感,礦工會在下井之 前,先放一只金絲雀到井中,如果金絲雀不叫了,就代表瓦斯濃度高。
在灰度發布開始后,先啟動一個新版本應用,但是並不直接將流量切過來,而是測試人員對新版本進行線上測試,啟動的這個新版本應用,就是我們的金絲雀。如果沒有問題,那么可以將少量的用戶流量導入到新版本上,然后再對新版本做運行狀態觀察,收集各種運行時數據,如果此時對新舊版本做各種數據對比,就是所謂的 A/B 測試。
當確認新版本運行良好后,再逐步將更多的流量導入到新版本 上,在此期間,還可以不斷地調整新舊兩個版本的運行的服務器副本數量,以使得新版本能夠承受越來越大的流量壓力。直到將 100% 的流量都切換到新版本上,最后關閉剩下的老版本服務,完成灰度發布。
如果在灰度發布過程中(灰度期)發現了新版本有問題,就應該立即將流量切回老版本上,這樣,就會將負面影響控制在最小范圍內。
1.2 Istio核心特性
-
流控 (traffic management) 斷路器(circuit breakers)、超時、重試、多路由規則、 AB 測試、灰度發布、按照百分比分配流量等。
-
安全 (security) 加密、身份認證、服務到服務的權限控制、K8S 里容器到容器的權限控制等。
-
可觀察 (observability) 追蹤、監控、數據收集,通過控制后台全面了解上行下行流量,服務鏈路情況,服務運行情況,系統性能情況,國內微服務架構體系,這一塊做得比較缺乏。
-
平台無關系 (platform support) K8s,物理機,自己的虛機都沒問題。
-
集成與定制 (integration and customization) 可定制化擴展功能。
1)斷路器
示例1:舉個生活中的例子 解釋斷路器
當電路發生故障或異常時,伴隨着電流不斷升高,並且升高的電流有可能能損壞電路中的某些重要器件,也有可能燒毀電路甚至造成火災。若電路中正確地安置了保險絲,那么保險絲就會在電流異常升高到一定的高度和熱度的時候,自身熔斷切斷電流,從而起到保護電路安全運行的作用。
斷路器也稱為 服務熔斷,在多個服務調用的時候,服務 A 依賴服務 B ,服務 B 依賴服務 C ,如果服務C 響應時間過長或者不可用,則會讓服務 B 占用太多系統資源,而服務 A 也依賴服 B ,同時也在占用大量的系統資源,造成系統雪崩的情況出現。 Istio 斷路器通過網格中的邊車對流量進行攔截判斷處理,避免了在代碼中侵入控制邏輯,非常方便的就實服務熔斷的能力。
在微服務架構中,在高並發情況下,如果請求數量達到一定極限(可以自己設置閾值),超出了設置的閾值,斷路器會自動開啟服務保護功能,然后通過服務降級的方式返回一個友好的提示給客戶端。假設當10個請求中,有10%失敗時,熔斷器就會打開,此時再調用此服務,將會直接返回失敗,不再調遠程服務。直到10s鍾之后,重新檢測該觸發條件,判斷是否把熔斷器關閉,或者繼續打開。
示例2:服務降級(提高用戶體驗效果)
比如電商平台,在針對618、雙11的時候會有一些秒殺場景,秒殺的時候請求量大,可能會返回報錯標志“當前請求人數多,請稍后重試”等,如果使用服務降級,無法提供服務的時候,消費者會調用降級的操作,返回服務不可用等信息,或者返回提前准備好的靜態頁面寫好的信息。
2)超時
什么時候需要用到超時?
在生產環境中經常會碰到由於調用方等待下游的響應過長,堆積大量的請求阻塞了自身服務,造成雪崩的情況,通過超時處理來避免由於無限期等待造成的故障,進而增強服務的可用性。
示例:
-
nginx服務設置了超時時間為 3 秒,如果超出這個時間就不在等待,返回超時錯誤
-
httpd服務設置了響應時間延遲 5 秒,任何請求都需要等待 5 秒后才能返回
-
client通過訪問 nginx 服務去反向代理 httpd 服務,由於 httpd 服務需要 5 秒后才能返回,但nginx 服務只等待 3 秒,所以客戶端會提示超時錯誤。
3)重試
istio 重試機制就是如果調用服務失敗, Envoy 代理嘗試連接服務的最大次數。而默認情況下,Envoy 代理在失敗后並不會嘗試重新連接服務 。
示例:
客戶端調用nginx,nginx 將請求轉發給 tomcat 。 tomcat 通過故障注入而中止對外服務, nginx設置如果訪問 tomcat 失敗則會重試 3 次。
4)多路由規則
-
HTTP 重定向(HTTPRedirect)
-
HTTP 重寫(HTTPRewrite)
-
HTTP 重試(HTTPRetry)
-
HTTP 故障注入(HTTPFaultInjection)
-
HTTP 跨域資源共享(CorsPolicy)
2 Istio架構
istio服務網格從邏輯上分為數據平面和控制平面。
數據平面由一組以Sidecar方式部署的智能代理(Envoy+Polit-agent)組成。這些代理承載並控制微服務之間的所有網絡通信,管理入口和出口流量,類似於一線員工。 Sidecar 一般和業務容器綁定在一起(在Kubernets中以自動注入的方式注入到到業務pod中),來劫持業務應用容器的流量,並接受控制面組件的控制,同時會向控制面輸出日志、跟蹤及監控數據。
Envoy 和 pilot-agent 打在同一個鏡像中,即sidecar Proxy。
控制平面負責管理和配置代理來路由流量。istio1.5+中使用了一個全新的部署模式,重建了控制平面,將原有的多個組件整合為一個單體結構istiod,這個組件是控制平面的核心,管理Istio的所有功能,主要包括Pilot、Mixer、Citadel等服務組件。
istiod是新版本中最大的變化,以一個單體組件替代了原有的架構,降低了復雜度和維護難度,但原有的多組件並不是被完全移除,而是在重構后以模塊的形式整合在一起組成了istiod。
結合下圖我們來理解Istio的各組件的功能及相互之間的協作方式。
1)自動注入:在創建應用程序時自動注入 Sidecar代理Envoy程序。在 Kubernetes中創建 Pod時,Kube-apiserver調用控制面組件的 Sidecar-Injector服務,自動修改應用程序的描述信息並注入Sidecar。在真正創建Pod時,在創建業務容器的Pod中同時創建Sidecar容器。
2)流量攔截:在Pod初始化時設置iptables 規則,基於配置的iptables規則攔截業務容器的Inbound流量和Outbound流量到Sidecar上。而應用程序感知不到Sidecar的存在,還以原本的方式 進行互相訪問。上圖中,流出frontend服務的流量會被 frontend服務側的 Envoy攔截,而當流量到達forecast容器時,Inbound流量被forecast 服務側的Envoy攔截。
3)服務發現:服務發起方的 Envoy 調用控制面組件 Pilot 的服務發現接口獲取目標服務的實例列表。上圖中,frontend 服務側的 Envoy 通過 Pilot 的服務發現接口得到forecast服務各個實例的地址。
4)負載均衡:服務發起方的Envoy根據配置的負載均衡策略選擇服務實例,並連接對應的實例地址。上圖中,數據面的各個Envoy從Pilot中獲取forecast服務的負載均衡配置,並執行負載均衡動作。
5)流量治理:Envoy 從 Pilot 中獲取配置的流量規則,在攔截到 Inbound 流量和Outbound 流量時執行治理邏輯。上圖中, frontend 服務側的 Envoy 從 Pilot 中獲取流量治理規則,並根據該流量治理規則將不同特征的流量分發到forecast服務的v1或v2版本。
6)訪問安全:在服務間訪問時通過雙方的Envoy進行雙向認證和通道加密,並基於服務的身份進行授權管理。上圖中,Pilot下發安全相關配置,在frontend服務和forecast服務的Envoy上自動加載證書和密鑰來實現雙向認證,其中的證書和密鑰由另一個管理面組件 Citadel維護。
7)服務監測:在服務間通信時,通信雙方的Envoy都會連接管理面組件Mixer上報訪問數據,並通過Mixer將數據轉發給對應的監控后端。上圖中,frontend服務對forecast服務的訪問監控指標、日志和調用鏈都可以通過這種方式收集到對應的監控后端。
8)策略執行:在進行服務訪問時,通過Mixer連接后端服務來控制服務間的訪問,判斷對訪問是放行還是拒絕。上圖中,Mixer 后端可以對接一個限流服務對從frontend服務到forecast服務的訪問進行速率控制等操作。
9)外部訪問:在網格的入口處有一個Envoy扮演入口網關的角 色。上圖中,外部服務通過Gateway訪問入口服務 frontend,對 frontend服務的負載均衡和一些流量治理策略都在這個Gateway上執行。
3 Istio組件詳解
Istio服務組件 有很多 ,從上面的流程中基本能看出每個組件如何協作的,下面具體講解每個組件的具體用途和功能。
3.1Pilot
Pilot是 Istio 的主要控制組件,下發指令控制客戶端。在整個系統中, Pilot 完成以下任務:
-
從 Kubernetes 或者其他平台的注冊中心獲取服務信息,完成服務發現過程。
-
讀取 Istio 的各項控制配置,在進行轉換之后,將其發給數據面進行實施。
Pilot 將配置內容下發給數據面的 Envoy,Envoy 根據 Pilot 指令,將路由、服務、監聽、集群等定義信息轉換為本地配置,完成控制行為的落地。
-
Pilot為Envoy提供服務發現
-
提供流量管理功能(例如,A/B 測試、金絲雀發布等)以及彈性功能(超時、重試、熔斷器等);
-
生成envoy配置
-
啟動envoy
-
監控並管理envoy的運行狀況,比如envoy出錯時pilot-agent負責重啟envoy,或者envoy配置變更后reload envoy
3.2 Envoy
Envoy是用 C++ 開發的高性能代理,用於協調服務網格中所有服務的入站和出站流量。
Envoy有許多強大的功能,例如:
-
動態服務發現
-
負載均衡
-
TLS終端
-
HTTP/2與gRPC代理
-
斷路器
-
健康檢查
-
流量拆分
-
灰度發布
-
1)Istio中 Envoy 與服務關系
為了便於理解Istio 中 Envoy 與服務的關系,下圖為 Envoy 的拓撲圖,如圖所示:
Envoy和 Service A 同屬於一個 Pod ,共享網絡和命名空間 Envoy 代理進出 Pod A 的流量,並將流量按照外部請求的規則作用於 Service A 中。
2)Pilot-agent介紹
-
Envoy不直接跟k8s交互,通過 pilot-agent管理的
-
Pilot-agent進程根據K8S APIserver中的配置信息生成Envoy的配置文件,並負責啟動Envoy進程。
-
Envoy由Pilot-agent進程啟動,啟動后,Envoy讀取Pilot-agent為它生成的配置文件,然后根據該文件的配置獲取到Pilot的地址,通過數據面從pilot拉取動態配置信息,包括路由(route),監聽器(listener),服務集群(cluster)和服務端點(endpoint)。
3.3 Citadel
負責處理系統上不同服務之間的TLS通信。 Citadel充當證書頒發機構(CA),並生成證書以允許在數據平面中進行安全的mTLS通信。
Citadel是 Istio的核心安全組件,提供了自動生 成、分發、輪換與撤銷密鑰和證書功能。Citadel一直監聽 Kube- apiserver,以 Secret的形式為每個服務都生成證書密鑰,並在Pod創建時掛載到Pod上,代理容器使用這些文件來做服務身份認證,進而代 理兩端服務實現雙向TLS認證、通道加密、訪問授權等安全功能。如圖 所示,frontend 服 務對 forecast 服務的訪問用到了HTTP方式,通過配置即可對服務增加認證功能,雙方的Envoy會建立雙向認證的TLS通道,從而在服務間啟用雙向認證的HTTPS。
3.4 Galley
Galley是istio的配置驗證、提取、處理和分發的組件。Galley是提供配置管理的服務。實現原理是通過k8s提供的ValidatingWebhook對配置進行驗證。
Galley使Istio可以與Kubernetes之外的其他環境一起工作,因為它可以將不同的配置數據轉換為Istio可以理解的通用格式。
3.5 Ingressgateway
Ingressgateway 就是入口處的 Gateway,從網格外訪問網格內的服務就是通過這個Gateway進行的。istio-ingressgateway是一個Loadbalancer類型的Service,不同於其他服務組件只有一兩個端 口,istio-ingressgateway 開放了一組端口。
這些就是網格內服務的外部訪問端口。如下圖所示,網格入口網關istio-ingressgateway的負載和網格內的Sidecar是同樣的執行流程,也和網格內的其他 Sidecar一樣從 Pilot處接收流量規則並執行。
3.6 Sidecar injector
Sidecar-injector是負責自動注入的組件,只要開啟了自動注 入,在Pod創建時就會自動調用istio-sidecar-injector向Pod中注入Sidecar 容器。
在 Kubernetes環境下,根據自動注入配置,Kube-apiserver在攔截到 Pod創建的請求時,會調用自動注入服務 istio-sidecar-injector 生成 Sidecar 容器的描述並將其插入原 Pod的定義中,這樣,在創建的 Pod 內除了包括業務容器,還包括 Sidecar容器,這個注入過程對用戶透明。
3.7 其他組件
除了以”istio“ 為前綴的 Istio 自有組件,在集群中一般還安裝 Jaeger agent 、 Jaeger-collector 、 Jaeger-query 、 Kiali 、 Prometheus 、 Grafana 、 Tracing 、 Zipkin 等組件,這些組件提供了 Istio 的調用鏈、監控等功能,可以選擇安裝來完成完整的服務監控管理功能。
4 在Kubernetes集群中安裝Istio
4.1 准備部署環境
1)下載
cd /root/ && wget https://github.com/istio/istio/releases/download/1.11.4/istio-1.11.4-linux-amd64.tar.gz
2)解壓
tar -zxvf istio-1.11.4-linux-amd64.tar.gz && mv istio-1.11.4 /usr/local/kubernetes/
3)添加環境變量
export PATH=/usr/local/kubernetes/istio-1.11.4/bin:$PATH
4)移動客戶端文件
cp -ar /usr/local/kubernetes/istio-1.11.4/bin/istioctl /usr/local/bin/
4.2 安裝Istio
1)執行安裝
istioctl install --set profile=demo -y
注意:執行安裝過程中出現失敗情況,一般都是由於網絡拉取不到鏡像 拉取到鏡像后服務無法啟動,一般是和K8S環境有關,建議使用kubeadm方式安裝實驗
2)查看部署情況
kubectl get pods -n istio-system -o wide
3)卸載Istio集群(需要時才操作)
istioctl manifest generate --set profile=demo | kubectl delete -f -
5 Istio部署演示demo-bookinfo
5.1 功能介紹
該應用由四個單獨的微服務構成,這個應用模仿在線書店的一個分類,顯示一本書的信息,頁面上會顯示一本書的描述,書籍的細節(ISBN、頁數等),以及關於這本書的一些評論。
Bookinfo應用分為四個單獨的微服務
-
productpage這個微服務會調用details和reviews兩個微服務,用來生成頁面;
-
details這個微服務中包含了書籍的信息;
-
reviews這個微服務中包含了書籍相關的評論,它還會調用ratings微服務;
-
ratings這個微服務中包含了由書籍評價組成的評級信息。
reviews微服務有3個版本
-
v1版本不會調用ratings服務;
-
v2版本會調用ratings服務,並使用1到5個黑色星形圖標來顯示評分信息;
-
v3版本會調用ratings服務,並使用1到5個紅色星形圖標來顯示評分信息。
Bookinfo應用中的幾個微服務是由不同的語言編寫的。這些服務對istio並無依賴,但是構成了一個有代表性的服務網格的例子:它由多個服務、多個語言構成,並且reviews服務具有多個版本。
5.2 部署應用
要在Istio中運行這一應用,無需對應用自身做出任何改變。 只要簡單的在 Istio 環境中對服務進行配置和運行,具體一點說就是把 Envoy sidecar 注入到每個服務之中。 最終的部署結果將如下圖所示:
所有的微服務都和Envoy sidecar集成在一起,被集成服務所有的出入流量都被envoy sidecar 所劫持,這樣就為外部控制准備了所需的 Hook,然后就可以利用Istio控制平面為應用提供服務路由、遙測數據收集以及策略實施等功能。
1)創建標簽綁定命名空間
kubectl label namespace default istio-injection=enabled
2)部署應用
因為屬於istio的demo實例,所以在istio文件夾中可以找到對應的yaml文件
kubectl apply -f /usr/local/kubernetes/istio-1.11.4/samples/bookinfo/platform/kube/bookinfo.yaml
查看部署情況
kubectl get deploy,pods,svc -o wide
確認 Bookinfo 應用是否正在運行,在某個Pod中用curl命令對應用發送請求,例如ratings:
kubectl exec -it $(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}') -c ratings -- curl productpage:9080/productpage | grep -o "<title>.*</title>"
3)部署網關
kubectl apply -f /usr/local/kubernetes/istio-1.11.4/samples/bookinfo/networking/bookinfo-gateway.yaml
查詢網關
kubectl get virtualservices,gateway
4)查詢ingress IP和端口
執行如下指令,明確自身 Kubernetes 集群環境支持外部負載均衡:
kubectl get svc istio-ingressgateway -n istio-system
如果EXTERNAL-IP值已設置,說明環境正在使用外部負載均衡,可以用其為ingress gateway 提供服務。 如果EXTERNAL-IP值為<none>(或持續顯示<pending>), 說明環境沒有提供外部負載均衡,無法使用ingress gateway。在這種情況下,可以使用服務的NodePort訪問網關。
5)訪問測試
http://NodeIP:port/productpage
6)擴展外部IP-extertal-IP
修改svc配置
kubectl edit svc istio-ingressgateway -n istio-system
增加以下字段
查看istio-ingressgateway的svc
kubectl get svc istio-ingressgateway -n istio-system
訪問測試
http://NodeIP/productpage
5.3 卸載應用
可以使用下面的命令來完成應用的刪除和清理了:
-
刪除路由規則,並銷毀應用的 Pod
sh /usr/local/kubernetes/istio-1.11.4/samples/bookinfo/platform/kube/cleanup.sh
-
確認應用已經關閉
kubectl get virtualservices,destinationrules,gateway,pods,svc
6 Istio實現灰度發布
6.1 灰度發布介紹
灰度發布也叫金絲雀部署,是指通過控制流量的比例,實現新老版本的逐步更替。比如對於服務 A 有 version1 、 version2 兩個版本 當前兩個版本同時部署,但是 version1 比例90% version2 比例 10% ,看運行效果,如果效果好逐步調整流量占比 80 20 7030 ·····10 90 0 100 ,最終 version1 版本下線。
灰度發布的特點
-
新老版本共存
-
可以實時根據反饋動態調整占比
-
理論上不存在服務完全宕機的情況
-
適合於服務的平滑升級與動態更新
6.2 實現灰度發布
1)創建演示環境
mkdir -p /opt/k8s-cfg/istio/
1)創建Deploy文件
cat <<EOF> /opt/k8s-cfg/istio/canary-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: appv1
labels:
app: v1
spec:
replicas: 1
selector:
matchLabels:
app: v1
apply: canary
template:
metadata:
labels:
app: v1
apply: canary
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: appv2
labels:
app: v2
spec:
replicas: 1
selector:
matchLabels:
app: v2
apply: canary
template:
metadata:
labels:
app: v2
apply: canary
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
EOF
kubectl apply -f /opt/k8s-cfg/istio/canary-deploy.yaml
登錄到容器內修改下index.html訪問文件,以便后續測試
kubectl exec -it appv1-6bcc5579f7-9smts -c nginx -- /bin/bash
echo v1 > /usr/share/nginx/html/index.html
cat /usr/share/nginx/html/index.html
2)創建Service文件
cat <<EOF> /opt/k8s-cfg/istio/canary-service.yaml
apiVersion: v1
kind: Service
metadata:
name: canary
labels:
apply: canary
spec:
selector:
apply: canary
ports:
- protocol: TCP
port: 80
targetPort: 80
EOF
kubectl apply -f /opt/k8s-cfg/istio/canary-service.yaml
3)創建Gateway
cat <<EOF> /opt/k8s-cfg/istio/canary-gateway.yaml
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: canary-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
EOF
kubectl apply -f /opt/k8s-cfg/istio/canary-gateway.yaml
4)創建Virtualservice
cat <<EOF> /opt/k8s-cfg/istio/canary-virtual.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: canary
spec:
hosts:
- "*"
gateways:
- canary-gateway
http:
- route:
- destination:
host: canary.default.svc.cluster.local
subset: v1
weight: 90
- destination:
host: canary.default.svc.cluster.local
subset: v2
weight: 10
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: canary
spec:
host: canary.default.svc.cluster.local
subsets:
- name: v1
labels:
app: v1
- name: v2
labels:
app: v2
EOF
kubectl apply -f /opt/k8s-cfg/istio/canary-virtual.yaml
5)查看部署情況
kubectl get virtualservices,destinationrules,gateway,pods,svc
6)查看演示效果
查看istio-ingressgateway的svc
kubectl get svc istio-ingressgateway -n istio-system
for i in `seq 1 100`; do curl 192.168.5.3:31817 ;done > 1.txt
7 Istio核心資源解讀
7.1 Gateway
在Kubernetes 環境中, Ingress controller 用於管理進入集群的流量。在 Istio 服務網格中 Istio Ingress Gateway 承擔相應的角色,它使用新的配置模型( Gateway 和 VirtualServices )完成流量管理的功能。通過下圖做一個總的描述。
-
用戶向某端口發出請求
-
負載均衡器監聽端口,並將請求轉發到集群中的某個節點上。 Istio Ingress Gateway Service會監聽集群節點端口的請求
-
Istio Ingress Gateway Service 將請求交給 Istio Ingress Gateway Pod 處理。IngressGateway Pod 通過 Gateway 和 VirtualService 配置規則處理請求。其中, Gateway 用來配置端口、協議和證書; VirtualService 用來配置一些路由信息(找到請求對應處理的服務 App Service
-
Istio Ingress Gateway Pod 將請求轉給 App Service
-
最終的請求會交給 App Service 關聯的 App Deployment 處理
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: canary-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
EOF
網關是一個運行在網格邊緣的負載均衡器,用於接收傳入或傳出的 HTTP/TCP 連接。 主要工作是接受外部請求, 把請求 轉發到內部服務 。 網格邊緣的 Ingress 流量,會通過對應的 Istio IngressGateway Controller 進入 到集群內部 。
在上面 這個 yaml 里我們配置了一個監聽 80 端口的入口網關,它會將 80 端口的 http 流量導入到集群內對應的 Virtual Service 上 。
注意:
hosts:
- "*"
表示通配符, 通過任何域名都可以訪問
7.2 VirtualService
VirtualService是 Istio 流量治理的一個核心配置,可以說是 Istio 流量治理中最重要、最復雜的。VirtualService 在形式上表示一個虛擬服務,將滿足條件的流量都轉發到對應的服務后端,這個服務后端可以是一個服務,也可以是在 DestinationRule 中定義的服務的子集。
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: canary
spec:
hosts:
- "*"
gateways:
- canary-gateway
http:
- route:
- destination:
host: canary.default.svc.cluster.local
subset: v1
weight: 90
- destination:
host: canary.default.svc.cluster.local
subset: v2
weight: 10
這個虛擬服務會收到上一個gateway 中所有 80 端口來的 http 流量。
VirtualService主要由以下部分組成:
-
hosts
-
Gateway
-
路由
hosts字段列出了 virtual service 的 虛擬 主機。它是客戶端向服務發送請求時使用的一個或多個地址,通過該字段提供的地址訪問 virtual service ,進而訪問后端服務。在集群內部 網格內 使用時通常與 kubernetes 的 Service 同 名 ;當需要在集群外部 網格外 訪問時,該字段為 gateway 請求的地址,即與 gateway 的 hosts 字段相同。
hosts:
- reviews
virtual service的主機名可以是 IP 地址、 DNS 名稱,也可以是短名稱 (例如 Kubernetes 服務短名稱),該名稱會被隱式或顯式解析為全限定域名(FQDN),具體取決於 istio 依賴的平台。可以使用前綴通配符("*")為所有匹配的服務創建一組路由規則。 virtual service 的 hosts 不一定是 Istio 服務注冊表的一部分,它們只是虛擬目的地,允許用戶為網格無法路由到的虛擬主機建立流量模型。
virtual service 的 hosts 短域名在解析為完整的域名時,補齊的 namespace 是 VirtualService 所在的命名空間,而非 Service 所在的命名空間。如上例的 hosts 會被解析為:reviews.default.svc.cluster.l ocal 。
hosts:
- "*"
# *表示通配符,任何域名都可以
7.3 virtualservice 配置路由規則
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end user:
exact: jason
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v3
在http 字段包含了虛擬服務的路由規則,用來描述匹配條件和路由行為,它們把 HTTP/1.1 、HTTP2 和 gRPC 等流量發送到 hosts 字段指定的目標 。
示例中的第一個路由規則有一個條件,以match 字段開始 。 此路由 接收 來自 ”jason“ 用戶的所有請求 ,把請求發送到 destination 指定 的 v 2 子集 。
1)路由規則優先級:
在上面例子中,不滿足第一個路由規則的流量均流向一個默認的目標,該目標在第二條規則中指定。因此,第二條規則沒有 match 條件,直接將流量導向 v3 子集。
2)多路由規則解讀:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- bookinfo.com
http:
- match:
- uri:
prefix: /reviews
route:
- destination:
host: reviews
- match:
- uri:
prefix: /ratings
route:
- destination:
host: ratings
路由規則是將特定流量子集路由到指定目標地址的工具。可以在流量端口、header 字段、 URI 等內容上設置匹配條件。例如, 上面 這個 虛擬服務讓用戶發送請求到兩個獨立的服務: ratings 和reviews 相當於訪問 http://bookinfo.com/ ratings 和 http://bookinfo.com/reviews 虛擬服務規則根據請求的 URI 把請求路由到特定的目標地址。
路由的destination 字段指定了匹配條件的流量的實際地址。與 virtual service 的主機不同,該host 必須是存在於 istio 的服務注冊表 如 kubernetes services consul services 等 中的真實目的地或由 ServiceEntries 聲明的 hosts ,否則 Envoy 不知道應該將流量發送到哪里。它可以是一個帶代理的網格服務或使用 s ervice entry 添加的非網格服務。在 kubernetes 作為平台的情況下, host 表示名為kubernetes 的 service 名稱:
- destination:
host: canary.default.svc.cluster.local
subset: v1
weight: 90
7.4 DestinationRule
destinationrule 是 istio 流量路由功能的重要組成部分。一個 virtual service 可以看作是如何將流量分發給特定的目的地,然后調用 destination rule 來配置分發到該目的地的流量。 destinationrule 在 virtual service 的路由規則之后起作用 即在 virtual service 的 math -->route destination 之后起作用,此時流量已經分發到真實的service 上 ),應用於真實的目的地。
可以使用destination rule 來指定命名的服務子集,例如根據版本對 服務的實例進行分組,然后通過 virtual service 的路由規則中的服務子集將控制流量分發到不同服務的實例中。
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: canary
spec:
host: canary.default.svc.cluster.local
subsets:
- name: v1
labels:
app: v1
- name: v2
labels:
app: v2
在虛擬服務中使用Hosts 配置默認綁定的路由地址,用 http.route 字段,設置 http 進入的路由地址,可以看到, 上面 導入到了目標規則為 v 1 和 v 2 的子集 。
v1 子集對應的是 具有如下標簽的 pod
selector:
matchLabels:
app: v1
流量控制流程:
Gateway-->VirtaulService -->TCP/HTTP Router -->DestinationWeight -->Subset:Port
8 Istio核心功能演示
8.1 斷路器
官網介紹:https://istio.io/latest/zh/docs/tasks/traffic-management/circuit-breaking/
斷路器是創建彈性微服務應用程序的重要模式。斷路器使應用程序可以適應網絡故障和延遲等網絡不良影響。
1)創建熔斷器后端服務器
kubectl apply -f /usr/local/kubernetes/istio-1.11.4/samples/httpbin/httpbin.yaml
查看
kubectl get pods,svc,sa
2)創建DestinationRule規則
cat <<EOF> httpbin-DR.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin
trafficPolicy:
connectionPool:
# 連接池( TCP | HTTP )配置,例如:連接數、並發請求等
tcp:
maxConnections: 1
# TCP 連接池中的最大連接請求數,當超過這個值,會返回 503 代碼 。如兩個請求過來,就會有一個請求返回 503
http:
http1MaxPendingRequests: 1
# 連接到目標主機的最大掛起請求數 ,也就是待處理請求數 。 這里的目標指的是 virtualservice 路由規則中配置的destination 。
maxRequestsPerConnection: 1
# 連接池中每個連接最多處理 1 個請求后就關閉,並根據需要重新創建連接池中的連接
outlierDetection:
# 異常檢測配置,傳統意義上的熔斷配置,即對規定時間內服務錯誤數的監測
consecutiveGatewayErrors: 1
# 連續錯誤數 1 ,即連續返回 502-504 狀態碼的 Http 請求錯誤數
interval: 1s
# 錯誤異常的掃描間隔 1s ,即在 interval 1s )內連續發生 consecutiveGatewayErrors 1 )個錯誤,則觸發服務熔斷
baseEjectionTime: 3m
# 基本驅逐時間 3 分鍾,實際驅逐時間為 baseEjectionTime* 驅逐次數
maxEjectionPercent: 100
# 最大驅逐百分比 100%
EOF
kubectl apply -f httpbin-DR.yaml
查看
kubectl get destinationrule
3)添加客戶端訪問 httpbin 服務
創建一個客戶端以將流量發送給httpbin 服務。該客戶端是一個簡單的負載測試客戶端, Fortio 可以控制連接數,並發數和 HTTP 調用延遲。使用此客戶端來 跳閘 在 DestinationRule 中設置的斷路器策略。
kubectl apply -f /usr/local/kubernetes/istio-1.11.4/samples/httpbin/sample-client/fortio-deploy.yaml
測試訪問:
kubectl exec -it fortio-deploy-5bb66f84-xtwsn -c fortio -- /usr/bin/fortio curl http://httpbin:8000/get
4)觸發斷路器
在DestinationRule 設置中,指定了 maxConnect ions: 1 和 http1MaxPendingRequests: 1 。這些規則表明,如果超過一個以上的連接並發請求,則 istio proxy 在為進一步的請求和連接打開路由時,應該會看到下面的情況 。
以兩個並發連接(-c 2 )和發送 20 個請求(-n 20 )調用服務
kubectl exec -it fortio-deploy-5bb66f84-xtwsn -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
8.2 超時
在生產環境中經常會碰到由於調用方等待下游的響應過長,堆積大量的請求阻塞了自身服務,造成雪崩的情況,通過通過超時處理來避免由於無限期等待造成的故障,進而增強服務的可用性 Istio 使用虛擬服務來優雅實現超時處理。
下面例子模擬客戶端調用 nginx,nginx 將請求轉發給 tomcat 。 nginx 服務設置了超時時間為 2秒,如果超出這個時間就不在等待,返回超時錯誤 。 tomcat 服務設置了響應時間延遲 10 秒,任何請求都需要等待 10 秒后才能返回 。 client 通過訪問 nginx 服務去反向代理 tomcat 服務,由於 tomcat 服務需要 10 秒后才能返回,但 nginx 服務只等待 2 秒,所以客戶端會提示超時錯誤 。
1)創建演示環境
mkdir -p /opt/k8s-cfg/istio/timeout
2)創建后端服務
cat <<EOF> /opt/k8s-cfg/istio/timeout/nginx-tomcat-deploy.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-tomcat
labels:
server: nginx
app: web
spec:
replicas: 1
selector:
matchLabels:
server: nginx
app: web
template:
metadata:
name: nginx
labels:
server: nginx
app: web
spec:
containers:
- name: nginx
image: nginx:latest
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat
labels:
server: tomcat
app: web
spec:
replicas: 1
selector:
matchLabels:
server: tomcat
app: web
template:
metadata:
name: tomcat
labels:
server: tomcat
app: web
spec:
containers:
- name: tomcat
image: docker.io/kubeguide/tomcat-app:v1
EOF
kubectl apply -f /opt/k8s-cfg/istio/timeout/nginx-tomcat-deploy.yaml
cat <<EOF> /opt/k8s-cfg/istio/timeout/nginx-tomcat-svc.yaml
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
server: nginx
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
selector:
server: tomcat
ports:
- name: http
port: 8080
targetPort: 8080
protocol: TCP
EOF
kubectl apply -f /opt/k8s-cfg/istio/timeout/nginx-tomcat-svc.yaml
kubectl get pods,svc -o wide
3)創建VirtualService路由規則
cat <<EOF> /opt/k8s-cfg/istio/timeout/virtual-nginx-tomcat.yaml
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: nginx-vs
spec:
hosts:
- nginx-svc
http:
- route:
- destination:
host: nginx-svc
timeout: 2s
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: tomcat-vs
spec:
hosts:
- tomcat-svc
http:
- fault:
delay:
percentage:
value: 100
fixedDelay: 10s
route:
- destination:
host: tomcat-svc
EOF
kubectl apply -f /opt/k8s-cfg/istio/timeout/virtual-nginx-tomcat.yaml
4 )設置反向代理
登錄到pod容器內
kubectl exec -it nginx-tomcat-c9d66cc79-hk6sp -c nginx -- /bin/bash
# 安裝vim編輯器
apt-get update
apt-get -y install vim
vim /etc/nginx/conf.d/default.conf
proxy_pass http://tomcat-svc:8080;
proxy_http_version 1.1;
# 更新配置文件
nginx -s reload
5)驗證超時
創建測試容器
kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh
time wget -q -O - http://nginx-svc
while true;do wget -q -O - http://nginx-svc; done
每隔2 秒,由於 nginx 服務的超時時間到了而 tomcat 未有響應,則提示返回超時錯誤。
驗證故障注入效果,執行如下語句: