Envoy基礎知識

banq發表於2018-10-29

Envoy是與HAProxy和ngin一樣,都是同一領域中的新型網路代理/網路伺服器。
關於任何軟體,你可能會有幾種問題:
  • 怎麼用?
  • 為什麼有用?
  • 它在內部如何工作?


什麼是Envoy
它是一個網路代理。你編譯以後把它放在你的伺服器上,告訴它使用哪個配置檔案,然後就可以了!
下面可能是使用Envoy最簡單的例子。配置檔案見這裡。此案例在埠7777上啟動一個Web伺服器,該伺服器其實代理另外一個埠為8000的HTTP伺服器。
如果您有Docker,可以立即嘗試 - 只需下載配置,啟動Envoy docker映象,然後離開!

python -mSimpleHTTPServer & # Start a HTTP server on port 8000 wget https://gist.githubusercontent.com/jvns/340e4d20c83b16576c02efc08487ed54/raw/1ddc3038ed11c31ddc70be038fd23dddfa13f5d3/envoy_config.json docker run --rm --net host -v=$PWD:/config envoyproxy/envoy /usr/local/bin/envoy -c /config/envoy_config.json

以上命令將啟動Envoy HTTP伺服器,然後你就可以向Envoy發出請求!
curl localhost:7777
它會代理你的請求轉發到localhost:8000。

Envoy基本概念:叢集,監聽器,路由和過濾器
我們剛剛執行的這個小小的 envoy_config.json包含了所有基本的Envoy概念!
首先,有一個監聽器。這告訴Envoy繫結到一個埠,在本例中為7777:

"listeners": [{
  "address": { 
     "socket_address": { "address": "127.0.0.1", "port_value": 7777 } 


接下來,監聽器有一個過濾器。過濾器告訴監聽器如何處理它收到的請求,併為Envoy提供一系列過濾器。如果您需要做一些複雜的事情,那麼要對每個請求使用幾個過濾器。
有幾種不同型別的過濾器(請參閱TCP過濾器列表),但最重要的過濾器可能是envoy.http_connection_manager過濾器,它用於代理HTTP請求。HTTP連線管理器還有一個適用的HTTP過濾器列表請參閱HTTP過濾器列表)。其中最重要的是將envoy.router的請求路由到後端的過濾器。
在我們的示例中,有一個TCP過濾器(envoy.http_connection_manager)和1個HTTP過濾器(envoy.router):

"filters": [
 {
   "name": "envoy.http_connection_manager",
   "config": {
     "stat_prefix": "ingress_http",
     "http_filters": [{ "name": "envoy.router", "config": {} }],



接下來,我們來談談路由。您可能會注意到,到目前為止,我們還沒有告訴envoy.router過濾器如何處理它收到的請求,應該在哪裡代理這些請求?它應該匹配哪些路徑?在我們的例子中,答案將是“代理對localhost:8000的所有請求”。
envoy.router過濾器被配置為路由的陣列。在我們的例子中,只有一條路由規則。

"route_config": {
  "virtual_hosts": [
    {
      "name": "blah",
      "domains": "*",
      "routes": [
        {
          "match": { "prefix": "/" },
          "route": { "cluster": "banana" }



這裡定義了要匹配的域列表(這些域與請求主機頭匹配)。如果我們更換"domains": "*"到"domains": "my.cool.service",那麼我們就需要傳遞頭部資訊“Host: my.cool.service”才行。
你會注意到我們案例中被代理的埠 8000未在任何地方定義過。只是有"cluster": "banana"。什麼是叢集?
好吧,叢集是一個服務後端的地址(IP地址/埠)集合。例如,如果您有8臺機器執行同一種HTTP服務,那麼這個群集中可以有8臺host主機集合。每個服務都需要自己的叢集。這裡示例叢集非常簡單:它只是一個在localhost上執行的IP /埠。

"clusters":[
    {
      "name": "banana",
      "type": "STRICT_DNS",
      "connect_timeout": "1s",
      "hosts": [
        { "socket_address": { "address": "127.0.0.1", "port_value": 8000 } }
      ]
    }
  ]


手動編寫Envoy配置的提示
從頭開始編寫Envoy配置非常耗時 - 在Envoy儲存庫(https://github.com/envoyproxy/envoy)中有一些例子,但即使使用Envoy一年後,這個基本配置實際上還是花了我近45分鐘,以下是一些提示:

  • Envoy有兩種不同的API:v1和v2 API。許多較新的功能僅在v2 API中可用,我發現它的文件更容易導航,因為它是從protocol buffers自動生成的。(例如,叢集文件是從cds.proto生成的)
  • Envoy API文件中的一些好的起點:監聽器叢集過濾器虛擬主機。要獲得所需的所有資訊,您需要點選很多資料(例如,檢視如何為需要從“虛擬主機”啟動的路由配置群集,然後單擊route_config - > virtual_hosts - > routes - > route - > cluster ),但按照它這樣做還是奏效的。
  • 這個體系結構概述文件是有用的,並給出一些Envoy是如何配置的全面解釋。
  • 可以使用json或yaml配置Envoy。上面我使用了JSON。


使用伺服器配置Envoy
儘管我們從磁碟上的配置檔案開始,但使用Envoy與HAProxy或nginx完全不同的一點是,Envoy通常不是透過配置檔案配置的。相反,可以使用一個或多個動態的配置伺服器去更改配置Envoy 。
假設您正在使用Envoy將請求載入到50個後端伺服器,這些伺服器是您定期輪換出來的EC2例項。因此 http://your-website.com請求轉到Envoy,並被路由到Envoy 群集,該群集需要是這些伺服器的50個IP地址和埠的列表。
但是,如果隨著時間的推移, 也許你正在推出新的伺服器或者它們中一些會被終止。您可以透過定期更改Envoy配置檔案並重新啟動Envoy來處理此問題。要麼!!可以設定“群集發現服務”(或“CDS”),例如,可以查詢AWS API並將後端伺服器的所有IP返回給Envoy。
我不打算詳細介紹如何配置發現服務,但基本上它看起來像這樣(來自這個模板)。您可以告訴它重新整理的頻率以及伺服器的地址。

dynamic_resources:
  cds_config:
    api_config_source:
      cluster_names:
      - cds_cluster
      refresh_delay: 30s
...
  - name: cds_cluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    hosts:
    - socket_address:
        protocol: TCP
        address: cds.yourcompany.net
        port_value: 80



4種Envoy發現服務
有四種資源可以為Envoy設定發現服務 - 路由(“叢集應該請求這個HTTP頭轉到什麼地方”),叢集(“這個服務有哪些後端?”),監聽器(過濾器用於埠)和端點。這些分別稱為RDS,CDS,LDS和EDS。XDS是整體協議。
從頭開始編寫發現服務的最簡單方法可能是在Go中使用 go-control-plane庫。
從頭開始編寫Envoy配置服務絕對是可能的,但還有一些其他開源專案可以實現Envoy發現服務。以下是我所知道的,但我確信還有更多:

  • 有一個叫做rotor開源Envoy發現服務看起來很有趣。建造它的公司幾周前就關閉了
  • Istio(據我所知)基本上是一個Envoy發現服務,它使用來自Kubernetes API的資訊(例如叢集中的服務)來配置Envoy叢集/路由。它有自己的配置語言。
  • consul可能會增加對Envoy的支援(請參閱此部落格文章),但我並不完全瞭解那裡的狀態


什麼是服務網格?
我聽到的另一個術語是“服務網格”。基本上,“服務網格”是先安裝Envoy,並透過Envoy代理所有網路請求。它可以讓您更輕鬆地控制一堆不同的應用程式(可能用不同的程式語言編寫)如何相互通訊。

如果您的所有網路流量都是透過Envoy代理的,並且可從中央伺服器控制所有Envoy配置,那麼您可以:

  • 使用斷路器
  • 將請求路由到僅關閉例項
  • 端到端加密網路流量
  • 執行受控程式碼部署(想要只將20%的流量傳送到你剛上線的新伺服器上嗎?好的!)

無需在任何地方更改任何應用程式程式碼。基本上它是一個非常強大/靈活的分散式負載均衡器。
顯然,設定一堆發現服務並執行它們和使用它們,這種以複雜的方式配置內部網路基礎架構比單獨“編寫一個nginx配置檔案”要複雜得多,對大多數人來說。我不打算告訴你誰應該或不應該使用Envoy,但我的經驗是,像Kubernetes一樣,它既非常強大又非常複雜。

超時標題和指標衡量
我真正喜歡Envoy的一個原因是你可以傳遞一個HTTP標頭來告訴它如何重試/超時你的請求!這是驚人的,因為每種程式語言正確實現超時/重試邏輯的工作方式不同,人們總是弄錯。因此能夠傳遞如何測量指標就非常棒。
超時和重試頭都記錄在這裡,這裡是我的最愛:

  • x-envoy-max-retries:重試次數
  • x-envoy-retry-on:哪些失敗重試(例如5xx或connect-failure)
  • x-envoy-upstream-rq-timeout-ms:總超時
  • x-envoy-upstream-rq-per-try-timeout-ms:每次重試超時