淺析ServiceMesh和Istio,你學會了嗎?
1、什么是ServiceMesh?
1.1、從單體到分布式
從后臺服務發展之初,其實一直面臨一個問題,就是如何將多臺服務器組成一個整體提供對外服務。畢竟單體服務功能單一,在發展前期已經滿足各種需求,但是隨著互聯網的發展,服務類型越來越多,也越來越復雜,如果用單體架構思考,就會發現越來越難滿足需求。為了解決這個問題,于是出現了分布式架構,將單體服務拆分成多個子服務,每個子服務負責不同的功能,然后通過網關組合子服務,對外提供服務。看似這樣已經解決了單體服務的問題,但是隨著子服務的增多,網關也會越來越復雜,而且每個子服務都需要單獨維護,服務治理就變得非常復雜。為了解決這里復雜性,因此引入各種架構概念:
- 用遠程調用代替子服務之間的通信,統一管理通訊協議;
- 用服務發現代替子服務的注冊,統一管理服務地址;
- 引入服務治理組件,統一管理子服務;
- 引入旁路負載均衡,統一管理流量管理;...
1.2、微服務架構
分布式架構下將單獨服務拆分成子服務,結合各種架構設計已經將分布式基石做好了,但是在業務層的架構設計上,還是有很多問題需要解決,比如子服務更新如何不影響全局,功能迭代如何足夠快,如何細粒度的監控某些服務狀態等。為了解決這些問題,于是出現了微服務架構,將業務從粒度上變成更加輕量,每個服務負責更小的業務,這樣就可以更快的迭代,更細粒度的監控服務狀態等。
1.3、ServiceMesh
雖然分布式基石做好了,微服務架構已經能解決業務層發展的一些問題,但是對于工程師來說,關心底層通訊協議,服務發現,負載均衡等這些細節,似乎有些繁瑣,就如同使用Linux一樣,如果開發者還需要關注什么是文件還是網絡(在Linux中,一切皆文件),那對于負擔太重了。于是隨著Docker和K8S的發展,ServiceMesh 應運而生,作為云原生下的服務間通訊的中間件,屏蔽了底層通訊協議,服務發現,負載均衡等細節,讓開發者只需要關注業務邏輯。
ServiceMesh架構圖
發展最早的是Linkerd,通過 Sidecar 模式托管服務間的網絡調用和調度,不過由于性能問題被開源社區放棄;第二代是由google發展的 Istio,重新開發了 Envoy 作為網關,將系統定義為數據面和控制面,數據面負責網絡通訊和負載均衡,控制面負責服務治理,下面將詳細介紹其架構和設計方式。
2、ServiceMesh 的開源實現:Istio
ServiceMesh有一些開源項目,其當前最流行是Google開源實現是 Istio,在2018年10月開源,目前已經發展到了1.2版本,其github地址為:
https://github.com/istio/istio
2.1、Istio架構圖
Istio架構圖如下:
Istio架構圖
提供的功能:
- 針對HTTP,gRPC,WebSocket和TCP協議提供負載均衡;
- 精細的流量控制,比如A/B測試,金絲雀部署等;
- 模塊化的插件設計,可以通過API進行訪問,頻率限制等;
- 全自動的請求遙測,包括請求的追蹤,監控和日志;
- 強大的安全功能,比如認證,授權,加密等;
2.2、Istio數據面
可以看到架構圖上,每個服務都有一個sidecar,也就是 Envoy,這個就是數據面,負責服務間通訊和負載均衡。所有進入服務的請求都經過 Envoy,然后根據路由規則轉發到相應的服務,所以 Envoy 被稱為服務網格的入口。Envoy 架構圖如下:
Envoy
當然,Envoy 并不是唯一的數據面,還有 Linkerd,Kuma 等,但是Envoy 性能比較好,所以目前使用最多。
2.3、Istio控制面
控制面負責服務治理,比如路由規則,安全策略等,是服務網格的控制核心,通過控制面,可以配置服務網格中各個組件的行為。為了結構化控制面的功能,Istio 將其分為Pilot,Mixer,Citadel組件,其各個部分對應的功能:
- Pilot:負責服務發現,負載均衡,路由規則等,不過Pilot不提供服務注冊,只提供標準化的接口,可以方便的對接到各個服務注冊中心,比如Eureka,Etcd等,然后通過服務發現控制Envoy的動態轉發能力;
- Mixer:負責訪問控制,策略執行等,在最初的Istio的架構設計中,Mixer是中心化的組件,由于Mixer提供了各種訪問控制策略,所以Mixer的負載壓力比較大,發起請求之前做一次邏輯檢查,請求結束后還需要上報處理,Mixer接收的請求至少漲了原始請求的2倍。為了解決這個問題,Mixer增加了緩存的功能,邏輯處理和上報都由Mixer緩存完成,這樣Mixer的負載壓力就能緩解;
- Citadel:負責安全功能,比如認證授權等,比如那些服務安全級別比較高,需要對請求做單獨的加密處理或者角色控制,Istio 通過引入Citadel組件,將安全能力透明化;
2.4、詳解 Envoy
Envoy是專為大型現代SOA(面向服務架構)設計的、用C++11開發的代理和通信總線,作為服務網格中的數據面,負責服務間通訊和負載均衡。開源地址:https://github.com/envoyproxy/envoy.git
(1)編譯編譯依賴:
- C++11
- bazel
git clone https://github.com/envoyproxy/envoy.git
cd envoy
bazel build //source/exe:envoy-static
(2)配置Envoy的配置文件為 yaml 格式,其配置文件分為兩部分:
- 靜態配置:在啟動時加載,后續不會變化;
- 動態配置:在運行時加載,可以調用API動態修改;
- 樣例配置文件:
admin: # 監控配置
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 9901 # 監聽的端口
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 10000 # 監聽的端口
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager # 過濾器名稱
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
access_log:
- name: envoy.access_loggers.stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
host_rewrite_literal: www.envoyproxy.io
cluster: service_envoyproxy_io
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: service_envoyproxy_io
type: LOGICAL_DNS
# Comment out the following line to test on v6 networks
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service_envoyproxy_io
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: www.envoyproxy.io
port_value: 443
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
sni: www.envoyproxy.io
(3)服務啟動和測試
./envoy -c envoy.yaml
curl -v localhost:10000
# 返回數據
TODO:
(4)Envoy架構
圖片
Envoy包括幾個部分:
- listeners:監聽器,負責監聽端口,接收請求,比如上述的配置文件中監聽10000端口;
- filter Chains:過濾器鏈,可以在配置文件配置對于請求的處理鏈路,可以在任何一個套接字上,按我們的需要去拼接多個過濾器,來實現對流量的、不同功能的處理,比如上述的配置文件中的過濾器鏈,在監聽器上添加了 HttpConnectionManager 過濾器,這個過濾器負責解析HTTP協議;
- cluster defintios:設置轉發到下游的upsteam server,比如上述配置文件中的cluster defintios,設置轉發到www.envoyproxy.io這個域名;
Envoy提供了xDS API標準,什么是xDS?xDS是x-discovery service,也就是服務發現服務,Envoy通過xDS API獲取配置信息,然后根據配置信息進行轉發,包括幾個類型,分別是:EDS(endpoint discovery service),LDS(listener discovery service)和CDS(cluster discovery service),對應實現節點服務發現,監聽器服務發現和集群服務發現。
Envoy
Envoy支持L3/L4 filter架構,提供了對L3/L4網絡代理功能,這是Envoy的核心功能,還支持TCP、UDP、HTTP、TLS證書認證、Redis、Postgres、MongoDb等諸多協議的filter;Envoy支持HTTP L7架構,提供了對HTTP協議的filter,支持HTTP1.1、HTTP2、HTTP3,gRPC等協議;Envoy還提供了健康檢查,負載均衡,熔斷,限流等功能,并且有強大的可觀測性,包括metrics、tracing等;
(5)Envoy處理請求流程
- 某請求經過TCP鏈接被處于某個worker線程的listener接受;
- listener filter鏈被創建,一個listener可以有多個filter鏈,主要用于SNI、相關等處理,一旦處理完成,listener將匹配一個network filter鏈,如HTTP connection manager;
- listener filter鏈可以與TLS關聯,以解密被加密的數據,network filter鏈被創建,如HTTP connection manager;
- HTTP/2編解碼器將TCP流解幀為獨立的stream,每個stream處理一對request/response;
- 對于每個HTTP stream,一個下游http filter被創建,其中最重要的是route filter,它必須位于HTTP filter鏈的末端;
- route filter根據配置來選定請求要被路由到哪個cluster(route filter將從cluster獲取HTTP connection pool);
- cluster通過負載均衡策略選定最終的上游節點,其中還涉及到了斷路器與健康檢查等機制,若HTTP connection pool不存在存活的鏈接,則一個與上游節點的新鏈接將被建立;
- 對于每個stream,一個上游HTTP filter鏈將被創建,默認情況下只有codec filter,它主要負責將請求編碼給上游節點,并將上游節點的回包解碼;
- 處理與上游節點相關的TLS,而后將請求發送到上游節點;
- 收到上游節點的回包后,回包以相反順序依次經過HTTP filter,包括上游codec filter,route filter等filter,最終被發送到下游;
- 最后stream被銷毀,更新整個過程中產生的統計數據與日志;
3、Istio實踐
Istio 是基于K8S編排服務,而K8S網絡相關的知識點,在《Kubernetes核心原理》做過一些介紹,這里再回顧一下:
- K8S的物理資源是Node,每個Node上運行一個Kubelet進程,而Node上運行的Pod,就是K8S的邏輯資源;
- 每個Pod都有一個IP地址,通過該IP地址可以訪問到Pod;
- 如果聲明Deploymnet,則K8S會為該Deployment創建一組Pod,每個Pod的IP地址是不同的,為了這些Pod實現負載均衡,K8S會為每個Pod創建一個Service,Service的IP地址是固定的,通過該IP地址可以訪問到一組Pod;
- Service的IP地址是虛擬IP,K8S通過iptables規則將Service的IP地址映射到Pod的IP地址;
- 在K8S中服務發現,是通過CoreDNS實現的DNS服務來找到對應的Service的IP;
而在Istio中,每個Pod都有一個對應的Sidecar,Sidecar負責與K8S進行通信,可以登陸到業務的Pod中執行ps aux,會看到proxy的進程,具體istio的pods詳細如下圖:
詳情
如果你想繼續探究內部實現,可以嘗試自己安裝Istio,如果你沒有自己的可用集群,可以使用Kubernetes Playground,打開鏈接:https://labs.play-with-k8s.com/具體可以參考這篇文章:https://www.knowledgehut.com/blog/cloud-computing/test-drive-your-first-istio-deployment-using-play-with-kubernetes-platform-cloud-computing
對應的腳本已經準備好了,可以先執行istio-preinstall.sh:
#!/bin/bash
kubeadm init --apiserver-advertise-address $(hostname -i)
mkdir -p $HOME/.kube
chown $(id -u):$(id -g) $HOME/.kube/config
kubectl apply -n kube-system -f "https://cloud.weave.works/k8s/net?k8s-versinotallow=$(kubectl version | base64 | tr -d '\n')"
然后執行istio-install.sh:
#!/bin/bash
curl -L https://git.io/getLatestIstio | sh -
export PATH=$PWD/bin:$PATH
cd istio-1.21.2
istioctl manifest apply --set profile=demo --set values.gateways.istio-ingressgateway.type=ClusterIP
最后執行:kubectl -n istio-system get pod 可以看到isito-ingressgateway和istio-pilot的pod狀態都是running。
參考
(1)https://cloud.tencent.com/developer/article/1351311
(2)https://labs.play-with-k8s.com/
(3)https://blog.csdn.net/KeyarchOS/article/details/135782578