本文分析的istio代碼版本爲0.8.0,commit爲0cd8d67,commit時間爲2018年6月18日。node
本文爲Service Mesh深度學習系列
之一:git
首先咱們回顧一下pilot整體架構,上面是官方關於pilot的架構圖,由於是old_pilot_repo目錄下,可能與最新架構有出入,僅供參考。所謂的pilot包含兩個組件:pilot-agent和pilot-discovery。圖裏的agent對應pilot-agent二進制,proxy對應Envoy二進制,它們兩個在同一個容器中,discovery service對應pilot-discovery二進制,在另一個跟應用分開部署的單獨的deployment中。github
service
、endpoint
、pod
、node
等資源信息,監聽istio控制平面配置信息(Kubernetes CRD), 翻譯爲Envoy能夠直接理解的配置格式。對於模塊的命名方法,本文采用模塊對應源碼main.go所在包名稱命名法。其餘istio分析文章有其餘命名方法。好比pilot-agent也被稱爲istio pilot,由於它在Kubernetes上的部署形式爲一個叫istio-pilot的deployment。docker
pilot-discovery是單獨二進制,被封裝在Dockerfile.pilot
裏,在istio-docker.mk
裏被build成$(HUB)/pilot:$(TAG)
鏡像。json
根據istio-pilot.yaml.tmpl
,在Kubernetes環境下,pilot鏡像並不是sidecar的一部分,也不是daemonset在每一個機器上都有,而是單獨部署成一個replica=1的deployment。bootstrap
pilot-discovery扮演服務註冊中心、istio控制平面到Envoy之間的橋樑做用。pilot-discovery的主要功能包括:api
service
、endpoint
、pod
、node
等資源信息。監控istio控制面信息變化,在Kubernetes環境下,會監控包括RouteRule
、VirtualService
、Gateway
、EgressRule
、ServiceEntry
等以Kubernetes CRD形式存在的istio控制面配置信息。pilot-discovery的初始化主要在pilot-discovery的init
方法和在discovery
命令處理流程中調用的bootstrap.NewServer
完成:緩存
init
方法爲pilot-discovery的discovery
命令配置一系列flag及其默認值。flag值被保存在bootstrap包的PilotArgs
對象中bootstrap.NewServer
利用PilotArgs
構建bootstrap包下的server
對象bootstrap.NewServer
工做流程以下。網絡
根據服務註冊中心配置是否包含Kubernetes(一個istio service mesh能夠鏈接多個服務註冊中心)建立kubeClient
,保存在Server.kubeClient
成員中。kubeClient
有兩種建立方式:架構
discovery
命令的kubeconfig
flag中提供文件路徑,默認爲空。istio支持使用一個istio control plane來管理跨多個Kubernetes集羣上的service mesh。這個叫「multicluster」功能的具體描述參考官方文檔,當前此特性成熟度僅是alpha水平。Istio的控制平面組件(如pilot-discovery)運行所在的Kubernetes集羣叫本地集羣,經過這個istio控制面板鏈接的其餘Kubernetes集羣叫遠程集羣(remote cluster)。remote cluster信息被保存在Server.clusterStore
成員中,裏面包含一個map,將Metadata
映射成RemoteCluster
對象。clusterStore
的具體建立流程以下:
檢測上一步驟是否建立好kubeClient
。否,則直接報錯返回
檢測服務註冊中心中是否包含Mock類型,是的話直接返回
若是pilot-discovery discovery
命令的flag clusterRegistriesConfigMap
不爲空,則從本地Kubernetes集羣中讀取一個包含遠程Kubernetes集羣訪問信息的configmap(configmap所在的默認命名空間爲「istio-system」
,名字經過discovery命令flag clusterRegistriesConfigMap
設定)。
這個configmap包含Kubernetes遠程集羣的訪問信息,其形式爲鍵值對。其key爲cluster惟一標識符,value爲一個使用yaml或json編碼的Cluster
對象。 Cluster
對象的Annotations指定一個本地Kubernetes集羣中的secret(secret所在命名空間對應的annotation key爲config.istio.io/accessConfigSecret
,默認爲istio-system
,secret名稱對應annotation key爲config.istio.io/accessConfigSecretNamespace
)。 到本地Kubernetes集羣中讀取secret內容,根據這個內容構建保存在clusterStore
中的RemoteCluster對象,對應一個遠程Kubernetes集羣。
mesh配置由MeshConfig
結構體定義,包含MixerCheckServer
、MixerReportServer
、ProxyListenPort
、RdsRefreshDelay
、MixerAddress
等一些列配置。這裏讀取默認mesh配置文件」/etc/istio/config/mesh」(用戶能夠經過discovery命令的flag meshConfig
提供自定義值)。若是配置文件讀取失敗,也能夠從Kubernetes集羣中讀取configmap得到默認的配置。做爲測試,這裏也讀取flag來覆蓋mesh配置的MixerCheckServer
和MixerReportServer
(可是這兩個flag在pilot-discovery的init方法中並無配置)
若是mesh配置中的控制平面認證策略爲mutual TLS(默認爲none),則配置mixerSan
對istio作出的各類配置,好比route rule、virtualservice等,須要保存在配置存儲中心(config store)內,istio當前支持2種形式的config store:
i) 文件存儲
經過pilot-discovery discovery
命令的configDir
flag來設置配置文件的文件系統路徑,默認爲「configDir」
。後續使用pilot/pkg/config/memory包下的controller和pilot/pkg/config/monitor持續監控配置文件的變化。
ii) Kubernetes CRD
以Kubernetes apiserver做爲config store的狀況下,config store的初始化流程以下:
讀取pilot-discovery discovery
命令的kubeconfig
flag配置的kubeconfig配置文件,flag默認爲空。
註冊Kubernetes CRD資源。註冊的資源類型定義在bootstrap包下的全局變量ConfigDescriptor
變量裏,包括:RouteRule
、 VirtualService
、 Gateway
、 EgressRule
、 ServiceEntry
、 DestinationPolicy
、 DestinationRule
、 HTTPAPISpec
、 HTTPAPISpecBinding
、 QuotaSpec
、 QuotaSpecBinding
、 AuthenticationPolicy
, AuthenticationMeshPolicy
、 ServiceRole
、 ServiceRoleBinding
、 RbacConfig
。其中RouteRule
、 EgressRule
、 DestinationPolicy
、 HTTPAPISpec
、 HTTPAPISpecBinding
、 QuotaSpec
、 QuotaSpecBinding
、 ServiceRole
、 ServiceRoleBinding
、 RbacConfig
對應istio v1alpha2版本api,VirtualService
、Gateway
、ServiceEntry
、DestinationRule
對應istio v1alpha3版本api
以文件做爲config store顯然不靈活,因此咱們能夠說istio的流量管理策略等控制面信息存儲依賴Kubernetes的apiserver。那麼當使用cloud foundry等其餘非Kubernetes平臺做爲服務註冊中心的時候,istio就須要實現一個「假的」Kubernetes apiserver,不過目前這個工做並沒完成,詳見社區的一些相關討論。
CRD資源註冊完成以後將建立config controller,搭建對CRD資源Add、Update、Delete事件的處理框架。對該框架的處理會在本文」pilot-discovery主要功能分析之二:istio控制面信息監控與處理」中描述。
istio須要從服務註冊中心(service registry)獲取服務註冊的狀況。表明pilot-discovery的server對象包含一個ServiceController
對象,一個ServiceController
對象包含一個或多個service controller(是的,這兩個名字只有大小寫區別)。每一個service controller負責鏈接服務註冊中心並同步相關的服務註冊信息。
當前istio支持的服務註冊中心類型包括ConfigRegistry, MockRegistry, Kubernetes, Consul, Eureka和CloudFoundry。不過僅對Kubernetes服務註冊中心的支持成熟度達到stable水平,其餘服務註冊中心的集成工做成熟度還都處於alpha水平。
ServiceController
對象的結構體定義在aggregate包下,從包名能夠看出一個ServiceController
對象是對多個service controller的聚合。所謂聚合,也就是當對ServiceController
操做時,會影響到其聚合的全部service controller。好比,當咱們向ServiceController
註冊一個服務註冊信息變動事件處理handler時,實際上會將handler註冊到全部的service controller上。
具體service controller對服務註冊信息的變動處理流程框架將在本文「pilot-discovery主要功能分析之三:服務註冊信息監控與處理」中描述。
istio service mesh中的envoy sidecar經過鏈接pilot-discovery的discovery服務獲取服務註冊狀況、流量控制策略等控制面的控制信息。discovery服務的初始化主要包括以下幾步:
i) 建立對外提供REST協議的discovery服務的discovery service對象
istio代碼在2018年6月的一次commit (e99cad5)中刪除了大量與Envoy v1版本的data plane api相關代碼。當前版本的istio中,做爲sidecar的Envoy已經再也不使用REST協議獲取控制面信息。與v1版本Envoy data plane api相關的cds
、rds
、lds
相關代碼都已被刪除,僅殘留sds
部分代碼。所以做爲sds
的殘留功能,用戶依然能夠訪問"/v1/registration"
URL訪問與服務endpoint
相關的信息,但Envoy並不會訪問這個URL。discovery service默認經過8080端口對外提供服務,能夠經過pilot-discovery的discovery
命令的httpAddr
flag自定義端口
ii) 建立對外提供gRPC協議discovery服務的Envoy xds server
所謂的xds
表明Envoy v2 data plane api中的eds
、 cds
、 rds
、 lds
、 hds
、 ads
、 kds
等一系列api。Envoy xds server默認經過15010和15012端口對外提供服務,能夠經過pilot-discovery的discovery
命令的grpcAddr
、secureGrpcAddr
flag自定義端口。
與Envoy xds server相關代碼分析咱們將在系列文章的下一篇分析。
pilot-discovery默認打開9093端口(端口號能夠經過pilot-discovery discovery命令的monitoringAddr
flag自定義),對外提供HTTP協議的自身運行狀態檢查監控功能。當前提供/metrics
和/version
兩個運行情況和基本信息查詢URL。
當使用一個istio控制面構建跨多個Kubernetes集羣的service mesh時,遠程Kubernetes集羣的訪問信息保存在secret中,此處使用list/watch監控secret資源的變化。
關於上面第五點說的兩種config store,代碼裏實際上還有第三種,經過
PilotArgs.Config.Controller
配置。但pilot-discovery的init
函數裏沒找到對應flag。
以上一系列初始化不候經過bootstrap包的NewServer
函數帶起,在此過程當中pilot-discovery已經啓動一部分協程,開始一些控制邏輯的循環執行。好比在上述第九步中的多Kubernetes集羣訪問信息(secret資源)的監控,在initMonitor
方法中,實際上已經啓動協程,利用client-go庫開始對secret信息的監控(list/watch)與處理。
而pilot-discovery的其餘控制邏輯則要在bootstrap包下的Server.Start
方法啓動,而Start
方法的邏輯是順序執行以前初始化過程當中在server
對象上註冊的一系列啓動函數(startFunc
)。 本文接下來分析pilot-discovery的其餘主要控制邏輯。 TODO 整理有哪些startfunc
istio的用戶能夠經過istioctl建立route rule
、virtualservice
等實現對服務網絡中的流量管理等配置建。而這些配置須要保存在config store中。在當前的istio實現中,config store以Kubernetes CRD的形式將virtualservice
等存儲在Kubernetes apiserver以後的etcd中。
在前面pilot-discovery初始化第五步驟中pilot-discovery已經完成了RouteRule
、VirtualService
等CRD資源在Kubernetes apiserver上的註冊,接下來pilot-discovery還須要在initConfigController方法中經過config controller搭建CRD資源對象處理的框架。config controller包含如下3個部分:
1. client
client是一個rest client集合,用於鏈接Kubernetes apiserver,實現對istio CRD資源的list/watch。具體而言,爲每一個CRD資源的group version (如config.istio.io/v1alpha2
、networking.istio.io/v1alpha3
)建立一個rest client。該rest client裏包含了鏈接Kubernetes apiserver須要用到的apimachinary
、client-go
等庫裏的對象,如GroupVersion
、RESTClient
等。
2. queue
用於緩存istio CRD資源對象(如virtual-service
、route-rule
等)的Add、Update、Delete事件的隊列,等待後續由config controller處理。詳見本文後續描述
3. kinds
爲每種CRD資源(如virtual-service
、route-rule
等)建立一個用於list/watch的SharedIndexInformer(Kubernetes client-go庫裏的概念)。
pilot-discovery在完成config controller的建立以後,向server對象註冊startFunc
,從而在後續server start的時候啓動config controller的主循環邏輯(config controller的Run方法),完成與istio控制面信息相關的監控與處理。config controller主循環主要包括兩方面:
client-go
庫裏的SharedIndexInformer實現對CRD資源的list/watch,爲每種CRD資源的Add、Update、Delete事件建立處理統一的流程框架。 這個流程將Add、Update、Delete事件涉及到的CRD資源對象封裝爲一個Task對象,並將之push到config controller的queue成員裏。Task對象除了包含CRD資源對象以外,還包含事件類型(如Add、Update、Delete等),以及處理函數ChainHandler。ChainHandler支持多個處理函數的串聯。這個流程執行結束以後,只是搭建了CRD資源對象變動事件的處理框架,真正CRD變動事件的處理邏輯要等到下面在discovery service中將相應的handler註冊到ChainHandler當中。
istio須要從服務註冊中心(service registry)獲取服務註冊的狀況。當前版本中istio能夠對接的服務註冊中心類型包括Kubernetes、Consul等。本小節以Kubernetes服務註冊中心爲例,分析istio對服務註冊信息的變動處理流程框架。
pilot-discovery初始化第六步中經過構建service controller實現對Kubernetes服務註冊信息的監控。pilot-discovery在完成service controller的建立以後,會向server對象(server對象表明pilot-discovery組件)註冊startFunc
,從而在後續server start的時候啓動service controller的主循環邏輯(service controller的Run方法),完成服務註冊信息的監控與處理。service controller主循環主要包括兩方面:
1. 利用client-go
庫裏的SharedIndexInformer
監控Kubernetes中的service
,endpoints
, node
和pod
資源(默認resync間隔爲60秒,能夠經過pilot-discovery discovery命令的resync
flag配置)。與config controller對於CRD資源的處理方式相似,全部service
,endpoints
等資源的Add,Update和Delete事件都採用統一處理框架。
i) 將事件封裝爲Task對象,包含:
a) 事件涉及的資源對象
b) 事件類型:Add、Update和Delete
c) Handler:ChainHandler。ChainHandler支持多個處理函數的串聯
ii) 將Task對象push到service controller的queue成員裏。
2. 啓動協程逐一處理服務註冊信息變動事件(queue.run),處理方法是調用每一個從queue中取出的Task對象上的ChainHandler
這個流程執行結束以後,只是搭建了服務註冊信息變動事件的處理框架,真正服務註冊變動事件的處理邏輯要等到下面在discovery service中將相應的handler註冊到ChainHandler當中。
pilot-discovery建立Envoy xds server對外提供gRPC協議discovery服務。所謂的xds
表明Envoy v2 data plane api中的eds
、 cds
、 rds
、 lds
、 hds
、 ads
、 kds
等api。與Envoy xds server相關代碼分析咱們將在系列文章的下一篇分析。