溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

服務(wù)網(wǎng)格數(shù)據(jù)平面的關(guān)鍵:層層剖析Envoy配置

發(fā)布時間:2020-06-19 09:17:25 來源:網(wǎng)絡(luò) 閱讀:304 作者:RancherLabs 欄目:云計算

Envoy是一種高性能C++分布式代理,專為單個服務(wù)和應(yīng)用程序設(shè)計。作為Service Mesh中的重要組件,充分理解其配置就顯得尤為重要。本文列出了使用Envoy而不用其他代理的原因。并給出了Envoy及其服務(wù)的配置,然后對其進(jìn)行詳細(xì)解讀,幫助讀者理解其配置,從而掌握Envoy。
 
服務(wù)網(wǎng)格數(shù)據(jù)平面的關(guān)鍵:層層剖析Envoy配置

 

 
服務(wù)網(wǎng)格是微服務(wù)設(shè)置中的通信層,也就是說往返于每個服務(wù)的所有請求都通過網(wǎng)格。服務(wù)網(wǎng)格在微服務(wù)設(shè)置中也成為基礎(chǔ)架構(gòu)層,它能夠讓服務(wù)之間的通信變得安全可靠。關(guān)于Service Mesh的基礎(chǔ)內(nèi)容,我們已經(jīng)在這篇文章中詳細(xì)介紹過。
 

每一個服務(wù)都有自己的代理服務(wù)(sidecars),然后所有代理服務(wù)一起形成服務(wù)網(wǎng)格。Sidecars處理服務(wù)之間的通信,也就是說所有的流量都會通過網(wǎng)格并且該透明層可以控制服務(wù)之間如何交互。
 

服務(wù)網(wǎng)格通過由API控制的組件提供可觀察性、服務(wù)發(fā)現(xiàn)以及負(fù)載均衡等。

 

實際上,如果一個服務(wù)要調(diào)用另一個服務(wù),它不會直接調(diào)用目標(biāo)服務(wù)。而是先將請求路由到本地代理,然后代理再將該請求路由到目標(biāo)服務(wù)。這一過程意味著服務(wù)實例不會和其他服務(wù)直接接觸,僅與本地代理進(jìn)行通信。
 
服務(wù)網(wǎng)格數(shù)據(jù)平面的關(guān)鍵:層層剖析Envoy配置
 
根據(jù)ThoughtWorks Technology Radar(這是一份半年度的文檔,用于評估現(xiàn)有技術(shù)和新生技術(shù)的風(fēng)險和收益)指出,“服務(wù)網(wǎng)格提供一致的發(fā)現(xiàn)、安全性、跟蹤(tracing)、監(jiān)控以及故障處理,而無需共享資源(如API網(wǎng)關(guān)或ESB)。一個十分典型的用例是輕量的反向代理進(jìn)程會與每個服務(wù)進(jìn)程或單獨的容器一起部署?!?/p>

 
當(dāng)談到服務(wù)網(wǎng)格時,不可避免談到的是“sidecar”——可用于每個服務(wù)實例的代理。每個sidecar負(fù)責(zé)管理一個服務(wù)的一個實例。我們將在本文中進(jìn)一步詳細(xì)討論sidecar。
 

服務(wù)網(wǎng)格可以交付什么?

 
服務(wù)網(wǎng)格數(shù)據(jù)平面的關(guān)鍵:層層剖析Envoy配置
 
當(dāng)前,越來越多的企業(yè)和組織開始轉(zhuǎn)向微服務(wù)架構(gòu)。這樣的企業(yè)需要服務(wù)網(wǎng)格所提供的上述功能。解耦庫的使用或自定義代碼的方法無疑是贏家。
 

為什么使用Envoy?

 
Envoy不是構(gòu)建一個服務(wù)網(wǎng)格的唯一選擇,市面上還有其他的代理如Nginx、Traefik等。我之所以選擇Envoy,這個用C++編寫的高性能代理,是因為我更喜歡Envoy的輕量、強(qiáng)大的路由,及其提供的可觀察性和可擴(kuò)展性。

 

讓我們首先構(gòu)建1個包含3個服務(wù)的服務(wù)網(wǎng)格設(shè)置,這是我們正在嘗試構(gòu)建的架構(gòu):
 
服務(wù)網(wǎng)格數(shù)據(jù)平面的關(guān)鍵:層層剖析Envoy配置
 

Front Envoy

 
在我們的設(shè)置中Front Envoy是一個邊緣代理,我們通常在其中執(zhí)行TLS終止、身份驗證、生成請求頭等操作。

 

我們來看看Front Envoy配置:
 

---
admin:
  access_log_path: "/tmp/admin_access.log"
  address: 
    socket_address: 
      address: "127.0.0.1"
      port_value: 9901
static_resources: 
  listeners:
    - 
      name: "http_listener"
      address: 
        socket_address: 
          address: "0.0.0.0"
          port_value: 80
      filter_chains:
          filters: 
            - 
              name: "envoy.http_connection_manager"
              config:
                stat_prefix: "ingress"
                route_config: 
                  name: "local_route"
                  virtual_hosts: 
                    - 
                      name: "http-route"
                      domains: 
                        - "*"
                      routes: 
                        - 
                          match: 
                            prefix: "/"
                          route:
                            cluster: "service_a"
                http_filters:
                  - 
                    name: "envoy.router"
  clusters:
    - 
      name: "service_a"
      connect_timeout: "0.25s"
      type: "strict_dns"
      lb_policy: "ROUND_ROBIN"
      hosts:
        - 
          socket_address: 
            address: "service_a_envoy"
            port_value: 8786

 
Envoy配置主要由以下部分組成:
 

1、 監(jiān)聽器(Listener)

2、 路由

3、 集群

4、 端點
 

監(jiān)聽器

 

一個或多個監(jiān)聽器可以在單個Envoy實例中運(yùn)行。在以上9到36行的代碼提到了當(dāng)前監(jiān)聽器的地址和端口。每個監(jiān)聽器也可以有一個或多個網(wǎng)絡(luò)過濾器。這些過濾器可以啟用路由、tls終止、流量轉(zhuǎn)移等活動。除了envoy.http_connection_manager使用的是內(nèi)置過濾器之外,Envoy還有其他幾個過濾器。
 

路 由

 

22行到34行代碼為過濾器配置了路由規(guī)范,同時它也指定了我們所接受請求的域以及路由匹配器。路由匹配器可以根據(jù)配置的規(guī)則匹配每個請求,并將請求轉(zhuǎn)發(fā)到適當(dāng)?shù)募骸?br/> 

集 群

 

集群是Envoy將流量路由到的上游服務(wù)規(guī)范。41行到48行代碼定義了“Service A”,這是Front Envoy要通信的唯一上游?!癱onnect_timeout”是在返回503之前建立與上游服務(wù)的連接的時間限制。

 

通常情況下,有多個“Serivce A”實例,并且Envoy支持多種負(fù)載均衡算法來路由流量。在本例中,我們使用了一個簡單的循環(huán)算法。
 

端 點

 

“host”指定我們要將流量路由到的Service A的實例。在本例中,我們只有1個實例。

 

第47行代碼沒有直接與Service A進(jìn)行通信,而是與Service A的Envoy代理實例進(jìn)行通信,該代理將路由到本地Service A實例。
 

我們還可以利用返回Service A的所有實例的服務(wù)名稱(如Kubernetes中的headless服務(wù)),來執(zhí)行客戶端負(fù)載均衡。Envoy緩存Service A的所有host,并每5秒刷新一次host列表。

 

此外,Envoy還支持主動和被動的健康檢查。因此,如果我們要進(jìn)行主動健康檢查,我們需要在集群配置部分對其進(jìn)行配置。
 

其 他

 

第2行到第7行配置了管理服務(wù)器,它能夠幫助查看配置、更改日志級別、查看統(tǒng)計信息等。

 

第8行的“static_resources”可以手動加載所有配置。我們將在下文討論如何動態(tài)地執(zhí)行此操作。

 

雖然這里描述了許多其他配置,但是我們的目標(biāo)不是全面介紹所有配置,而是以最少的配置開始。
 

Service A

 

這是Service A的Envoy配置:
 


admin:
  access_log_path: "/tmp/admin_access.log"
  address: 
    socket_address: 
      address: "127.0.0.1"
      port_value: 9901
static_resources:
  listeners:

    -
      name: "service-a-svc-http-listener"
      address:
        socket_address:
          address: "0.0.0.0"
          port_value: 8786
      filter_chains:
        -
          filters:
            -
              name: "envoy.http_connection_manager"
              config:
                stat_prefix: "ingress"
                codec_type: "AUTO"
                route_config:
                  name: "service-a-svc-http-route"
                  virtual_hosts:
                    -
                      name: "service-a-svc-http-route"
                      domains:
                        - "*"
                      routes:
                        -
                          match:
                            prefix: "/"
                          route:
                            cluster: "service_a"
                http_filters:
                  -
                    name: "envoy.router"
    -
      name: "service-b-svc-http-listener"
      address:
        socket_address:
          address: "0.0.0.0"
          port_value: 8788
      filter_chains:
        -
          filters:
            -
              name: "envoy.http_connection_manager"
              config:
                stat_prefix: "egress"
                codec_type: "AUTO"
                route_config:
                  name: "service-b-svc-http-route"
                  virtual_hosts:
                    -
                      name: "service-b-svc-http-route"
                      domains:
                        - "*"
                      routes:
                        -
                          match:
                            prefix: "/"
                          route:
                            cluster: "service_b"
                http_filters:
                  -
                    name: "envoy.router"

    -
      name: "service-c-svc-http-listener"
      address:
        socket_address:
          address: "0.0.0.0"
          port_value: 8791
      filter_chains:
        -
          filters:
            -
              name: "envoy.http_connection_manager"
              config:
                stat_prefix: "egress"
                codec_type: "AUTO"
                route_config:
                  name: "service-b-svc-http-route"
                  virtual_hosts:
                    -
                      name: "service-b-svc-http-route"
                      domains:
                        - "*"
                      routes:
                        -
                          match:
                            prefix: "/"
                          route:
                            cluster: "service_c"
                http_filters:
                  -
                    name: "envoy.router"                                
  clusters:
      -
        name: "service_a"
        connect_timeout: "0.25s"
        type: "strict_dns"
        lb_policy: "ROUND_ROBIN"
        hosts:
          -
            socket_address:
              address: "service_a"
              port_value: 8081  
      -
        name: "service_b"
        connect_timeout: "0.25s"
        type: "strict_dns"
        lb_policy: "ROUND_ROBIN"
        hosts:
          -
            socket_address:
              address: "service_b_envoy"
              port_value: 8789

      -
        name: "service_c"
        connect_timeout: "0.25s"
        type: "strict_dns"
        lb_policy: "ROUND_ROBIN"
        hosts:
          -
            socket_address:
              address: "service_c_envoy"
              port_value: 8790

 
11行到39行定義了一個監(jiān)聽器來路由流量到實際的Service A實例。在103行到111行中找到service_a實例的相應(yīng)集群定義。

 

Service A與Service B和Service C進(jìn)行通信,它指向了兩個以上的監(jiān)聽器以及集群。在本例中,我們?yōu)槊總€上游(localhost、Service B和Service C)分離了監(jiān)聽器。另一種方法是使用單個監(jiān)聽器,并根據(jù)URL或請求頭路由到任意上游。
 

Service B 和 Service C

 

Service B和Service C處于葉級,除了本地主機(jī)服務(wù)實例外,不與任何其他上游通信。因此其配置十分簡單。
 

而讓事情變得復(fù)雜的是上述配置中的單個監(jiān)聽器和單個集群。
 

配置完成后,我們將此設(shè)置部署到Kubernetes或使用docker-compose對其進(jìn)行測試。你可以運(yùn)行docker-compose builddocker-compose up并點擊localhost:8080,以查看請求是否成功通過所有服務(wù)和Envoy代理。我們可以使用日志對其進(jìn)行驗證。
 

Envoy xDS

 

我們?yōu)槊總€sidecar提供了配置,并且根據(jù)不同的服務(wù),服務(wù)之間的配置也有所不同。雖然我們可以手動制作和管理sidecar配置,但最初至少要提供2或3個服務(wù),并且隨著服務(wù)數(shù)量的增加,配置會變得十分復(fù)雜。此外,每次sidecar配置更改時,你都必須重新啟動Envoy實例,以使更改生效。

 

正如上文所討論的,我們可以通過使用API server來避免手動配置并加載所有組件:集群(CDS)、端點(EDS)、監(jiān)聽器(LDS)以及路由(RDS)。所以每個sidecar將與API server通信并接收配置。當(dāng)新配置更新到API server時,它將自動反映在Envoy實例中,從而避免了重新啟動。

 

你可以在以下鏈接中了解關(guān)于動態(tài)配置的信息:
 
https://www.envoyproxy.io/docs/envoy/latest/configuration/overview/v2_overview#dynamic

 

這有一個簡單的xDS server:
 
https://github.com/tak2siva/Envoy-Pilot
 

如何在Kubernetes中實現(xiàn)

 

本部分將討論如果我們要在Kubernetes中實現(xiàn)所討論的設(shè)置該怎么辦。以下是架構(gòu)圖:
 
因此,將需要更改:

  • Pod

  • 服務(wù)
     

    部署Pod

 

盡管Pod規(guī)范中僅定義了一個容器——按照定義,一個Pod可以容納一個或多個容器。為了對每個服務(wù)實例運(yùn)行sidecar代理,我們將Envoy容器添加到每個Pod中。為了與外界通信,服務(wù)容器將通過localhost與Envoy容器進(jìn)行對話。
 
部署文件如下所示:
 


admin:
  access_log_path: "/tmp/admin_access.log"
  address: 
    socket_address: 
      address: "127.0.0.1"
      port_value: 9901
static_resources:
  listeners:

    -
      name: "service-b-svc-http-listener"
      address:
        socket_address:
          address: "0.0.0.0"
          port_value: 8789
      filter_chains:
        -
          filters:
            -
              name: "envoy.http_connection_manager"
              config:
                stat_prefix: "ingress"
                codec_type: "AUTO"
                route_config:
                  name: "service-b-svc-http-route"
                  virtual_hosts:
                    -
                      name: "service-b-svc-http-route"
                      domains:
                        - "*"
                      routes:
                        -
                          match:
                            prefix: "/"
                          route:
                            cluster: "service_b"
                http_filters:
                  -
                    name: "envoy.router"

  clusters:
      -
        name: "service_b"
        connect_timeout: "0.25s"
        type: "strict_dns"
        lb_policy: "ROUND_ROBIN"
        hosts:
          -
            socket_address:
              address: "service_b"
              port_value: 8082

在容器部分添加了Envoy sidecar,并且在33到39行的configmap中我們掛載了我們的Envoy配置文件。
 

更改服務(wù)

 
Kubernetes服務(wù)負(fù)責(zé)維護(hù)Pod端點列表,該列表可以路由流量。盡管kube-proxy通常處理Pod端點之間的負(fù)載均衡,但在本例中,我們將執(zhí)行客戶端負(fù)載均衡,并且我們不希望kube-proxy進(jìn)行負(fù)載均衡。此外,我們想要提取Pod端點列表并對其進(jìn)行負(fù)載均衡。為此,我們需要使用“headless服務(wù)“來返回端點列表。

 

如下所示:

 


apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: servicea
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: servicea
    spec:
      containers:
      - name: servicea
        image: dnivra26/servicea:0.6
        ports:
        - containerPort: 8081
          name: svc-port
          protocol: TCP
      - name: envoy
        image: envoyproxy/envoy:latest
        ports:
          - containerPort: 9901
            protocol: TCP
            name: envoy-admin
          - containerPort: 8786
            protocol: TCP
            name: envoy-web
        volumeMounts:
          - name: envoy-config-volume
            mountPath: /etc/envoy-config/
        command: ["/usr/local/bin/envoy"]
        args: ["-c", "/etc/envoy-config/config.yaml", "--v2-config-only", "-l", "info","--service-cluster","servicea","--service-node","servicea", "--log-format", "[METADATA][%Y-%m-%d %T.%e][%t][%l][%n] %v"]
      volumes:
        - name: envoy-config-volume
          configMap:
            name: sidecar-config
            items:
              - key: envoy-config
                path: config.yaml

 
有兩件事需要注意。一是第6行使服務(wù)變成headless,二是我們不是將Kubernetes服務(wù)端口映射到應(yīng)用程序的服務(wù)端口,而是映射到Envoy監(jiān)聽器端口。這意味著,流量首先通向Envoy。即便如此,Kubernetes也可以完美運(yùn)行。

 

在本文中,我們看到了如何使用Envoy代理構(gòu)建服務(wù)網(wǎng)格。其中,我們設(shè)置了所有通信都將通過網(wǎng)格。因此,現(xiàn)在網(wǎng)格不僅有大量有關(guān)流量的數(shù)據(jù),而且還具有控制權(quán)。

 

以下鏈接中你可以獲取我們所討論的配置和代碼:

https://github.com/dnivra26/envoy_servicemesh

 

原文鏈接:

https://www.thoughtworks.com/insights/blog/building-service-mesh-envoy-0

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI