Istio技術與實踐02:源碼解析之Istio on Kubernetes 統一服務發現

      網友投稿 954 2025-04-04

      前言


      前言

      前面文章《Istio源碼解析 Pilot服務發現的Adapter機制》結合Pilot的代碼實現介紹了Istio的抽象服務模型和基于該模型的數據結構定義,了解到Istio上只是定義的服務發現的接口,并未實現服務發現的功能,而是通過Adapter機制以一種可擴展的方式來集成各種不同的服務發現。本文重點講解Adapter機制在Kubernetes平臺上的使用。即Istio+Kubernetes如何實現服務發現。

      Istio的官方設計上特別強調其架構上的可擴展性,即通過框架定義與實現解耦的方式來集成各種不同的實現。如Pilot上的adapter機制集成不同的服務注冊表,Mixer通過提供一個統一的面板給數據面Sidecar,后端可以通過模板定義的方式對接不同的Backend來進行各種訪問管理。但就現階段實現,從代碼或者文檔的細節去細看其功能,還是和Kubernetes結合最緊密。

      Kubernetes和Istio的結合

      從場景和架構上看Istio和Kubernetes都是非常契合的一種搭配。

      首先從場景上看Kuberntes為應用負載的部署、運維、擴縮容等提供了強大的支持。通過Service機制提供了負載間訪問機制,通過域名結合Kubeproxy提供的轉發機制可以方便的訪問到對端的服務實例。因此如上圖可以認為Kubernetes提供了一定的服務發現和負載均衡能力,但是較深入細致的流量治理能力,因為Kubnernetes所處的基礎位置并未提供,而Istio正是補齊了這部分能力,兩者的結合提供了一個端到端的容器服務運行和治理的解決方案

      從架構看Istio和Kubernetes更是深度的結合。?得益于Kuberntes Pod的設計,數據面的Sidecar作為一種高性能輕量的代理自動注入到Pod中和業務容器部署在一起,接管業務容器的inbound和outbound的流量,從而實現對業務容器中服務訪問的治理。在控制面上Istio基于其Adapter機制集成Kubernetes的域名,從而避免了兩套名字服務的尷尬場景。

      在本文中將結合Pilot的代碼實現來重點描述圖中上半部分的實現,下半部分的內容Pilot提供的通用的API給Envoy使用可參照上一篇文章的DiscoverServer部分的描述。

      基于Kubernetes的服務發現

      理解了Pilot的ServiceDiscovery的Adapter的主流程后,了解這部分內容比較容易。Pilot-discovery在initServiceControllers時,根據服務注冊配置的方式,如果是Kubernetes,則會走到這個分支來構造K8sServiceController。

      case?serviceregistry.KubernetesRegistry:

      s.createK8sServiceControllers(serviceControllers,?args);?err != nil {

      return?err

      }

      創建controller其實就是創建了一個Kubenernetes的controller,可以看到List/Watch了Service、Endpoints、Node、Pod幾個資源對象。

      // NewControllercreates a new Kubernetes controller

      func NewController(clientkubernetes.Interface, options ControllerOptions) *Controller {

      out := &Controller{

      domainSuffix: options.DomainSuffix,

      client:?????? client,

      queue:??????? NewQueue(1 * time.Second),

      }

      out.services =out.createInformer(&v1.Service{}, "Service", options.ResyncPeriod,

      func(opts meta_v1.ListOptions) (runtime.Object, error) {

      Istio技術與實踐02:源碼解析之Istio on Kubernetes 統一服務發現

      return client.CoreV1().Services(options.WatchedNamespace).List(opts)

      },

      func(opts meta_v1.ListOptions) (watch.Interface, error) {

      return client.CoreV1().Services(options.WatchedNamespace).Watch(opts)

      })

      out.endpoints =out.createInformer(&v1.Endpoints{}, "Endpoints", options.ResyncPeriod,

      func(opts meta_v1.ListOptions) (runtime.Object, error) {

      return client.CoreV1().Endpoints(options.WatchedNamespace).List(opts)

      },

      func(opts meta_v1.ListOptions) (watch.Interface, error) {

      return client.CoreV1().Endpoints(options.WatchedNamespace).Watch(opts)

      })

      out.nodes =out.createInformer(&v1.Node{}, "Node", options.ResyncPeriod,

      func(opts meta_v1.ListOptions) (runtime.Object, error) {

      return client.CoreV1().Nodes().List(opts)

      },

      func(opts meta_v1.ListOptions) (watch.Interface, error) {

      return client.CoreV1().Nodes().Watch(opts)

      })

      out.pods =newPodCache(out.createInformer(&v1.Pod{}, "Pod", options.ResyncPeriod,

      func(opts meta_v1.ListOptions) (runtime.Object, error) {

      return client.CoreV1().Pods(options.WatchedNamespace).List(opts)

      },

      func(opts meta_v1.ListOptions) (watch.Interface, error) {

      return client.CoreV1().Pods(options.WatchedNamespace).Watch(opts)

      }))

      return out

      }

      在?createInformer?中其實就是創建了SharedIndexInformer。這種方式在Kubernetes的各種Controller中廣泛使用。Informer調用?APIserver的 List 和 Watch 兩種類型的 API。在初始化的時,先調用 List API 獲得全部資源對象,緩存在內存中; 然后,調用 Watch API 去 Watch這種這種資源對象,維護緩存。

      Service informer := cache.NewSharedIndexInformer(

      &cache.ListWatch{ListFunc: lf, WatchFunc: wf}, o,

      resyncPeriod, cache.Indexers{})

      下面看下Kubernetes場景下對ServiceDiscovery接口的實現。我們看下Kubernetes下提供的服務發現的接口,包括獲取服務列表和服務實例列表。

      func (c *Controller) GetService(hostname model.Hostname) (*model.Service, error) {

      name, namespace, err := parseHostname(hostname)

      item, exists := c.serviceByKey(name, namespace)

      svc := convertService(*item, c.domainSuffix)

      return svc, nil

      }

      最終是從infromer的緩存中獲取Service資源對象。

      func (c *Controller) serviceByKey(name, namespace string) (*v1.Service, bool) {

      item, exists, err := c.services.informer.GetStore().GetByKey(KeyFunc(name, namespace))

      return item.(*v1.Service), true

      }

      獲取服務實例列表也是類似,也是從Informer的緩存中獲取對應資源,只是涉及的對象和處理過程比Service要復雜一些。

      func (c *Controller) InstancesByPort(hostname model.Hostname, reqSvcPort int,

      labelsList model.LabelsCollection) ([]*model.ServiceInstance, error) {

      // Get actual service by name

      name, namespace, err := parseHostname(hostname)

      item, exists := c.serviceByKey(name, namespace)

      svc := convertService(*item, c.domainSuffix)

      svcPortEntry, exists := svc.Ports.GetByPort(reqSvcPort)

      for _, item := range c.endpoints.informer.GetStore().List() {

      ep := *item.(*v1.Endpoints)

      }

      ...

      }

      }

      return nil, nil

      }

      可以看到就是做了如下的轉換,將Kubernetes的對一個服務發現的數據結構轉換成Istio的抽象模型對應的數據結構。

      其實在conversion.go中提供了多個convert的方法將Kubernetes的數據對象轉換成Istio的標準格式。除了上面的對Service、Instance的convert外,還包含對port,label、protocol的convert。如下面protocol的convert就值得一看。

      func ConvertProtocol(name string, proto v1.Protocol) model.Protocol {

      out := model.ProtocolTCP

      switch proto {

      case v1.ProtocolUDP:

      out = model.ProtocolUDP

      case v1.ProtocolTCP:

      prefix := name

      i := strings.Index(name, "-")

      if i >= 0 {

      prefix = name[:i]

      }

      protocol := model.ParseProtocol(prefix)

      if protocol != model.ProtocolUDP && protocol != model.ProtocolUnsupported {

      out = protocol

      }

      }

      return out

      }

      看過Istio文檔的都知道在使用Istio和Kuberntes結合的場景下創建Pod時要求滿足4個約束。其中重要的一個是Port必須要有名,且Port的名字名字的格式有嚴格要求:Service 的端口必須命名,且端口的名字必須滿足格式 [-],例如name: http2-foo 。在K8s場景下這部分我們一般可以不對Pod命名的,看這段解析的代碼可以看服務的Protocol是從name中解析出來的。如果Service的protocol是UDP的,則協議UDP;如果是TCP的,則會從名字中繼續解析協議。如果名稱是不可識別的前綴或者端口上的流量就會作為普通的 TCP 流量來處理。

      另外同時在Informer?中添加對add、delete和update事件的回調,分別對應?informer?監聽到創建、更新和刪除這三種事件類型。可以看到這里是將待執行的回調操作包裝成一個task,再壓到Queue中,然后在Queue的run()方法中拿出去挨個執行,這部分不細看了。

      到這里Kuberntes特有的服務發現能力就介紹完了。即kube\controller也實現了ServiceDiscovery中規定的服務發現的接口中定義的全部發方法。除了初始化了一個kube controller來從Kubeapiserver中獲取和維護服務發現數據外,在pilot server初始化的時候,還有一個重要的initDiscoveryService初始化DiscoveryServer,這個discoveryserver使用contrller,其實是ServiceDiscovery上的服務發現供。發布成通用協議的接口,V1是rest,V2是gRPC,進而提供服務發現的能力給Envoy調用,這部分是Pilot服務發現的通用機制,在上篇文章的adapter機制中有詳細描述,這里不再贅述。

      總結

      以上介紹了istio基于Kubernetes的名字服務實現服務發現的機制和流程。整個調用關系如下,可以看到和其他的Adapter實現其實類似。

      1.KubeController使用List/Watch獲取和維護服務列表和其他需求的資源對象,提供轉換后的標準的服務發現接口和數據結構;

      2.Discoveryserver基于Controller上維護的服務發現數據,發布成gRPC協議的服務供Envoy使用。

      前面只是提到了服務發現的數據維護,可以看到在Kubernetes場景下,Istio只是是使用了kubeAPIServer中service這種資源對象。在執行層面,說到Service就不得不說Kuberproxy,因為Service只是一個邏輯的描述,真正執行轉發動作的是Kubeproxy,他運行在集群的每個節點上,把對Service的訪問轉發到后端pod上。在引入Istio后,將不再使用Kubeproxy做轉發了,而是將這些映射關系轉換成為pilot的轉發模型,下發到envoy進行轉發,執行更復雜的控制。這些在后面分析Discoveryserver和Sidecar的交互時再詳細分析。

      在和Kubnernetes結合的場景下

      強調下幾個概念:

      1.Istio的治理Service就是Kubernetes的Service。不管是服務描述的manifest還是存在于服務注冊表中服務的定義都一樣。

      2.Istio治理的是服務間的通信。這里的服務并不一定是所謂的微服務,并不在乎是否做了微服務化。只要有服務間的訪問,需要治理就可以用。一個大的單體服務打成一個鏡像在Kuberntes里部署起來被其他負載訪問和分拆成微服務后被訪問,在治理看來沒有任何差別。

      本文只是描述了在服務發現上兩者的結合,隨著分析的深入,會發現Istio和Kubernetes的更多契合。K8s編排容器服務已經成為一種事實上的標準;微服務與容器在輕量、快速部署運維等特征的匹配,微服務運行在容器中也正成為一種標準實踐;隨著istio的成熟和ServiceMesh技術的流行,使用Istio進行微服務治理的實踐也正越來越多;而istio和k8s的這種天然融合使得上面形成了一個完美的閉環。對于云原生應用,采用kubernetes構建微服務部署和集群管理能力,采用Istio構建服務治理能力,也將成為微服務真正落地的一個最可能的途徑。有幸參與其中讓我們一起去見證和經歷這個趨勢吧。

      華為云APP

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:【精選】深入淺出帶你了解微服務架構如何運作?
      下一篇:怎樣刪除最后一頁?(怎樣刪除最后一頁空白頁)
      相關文章
      亚洲国产精品免费在线观看| 五月天网站亚洲小说| 亚洲国产精品网站久久| 久久亚洲精品中文字幕三区| 中文字幕精品亚洲无线码一区应用| 亚洲国产精品一区二区第四页| 精品国产日韩亚洲一区在线| 亚洲国产成人AV在线播放| 亚洲中文字幕无码爆乳app| 精品国产日韩久久亚洲| 亚洲中文无码mv| 亚洲欧美一区二区三区日产| 亚洲日本成本人观看| 亚洲午夜成人精品无码色欲| 亚洲人成网站在线播放2019| 亚洲国产午夜精品理论片在线播放 | 亚洲春色在线观看| 亚洲国产成人精品久久| 精品亚洲AV无码一区二区 | 区久久AAA片69亚洲| 亚洲欧洲∨国产一区二区三区 | 亚洲看片无码在线视频| 亚洲日韩AV一区二区三区中文| 亚洲色大成网站www久久九| 亚洲精品GV天堂无码男同| 日韩精品成人亚洲专区| 亚洲片一区二区三区| 亚洲日韩av无码| 亚洲国产一区二区a毛片| 亚洲高清无在码在线无弹窗 | 亚洲综合亚洲综合网成人| 中文字幕亚洲日韩无线码| 国产V亚洲V天堂无码久久久| 亚洲精品自产拍在线观看动漫| 亚洲精品国产福利片| 亚洲AV男人的天堂在线观看| 亚洲av乱码一区二区三区按摩 | 亚洲麻豆精品国偷自产在线91| 丝袜熟女国偷自产中文字幕亚洲| 亚洲中文字幕久久精品无码喷水| 久久香蕉国产线看观看亚洲片|