從 Nginx 遷移到 Envoy 代理

你好,哈布爾! 我提請您注意該帖子的翻譯: 從 Nginx 遷移到 Envoy 代理.

Envoy 是一個專為個體服務和應用程式設計的高效能分散式代理伺服器(以 C++ 編寫),也是專為大型微服務「服務網格」架構設計的通訊匯流排和「通用資料平面」。 在創建時,考慮了NGINX、HAProxy、硬體負載平衡器和雲端負載平衡器等伺服器開發過程中出現的問題的解決方案。 Envoy 與每個應用程式一起工作,並抽象化網路以提供通用功能,無論平台如何。 當基礎架構中的所有服務流量都流經 Envoy 網格時,可以輕鬆地以一致的可觀察性視覺化問題區域、調整整體效能以及在特定位置添加核心功能。

功能

  • 進程外架構:envoy 是一個獨立的高效能伺服器,佔用少量 RAM。 它可以與任何應用程式語言或框架結合使用。
  • http/2 和 grpc 支援:envoy 對傳入和傳出連接提供一流的 http/2 和 grpc 支援。 這是一個從http/1.1到http/2的透明代理。
  • 進階負載平衡:envoy 支援進階負載平衡功能,包括自動重試、斷鍊、全域速率限制、請求陰影、本地區域負載平衡等。
  • 配置管理 API:envoy 提供了強大的 API 來動態管理您的配置。
  • 可觀測性:L7 流量的深度可觀測性,原生支援分散式追蹤以及 mongodb、dynamodb 和許多其他應用程式的可觀測性。

步驟 1 — NGINX 設定範例

該腳本使用特製文件 nginx.conf,基於完整範例 NGINX 維基。 您可以透過開啟來查看編輯器中的配置 nginx.conf

Nginx 來源配置

user  www www;
pid /var/run/nginx.pid;
worker_processes  2;

events {
  worker_connections   2000;
}

http {
  gzip on;
  gzip_min_length  1100;
  gzip_buffers     4 8k;
  gzip_types       text/plain;

  log_format main      '$remote_addr - $remote_user [$time_local]  '
    '"$request" $status $bytes_sent '
    '"$http_referer" "$http_user_agent" '
    '"$gzip_ratio"';

  log_format download  '$remote_addr - $remote_user [$time_local]  '
    '"$request" $status $bytes_sent '
    '"$http_referer" "$http_user_agent" '
    '"$http_range" "$sent_http_content_range"';

  upstream targetCluster {
    172.18.0.3:80;
    172.18.0.4:80;
  }

  server {
    listen        8080;
    server_name   one.example.com  www.one.example.com;

    access_log   /var/log/nginx.access_log  main;
    error_log  /var/log/nginx.error_log  info;

    location / {
      proxy_pass         http://targetCluster/;
      proxy_redirect     off;

      proxy_set_header   Host             $host;
      proxy_set_header   X-Real-IP        $remote_addr;
    }
  }
}

NGINX 配置通常有三個關鍵要素:

  1. 設定 NGINX 伺服器、日誌結構和 Gzip 功能。 在所有情況下,這都是全域定義的。
  2. 配置 NGINX 以接受對主機的請求 one.example.com 在連接埠 8080 上。
  3. 設定目標位置,如何處理 URL 不同部分的流量。

並非所有配置都適用於 Envoy Proxy,且您不需要配置某些設定。 特使代理有 四種關鍵類型,支援 NGINX 提供的核心基礎設施。 核心是:

  • 聽眾: 它們確定 Envoy 代理如何接受傳入請求。 Envoy Proxy 目前僅支援基於 TCP 的偵聽器。 一旦建立連接,它就會被傳遞到一組過濾器進行處理。
  • 過濾器: 它們是可以處理傳入和傳出資料的管道架構的一部分。 此功能包括 Gzip 等過濾器,它在將資料發送到客戶端之前對其進行壓縮。
  • 路由器: 它們將流量轉送到所需的目的地(定義為叢集)。
  • 集群: 它們定義流量和配置參數的端點。

我們將使用這四個元件來建立 Envoy 代理程式配置以符合特定的 NGINX 配置。 Envoy 的目標是使用 API 和動態配置。 在這種情況下,基本配置將使用 NGINX 中的靜態硬編碼設定。

第 2 步 - NGINX 配置

第一部分 nginx.conf 定義了一些需要設定的 NGINX 內部結構。

工人連接

下面的配置決定了工作進程和連接的數量。 這表明 NGINX 將如何擴展以滿足需求。

worker_processes  2;

events {
  worker_connections   2000;
}

Envoy Proxy 以不同的方式管理工作流程和連線。

Envoy 為系統中的每個硬體執行緒建立一個工作執行緒。 每個工作執行緒執行一個非阻塞事件循環,負責

  1. 傾聽每位聽眾的心聲
  2. 接受新連接
  3. 為連接建立一組過濾器
  4. 在連線的生命週期內處理所有 I/O 操作。

所有進一步的連接處理完全在工作線程中處理,包括任何轉發行為。

對於 Envoy 中的每個工作線程,都有一個連線池。 因此,HTTP/2 連接池每次只為每個外部主機建立一個連接,如果有四個工作線程,則每個外部主機將有四個處於穩定狀態的 HTTP/2 連接。 透過將所有內容保留在一個工作線程中,幾乎所有程式碼都可以在不阻塞的情況下編寫,就像單線程一樣。 如果分配的工作執行緒多於必要的數量,則可能會導致記憶體浪費,創建大量空閒連接,並減少連接返回池的次數。

欲了解更多信息,請訪問 特使代理博客.

HTTP 設定

以下 NGINX 配置區塊定義了 HTTP 設定,例如:

  • 支援哪些 mime 類型
  • 預設逾時
  • Gzip 配置

您可以使用 Envoy Proxy 中的過濾器自訂這些方面,我們將在稍後討論。

第 3 步 - 伺服器配置

在 HTTP 設定區塊中,NGINX 設定指定偵聽連接埠 8080 並回應網域的傳入請求 one.example.com и www.one.example.com.

 server {
    listen        8080;
    server_name   one.example.com  www.one.example.com;

在 Envoy 內部,它由 Listeners 控制。

特使聽眾

開始使用 Envoy Proxy 的最重要的方面是定義您的偵聽器。 您需要建立一個設定檔來描述您希望如何執行 Envoy 實例。

下面的程式碼片段將建立一個新的偵聽器並將其綁定到連接埠 8080。此設定告訴 Envoy 代理程式應該為傳入請求綁定到哪些連接埠。

Envoy Proxy 使用 YAML 表示法進行設定。 有關此表示法的介紹,請參閱此處 鏈接.

Copy to Editorstatic_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }

無需定義 服務器名稱,因為 Envoy 代理過濾器將處理這個問題。

第 4 步 - 位置配置

當請求進入 NGINX 時,位置區塊決定如何處理流量以及將流量路由到何處。 在下面的片段中,該站點的所有流量都會傳輸到一個名為的上游(譯者註:上游通常是應用伺服器)集群 目標簇。 上游叢集定義應處理請求的節點。 我們將在下一步討論這個問題。

location / {
    proxy_pass         http://targetCluster/;
    proxy_redirect     off;

    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
}

在 Envoy,過濾器就是這樣做的。

特使過濾器

對於靜態配置,過濾器決定如何處理傳入請求。 在這種情況下,我們設定匹配的過濾器 伺服器名稱 在上一步。 當與某些域和路由相符的傳入請求到達時,流量將路由到叢集。 這相當於 NGINX 自下而上的配置。

Copy to Editor    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
                - "one.example.com"
                - "www.one.example.com"
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: targetCluster
          http_filters:
          - name: envoy.router

envoy.http_connection_manager 是 Envoy Proxy 中的內建濾鏡。 其他過濾器包括 Redis的, 蒙戈, TCP。 您可以在以下位置找到完整清單: 文件.

有關其他負載平衡策略的更多信息,請訪問 特使文檔.

第 5 步 - 代理和上游配置

在 NGINX 中,上游設定定義了一組將處理流量的目標伺服器。 在本例中,分配了兩個集群。

  upstream targetCluster {
    172.18.0.3:80;
    172.18.0.4:80;
  }

在 Envoy 中,這是由叢集管理的。

特使集群

上游等效項定義為叢集。 在這種情況下,將為流量提供服務的主機已被識別。 存取主機的方式(例如逾時)被定義為叢集配置。 這允許對延遲和負載平衡等方面進行更精細的控制。

Copy to Editor  clusters:
  - name: targetCluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    hosts: [
      { socket_address: { address: 172.18.0.3, port_value: 80 }},
      { socket_address: { address: 172.18.0.4, port_value: 80 }}
    ]

使用服務發現時 STRICT_DNS Envoy 將持續非同步解析指定的 DNS 目標。 DNS 結果傳回的每個 IP 位址都將被視為上游叢集中的明確主機。 這意味著如果請求傳回兩個 IP 位址,Envoy 將假定叢集中有兩台主機,且兩台主機都必須進行負載平衡。 如果從結果中刪除主機,Envoy 將假定它不再存在,並將從任何現有連接池中提取流量。

有關更多信息,請參閱 Envoy 代理文檔.

第 6 步 — 記錄訪問和錯誤

最後的配置就是註冊。 Envoy Proxy 沒有將錯誤日誌推送到磁碟,而是採用基於雲端的方法。 所有應用程式日誌都輸出到 標準輸出 и 斯特德.

當使用者提出請求時,存取日誌是可選的,並且預設為停用。 若要啟用 HTTP 請求的存取日誌,請啟用配置 訪問日誌 用於 HTTP 連線管理器。 該路徑可以是諸如 標準輸出,或磁碟上的文件,取決於您的要求。

以下配置將所有訪問日誌重新導向到 標準輸出 (譯者註 - 在 docker 內使用 envoy 需要 stdout。如果不使用 docker,則將 /dev/stdout 替換為常規日誌檔案的路徑)。 將程式碼片段複製到連線管理員的設定部分:

Copy to Clipboardaccess_log:
- name: envoy.file_access_log
  config:
    path: "/dev/stdout"

結果應該如下圖所示:

      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          access_log:
          - name: envoy.file_access_log
            config:
              path: "/dev/stdout"
          route_config:

預設情況下,Envoy 有一個格式字串,其中包含 HTTP 請求的詳細資訊:

[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"n

該格式字串的結果是:

[2018-11-23T04:51:00.281Z] "GET / HTTP/1.1" 200 - 0 58 4 1 "-" "curl/7.47.0" "f21ebd42-6770-4aa5-88d4-e56118165a7d" "one.example.com" "172.18.0.4:80"

可以透過設定格式欄位來自訂輸出內容。 例如:

access_log:
- name: envoy.file_access_log
  config:
    path: "/dev/stdout"
    format: "[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"n"

日誌行也可以透過設定欄位以JSON格式輸出 json_格式。 例如:

access_log:
- name: envoy.file_access_log
  config:
    path: "/dev/stdout"
    json_format: {"protocol": "%PROTOCOL%", "duration": "%DURATION%", "request_method": "%REQ(:METHOD)%"}

有關特使註冊方法的更多信息,請訪問

https://www.envoyproxy.io/docs/envoy/latest/configuration/access_log#config-access-log-format-dictionaries

日誌記錄並不是深入了解使用 Envoy 代理程式的唯一方法。 它內建了先進的追蹤和指標功能。 您可以在以下位置了解更多信息 追蹤文檔 或通過 互動式追蹤腳本.

第 7 步 - 啟動

您現在已將設定從 NGINX 移轉到 Envoy 代理程式。 最後一步是啟動 Envoy Proxy 實例來測試它。

以使用者身分執行

NGINX 配置行的頂部 使用者 www www; 指定以低權限使用者執行NGINX以提高安全性。

Envoy Proxy 採用雲端為基礎的方法來管理流程的擁有者。 當我們透過容器執行 Envoy Proxy 時,我們可以指定一個低特權使用者。

啟動 Envoy 代理

下面的命令將透過主機上的 Docker 容器執行 Envoy Proxy。 此命令使 Envoy 能夠偵聽連接埠 80 上的傳入請求。但是,根據偵聽器配置中的指定,Envoy 代理程式偵聽連接埠 8080 上的傳入流量。這允許進程作為低權限使用者執行。

docker run --name proxy1 -p 80:8080 --user 1000:1000 -v /root/envoy.yaml:/etc/envoy/envoy.yaml envoyproxy/envoy

測試

隨著代理運行,現在可以進行和處理測試。 以下 cURL 指令發出帶有代理設定中定義的主機標頭的請求。

curl -H "Host: one.example.com" localhost -i

HTTP 請求將導致錯誤 503。 這是因為上游連線不起作用且不可用。 因此,Envoy Proxy 沒有可用的請求目的地。 以下命令將啟動一系列與 Envoy 定義的配置相符的 HTTP 服務。

docker run -d katacoda/docker-http-server; docker run -d katacoda/docker-http-server;

借助可用的服務,Envoy 可以成功地將流量代理到其目的地。

curl -H "Host: one.example.com" localhost -i

您應該看到一個回應,指示哪個 Docker 容器處理了該請求。 在 Envoy 代理程式日誌中,您還應該看到存取字串輸出。

附加 HTTP 回應標頭

您將在實際請求的回應標頭中看到其他 HTTP 標頭。 標頭顯示上游主機處理請求所花費的時間。 以毫秒錶示。 如果客戶端想要確定與網路延遲相比的服務時間,這非常有用。

x-envoy-upstream-service-time: 0
server: envoy

最終配置

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
                - "one.example.com"
                - "www.one.example.com"
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: targetCluster
          http_filters:
          - name: envoy.router
          clusters:
  - name: targetCluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    hosts: [
      { socket_address: { address: 172.18.0.3, port_value: 80 }},
      { socket_address: { address: 172.18.0.4, port_value: 80 }}
    ]

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 0.0.0.0, port_value: 9090 }

譯者提供的附加資訊

安裝 Envoy Proxy 的說明可以在網站上找到 https://www.getenvoy.io/

預設情況下,rpm 沒有 systemd 服務配置。

新增systemd服務配置/etc/systemd/system/envoy.service:

[Unit]
Description=Envoy Proxy
Documentation=https://www.envoyproxy.io/
After=network-online.target
Requires=envoy-auth-server.service
Wants=nginx.service

[Service]
User=root
Restart=on-failure
ExecStart=/usr/bin/envoy --config-path /etc/envoy/config.yaml
[Install]
WantedBy=multi-user.target

您需要建立一個目錄 /etc/envoy/ 並將 config.yaml 配置放在那裡。

有一個使用 envoy 代理的電報聊天: https://t.me/envoyproxy_ru

Envoy 代理程式不支援提供靜態內容。 因此,誰可以投票支持該功能: https://github.com/envoyproxy/envoy/issues/378

只有註冊用戶才能參與調查。 登入, 請。

這篇文章是否鼓勵您安裝和測試 Envoy 代理程式?

  • 是的

  • 沒有

75 位用戶投票。 18 名用戶棄權。

來源: www.habr.com

添加評論