本篇目錄
說明
在梳理開源的 API 網關和 ServiceMesh 項目時,最常遇到的一個詞是 Envoy,Ambassador、Contour、Gloo、Istio 等項目的數據平面都選用了 Envoy。Envoy 何德何能受到眾多項目的青睞? 掌握 Envoy 的脈絡只需 2 分鍾。
響應了時代號召的 Envoy
Envoy 是一個具有反向代理和負載均衡功能的單機軟件,和 Nginx、Haproxy 屬於同一類軟件。與 Nginx 和 Haproxy 相比,Envoy 有一個的重要特色是:自帶配置 API。
以 Nginx、Haproxy 為代表的負載均衡軟件,在過去很多年的實際應用中,很少會在軟件運行的時候更改配置,即使偶爾要修改配置文件,使用 reload 等命令重新加載就能滿足需要。
以 Kubernetes 為代表的 PaaS 或者容器管理系統出現后,IT 系統沿着“分工專業化、更少的人做更多同質事情”的路線演進,在當前的演進過程中,反向代理與負載均衡的能力被集中管理、統一提供。
這一演進在 Kubernetes 中體現為作為集群出口的 ingress 代理集群內所有服務,在以 istio 為代表的 ServiceMesh 中體現為分散在各處的代理軟件在同一個中心的控制下流轉流量。 無論是作為 Kubernetes 的出口,還是作為 Mesh 中的一個節點,承擔流量轉發功能的組件都需要完成一個挑戰: 在運行過程中頻繁的更新配置。
新場景中的更新的頻率是每秒 N 次,遠遠超過以往的場景中以周、月乃至年為周期的更新頻率。這種情形下,熱加載配置文件的方式明顯遲緩笨重,有一些項目通過開發一個帶有 API 功能的組件,實現生成配置文件、觸發熱加載的功能,以此賦予 Nginx、Haproxy 等傳統負載均衡軟件高頻更新配置的能力。
但是,如果有一個軟件原生帶有配置 API,且專注於數據平面,它作為可靠的第三方存在,能夠讓控制平面專心於規則管理,那么它是不是會很受歡迎呢?
Envoy 就是這樣一款軟件。注意,這里只是在交代背景,不為 envoy 吹票,nginx、haproxy 等都在更新演進以適應場景的變化。
Cluster、Listener 與 Filter
Envoy 的功能和使用細節繁雜,但只要搞清楚了 Cluster、Listener 和 Filter 的用途,就把握住了大方向。
Cluster 就是一組 IP,相當於 Nginx 中 upstream,負載均衡策略在 cluster 中設置,cluster 中可以是 IP 也可以是域名:
Listener 就是監聽地址和轉發規則:
難啃的配置文件
Envoy 的配置文件是從零開始了解 Envoy 時遇到的最大困難,它的配置比較繁雜,而且缺少系統的介紹。
配置文件在 envoy 啟動時,用 -c
指定,內容分為以下幾個部分:
{ "node": { "id": "...", "cluster": "...", "metadata": "{...}", "locality": "{...}", "build_version": "..." }, "static_resources": { "listeners": [], "clusters": [], "secrets": [] }, "dynamic_resources": { "lds_config": "{...}", "cds_config": "{...}", "ads_config": "{...}" }, "cluster_manager": { "local_cluster_name": "...", "outlier_detection": "{...}", "upstream_bind_config": "{...}", "load_stats_config": "{...}" }, "hds_config": { "api_type": "...", "cluster_names": [], "grpc_services": [], "refresh_delay": "{...}", "request_timeout": "{...}", "rate_limit_settings": "{...}" }, "flags_path": "...", "stats_sinks": [ { "name": "...", "config": "{...}" } ], "stats_config": { "stats_tags": [], "use_all_default_tags": "{...}", "stats_matcher": "{...}" }, "stats_flush_interval": "{...}", "watchdog": { "miss_timeout": "{...}", "megamiss_timeout": "{...}", "kill_timeout": "{...}", "multikill_timeout": "{...}" }, "tracing": {