天天看點

Envoy HTTP路由

HTTP 路由功能

Envoy 包含一個 HTTP路由器過濾器,可以安裝它來執行進階路由任務。這對于處理邊緣流量(傳統的反向代理請求處理)以及建構服務 Envoy 網格(通常通過主機/授權 HTTP 标頭上的路由以到達特定的上遊服務叢集)都很有用。Envoy 還可以配置為正向代理。在轉發代理配置中,網格用戶端可以通過适當地将其 http 代理配置為 Envoy 來參與。在較進階别,路由器接收傳入的 HTTP 請求,将其與上遊叢集比對,擷取到上遊叢集中主機的 連接配接池,然後轉發請求。路由器過濾器支援以下功能:

  • 将域/權限映射到一組路由規則的虛拟主機。
  • 字首和精确路徑比對規則(區分大小寫和不區分大小寫)。
  • 正規表達式路徑比對規則。
  • 虛拟主機級别的TLS 重定向。
  • 路由級别的路徑/主機重定向。
  • 路由級别的直接(非代理)HTTP 響應。
  • 顯式主機重寫。
  • 根據所選上遊主機的 DNS 名稱自動重寫主機。
  • 字首重寫。
  • 使用正規表達式和捕獲組進行路徑重寫。
  • 通過 HTTP 标頭或路由配置指定的請求重試。
  • 通過HTTP 标頭或路由配置指定的請求逾時。
  • 請求對沖以響應請求(每次嘗試)逾時而重試。
  • 流量通過運作時值從一個上遊叢集轉移到另一個叢集(請參閱流量轉移/拆分)。
  • 使用基于權重/百分比的路由将流量拆分到多個上遊叢集(請參閱流量轉移/拆分)。
  • 任意标頭比對路由規則。
  • 虛拟叢集規範。虛拟叢集是在虛拟主機級别指定的,Envoy 使用它在标準叢集級别的基礎上生成額外的統計資訊。虛拟叢集可以使用正規表達式比對。
  • 基于優先級的路由。
  • 基于哈希政策的路由。
  • 非 tls 轉發代理支援絕對 url 。

将域名映射到虛拟主機

  • domains:
  • 将請求封包中的host标頭值依次與路由表中定義的各Virtualhost的domain屬性值進行比較,并于第一次比對時終止搜尋;
  • 域名搜尋順序:
  1. 精确比對:​

    ​www.foo.com​

    ​.
  2. 左字首通配符比對:​

    ​*.foo.com​

    ​或​

    ​*-bar.foo.com​

    ​.
  3. 右字尾通配符比對:​

    ​foo.*​

    ​或​

    ​foo-*​

    ​.
  4. ​*​

    ​比對任何域的特殊通配符。
  • 通配符将不比對空字元串。例如​

    ​*-bar.foo.com​

    ​​将比對​

    ​baz-bar.foo.com​

    ​​但不比對​

    ​-bar.foo.com​

    ​​。最長的通配符首先比對。整個路由配置中隻有一個虛拟主機可以比對上​

    ​*​

    ​。域在所有虛拟主機中必須是唯一的,否則配置将無法加載。

路由配置

路由比對(match)

  • 基于prefix、path、safe_regex和connect_matchter 四者其中任何一個進行URL比對
  • 基礎比對:prefix、path和safe_regex
  • 可額外根據headers和query_parameters完成封包比對
  • 進階比對:headers和query_patameters

路由

  • 支援cluster、weighted_clusters和cluster_header三者之一定義目标路由;
  • 發期間可根據prefix_rewrite和host_rewrite完成URL重寫;
  • 可額外配置流量管理機制,例如
  • 韌性相關:timeout、retry_policy
  • 測試相關:request_mirror_policy
  • 流控相關:rate_limits
  • 通路控制相關: cors
Envoy HTTP路由

路由比對

路由比對條件

  • 比對條件是定義的檢測機制,用于過濾出符合條件的請求并對其作出所需的處理,例如路由、重定向或直接響應等;
  • 必須要定義prefix、path和regex三種比對條件中的一種形式
  • 除了必須設定上述三者其中之一外,還可額外完成如下限定
  • 區分字元大小寫(case_sensitive)
  • 比對指定的運作鍵值表示的比例進行流量遷移(runtime_fraction);
  • 不斷地修改運作時鍵值完成流量遷移
  • 基于标頭的路由:比對指定的一組标頭(headers);
  • 基于參數的路由:比對指定的一組URL查詢參數(query_parameters);
  • 僅比對grpc流量(grpc);

基于标頭的路由比對

route.HeaderMatcher

  • 指定的路由需要額外比對指定的一組标頭
  • 路由器将根據路由配置中的所有指定标頭檢查請求的标頭
  • 若路由中指定的所有标頭都存在于請求中且具有相同值,則比對
  • 若配置中未指定标頭值,則基于标頭的存在性進行判斷
  • 标頭及其值的上述檢查機制僅能定義exact_match、safe_regex_match range_match、 present_match 、prefix_match 、suffix_match、contains_match及string_match其中之一;

基于标頭的路由比對格式

檢視代碼

--
  listeners: 
    ...
    filter_chains: 
      filter_chain_match: {...}
      filters: 
        name: ...
        typed_config: ...
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
            ...
            route_config: 
              name: ...
              virtual_hosts: 
                name: ...
                domains: []
                routes: 
                  name: ...
                  match: 
                    ...
                    headers:
                      name: ...
                      exact_match: ...          # 精确值比對
                      safe_regex_match: {...}   # 正規表達式模式比對
                      range_match: {...}        # 值範圍比對,檢查标頭值是否在指定的範圍内
                      present_match: ...        # 标頭存在性比對,檢查标頭存在與否
                      prefix_match: ...         # 值字首比對
                      suffix_match: ...         # 值字尾比對
                      contains_match: ...       # 檢測标頭值是否包含此處指定的字元串
                      string_match: {...}       # 檢測标頭值是否比對該處指定的字元串
                      invert_match: ...         # 是否将比對的檢測結果取反,即以不滿足條件為”真”,預設為fase
                      treat_missing_header_as_empty: ...  # 如果标頭比對規則指定的标頭不存在,則此标頭值将被視為空,預設為fase      

基于查詢參數的路由比對

route.QueryParameterMatcher

  • 指定的路由需要額外比對的一組URL查詢參數
  • 路由器将根據路由配置中指定的所有查詢參數檢查路徑頭中的查詢字元串
  • 查詢參數比對将請求的URL中查詢字元串視為以&符号分隔的“鍵”或“鍵=值”元素清單
  • 若存在指定的查詢參數,則所有參數都必須與URL中的查詢字元串比對
  • 比對條件指定為value、regex、string_match或present_match其中之一

基于查詢參數的路由比對格式

檢視代碼

--
  listeners: 
    ...
    filter_chains: 
      filter_chain_match: {...}
      filters: 
        name: ...
        typed_config: ...
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
            ...
            route_config: 
              name: ...
              virtual_hosts: 
                name: ...
                domains: []
                routes: 
                  name: ...
                  match: 
                    ...
                    query_parameters:
                      name: ...
                      string_match: # 參數值的字元串比對檢查,支援使用以下五種檢查方式其中之一進行字元串比對
                        exact: ...
                        prefix: ...
                        suffix: ...
                        safe_regex: {...}  
                        contains: ...
                        ignore_case: ...
                      present_match: ...      

路由目标

路由到指定叢集

route

  • 比對到的流量可路由至如下三種目标之一
  • cluster:路由至指定的上遊叢集;
  • cluster_header:路由至請求标頭中由cluster_header的值指定的上遊叢集;
  • weighted_clusters:基于權重将請求路由至多個上遊叢集,進行流量分割;

路由到指定叢集格式

檢視代碼

--
  listeners: 
    ...
    filter_chains: 
      filter_chain_match: {...}
      filters: 
        name: ...
        typed_config: ...
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
            ...
            route_config: 
              name: ...
              virtual_hosts: 
                name: ...
                domains: []
                routes: 
                  name: ...
                  route:
                    cluster: ...             # 路由到指定的目标叢集
                    cluster_header: ...      
                    weighted_clusters: {...} # 路由并按權重比例配置設定到多個上遊叢集
                    cluster_specifier_plugin: ...
                    inline_cluster_specifier_plugin: {...}
                    cluster_not_found_response_code: ...
                    metadata_match: {...}
                    prefix_rewrite: ...
                    regex_rewrite: {...}
                    host_rewrite_literal: ...
                    auto_host_rewrite: {...}
                    host_rewrite_header: ...
                    host_rewrite_path_regex: {...}
                    append_x_forwarded_host: ...
                    timeout: {...}
                    idle_timeout: {...}
                    early_data_policy: {...}
                    retry_policy: {...}
                    request_mirror_policies: []
                    priority: ...
                    rate_limits: []
                    include_vh_rate_limits: {...}
                    hash_policy: []
                    cors: {...}
                    max_grpc_timeout: {...}
                    grpc_timeout_offset: {...}
                    upgrade_configs: []
                    internal_redirect_policy: {...}
                    internal_redirect_action: ...
                    max_internal_redirects: {...}
                    hedge_policy: {...}
                    max_stream_duration: {...}      

重定向

redirect

  • 為請求響應一個301應答,進而将請求從一個URL永久重定向至另一個URL
  • Envoy支援如下重定向行為
  • 協定重定向:https_redirect或scheme_redirect二者隻能使用其一;
  • 主機重定向:host_redirect
  • 端口重定向:port_redirect
  • 路徑重定向:path_redirect
  • 路徑字首重定向:prefix_redirect
  • 正規表達式模式定義的重定向:regex_rewrite
  • 重設響應碼:response_code,預設為301
  • strip_query:是否在重定向期間删除URL中的查詢參數,預設為false;

重定向格式

檢視代碼

--
  listeners: 
    ...
    filter_chains: 
      filter_chain_match: {...}
      filters: 
        name: ...
        typed_config: ...
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
            ...
            route_config: 
              name: ...
              virtual_hosts: 
                name: ...
                domains: []
                routes: 
                  name: ...
                  redirect:
                    https_redirect: ...
                    scheme_redirect: ...
                    host_redirect: ...
                    port_redirect: ...
                    path_redirect: ...
                    prefix_rewrite: ...
                    regex_rewrite: {...}
                    response_code: ...
                    strip_query: ...      

直接響應請求

direct_response

  • Envoy還可以直接響應請求
  • status:指定響應碼;
  • body:響應正文,可省略,預設為空;需要指定時應該由body通過如下三種方式之一給出資料源
  • filename:本地檔案資料源;
  • inline_bytes:直接給出的内聯位元組;
  • inline_string:直接給出的内聯字元串;

直接響應請求格式

檢視代碼

--
  listeners: 
    ...
    filter_chains: 
      filter_chain_match: {...}
      filters: 
        name: ...
        typed_config: ...
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
            ...
            route_config: 
              name: ...
              virtual_hosts: 
                name: ...
                domains: []
                routes: 
                  name: ...
                  direct_response:
                    status: ...
                    body: 
                      filename: ...           # 本地檔案資料源。必須設定filename、inline_bytes、inline_string、environment_variable之一。
                      inline_bytes: ...       # 直接給出的内聯位元組
                      inline_string: ...      # 直接給出的内聯字元串
                      environment_variable: ...  # 環境變量資料源      

路由政策

基礎路由配置

  • 在match中簡單通過prefix、path或regex指定比對條件
  • 将比對到的請求進行重定向、直接響應或路由到指定目标叢集

進階路由政策

  • 在match中通過prefix、path或regex指定比對條件,并使用進階比對機制
  • 結合runtime_fraction按比例切割流量
  • 結合headers按指定的标頭路由,例如基于cookie進行,将其值分組後路由到不同目标;
  • 結合query_parameters按指定的參數路由,例如基于參數group進行,将其值分組後路由到不同的目标;
  • 提示:可靈活組合多種條件建構複雜的比對機制;
  • 複雜路由目标
  • 結合請求封包标頭中cluster_header的值進行定向路由;
  • weighted_clusters:将請求根據目标叢集權重進行流量分割;
  • 配置進階路由屬性,例如重試、逾時、CORS、限速等;

路由配置示例

示例一

envoy配置檔案

檢視代碼

admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    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
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: vh_001
              domains: ["foo.com", "*.foo.com", "foo.*"]
              routes:
              - match:
                  path: "/service/blue"
                route:
                  cluster: blue
              - match:
                  safe_regex: 
                    google_re2: {}
                    regex: "^/service/.*blue$"
                redirect:
                  path_redirect: "/service/blue"
              - match:
                  prefix: "/service/yellow"
                direct_response:
                  status: 200
                  body:
                    inline_string: "This page will be provided soon later.\n"
              - match:
                  prefix: "/"
                route:
                  cluster: red
            - name: vh_002
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: gray
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
  - name: blue
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    load_assignment:
      cluster_name: blue
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: blue
                port_value: 80

  - name: red
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    load_assignment:
      cluster_name: red
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: red
                port_value: 80

  - name: green
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    load_assignment:
      cluster_name: green
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: green
                port_value: 80

  - name: gray
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    load_assignment:
      cluster_name: gray
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: gray
                port_value: 80      

測試用例

測試domain的比對機制

# 首先通路無法比對到vh_001的域名
curl -H "Host: www.roo.com" http://ip/service/a

# 接着通路可以比對vh_001的域名
curl -H "Host: www.foo.com" http://ip/service/a      

測試路由比對機制

# 首先通路“/service/blue”
curl -H "Host: www.foo.com" http://ip/service/blue

# 接着通路“/service/dark_blue”
curl -I -H "Host: www.foo.com" http://ip/service/dark_blue
HTTP/1.1 301 Moved Permanently
location: http://www.foo.com/service/blue
date: Fri, 29 Oct 2021 03:02:59 GMT
server: envoy
transfer-encoding: chunked

# 然後通路“/serevice/yellow”
curl -H "Host: www.foo.com" http://ip/service/yellow
This page will be provided soon later.      

示例二

envoy配置

檢視代碼

admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    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
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: vh_001
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                  headers:
                  - name: X-Canary
                    exact_match: "true"
                route:
                  cluster: demoappv12
              - match:
                  prefix: "/"
                  query_parameters:
                  - name: "username"
                    string_match:
                      prefix: "vip_"
                route:
                  cluster: demoappv11
              - match:
                  prefix: "/"
                route:
                  cluster: demoappv10
          http_filters:
          - name: envoy.filters.http.router

  clusters:
  - name: demoappv10
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: demoappv10
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: demoappv10
                port_value: 80

  - name: demoappv11
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: demoappv11
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: demoappv11
                port_value: 80

  - name: demoappv12
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: demoappv12
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: demoappv12
                port_value: 80      

測試用例

測試使用“X-Canary: true”村頭的請求

# 使用特定的标頭發起請求
curl -H "X-Canary: true" http://ip/hostname  
ServerName: demoapp-v1.2-1      

測試使用特定的查詢條件

# 在請求中使用特定的查詢條件
curl http://ip/hostname?username=vip_123
ServerName: demoapp-v1.1-1

curl http://ip/hostname?username=vip_456  
ServerName: demoapp-v1.1-2      

參考文檔

​​https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/http/http_routing​​

​​https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route.proto#envoy-v3-api-msg-config-route-v3-routeconfiguration​​

繼續閱讀