前言
上一篇內容,我們詳細討論了envoy做服務發現,並且詳細討論了靜態配置與使用dns做服務發現,並且通過consul的詳細配置闡述了dns做服務發現的工作原理,但是也遺留了一個問題,一旦想要修改endpoint的配置
clusters:
- name: app_service
connect_timeout: 1s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: app_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: "backend-service"
port_value: 10000
比如我想改address: "backend-service",envoy並不會自動感知,還是需要重啓
envoy xDS簡介
xDS 不是一個單一的模塊,而是一組與 Envoy 服務發現相關、解耦的 API 接口集合
- CDS (Cluster Discovery Service): 集羣發現。獲取上游集羣的定義,即 Envoy 可以將流量路由到的一組邏輯上相似的上游主機
- EDS (Endpoint Discovery Service): 端點發現。這是最核心的服務發現模塊。它為每個集羣提供具體的、健康的網絡端點(如 IP:Port)列表。Envoy 支持通過 EDS 進行增量更新,從而實現高效、實時的服務實例變更
- LDS (Listener Discovery Service): 監聽器發現。獲取 Envoy 應該監聽的網絡地址、端口和過濾器鏈配置
- RDS (Route Discovery Service): 路由發現。獲取虛擬主機和路由規則配置,用於將流量定向到正確的集羣
- SDS (Secret Discovery Service): 密鑰發現。安全地獲取 TLS 證書和私鑰
- ADS (Aggregated Discovery Service): 聚合發現服務。一個特殊的 gRPC 端點,它將所有 xDS API 聚合到單個流中。這確保了配置更新的一致性和順序性,避免配置不一致導致的流量中斷
是不是看得腦袋嗡嗡的,沒關係,我們從最核心的入手,那就是EDS
envoy EDS
所謂EDS服務:
- 就是在envoy之外,有一個配置中心,之前直接配置在envoy的靜態配置,搬遷到配置中心來,新增和維護新規則都在配置中心維護
- 一旦配置有變更,配置中心會主動推送到envoy,讓其及時變更流量轉發配置
創建eds服務端
手搓一個最簡單的eds_server用來演示:
eds服務
該腳本啓動18000端口,接收gRPC請求,並且響應EDS,只要envoy來連接18000,就會下發endpoint到envoy
修改envoy配置
再修改一下envoy的配置:
...
clusters:
- name: backend_cluster
type: EDS
connect_timeout: 0.25s
lb_policy: ROUND_ROBIN
eds_cluster_config:
eds_config:
api_config_source:
api_type: GRPC
grpc_services:
- envoy_grpc:
cluster_name: eds_server
- name: eds_server
connect_timeout: 1s
type: STATIC
http2_protocol_options: {}
load_assignment:
cluster_name: eds_server
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 10.22.12.178
port_value: 18000
...
type: EDS説明了使用EDS作為服務發現,而EDS的相關信息在cluster_name: eds_server這裏定義eds_server是靜態的配置,訪問10.22.12.178:10000就能夠獲取獲取eds配置
驗證
配置完之後,首先啓動eds_server
▶ go run eds.go
2025/12/23 18:15:36 EDS server listening on :18000
修改envoy配置之後重啓,檢查eds_server的輸出:
▶ go run eds.go
2025/12/23 18:15:36 EDS server listening on :18000
2025/12/23 18:17:33 EDS stream connected
2025/12/23 18:17:33 >>> Sending EDS response version=1766484936064308385, nonce=1766485053421230413
2025/12/23 18:17:33 DiscoveryRequest resources=[backend_cluster] version="" nonce=""
2025/12/23 18:17:33 DiscoveryRequest resources=[backend_cluster] version="1766484936064308385" nonce="1766485053421230413"
成功了,啓動的envoy之後,envoy與eds_server建立連接,並且eds_server推送相關配置給envoy,再訪問一下試試curl 10.22.12.178:30785/test
[2025-12-23T10:20:44.892Z] "GET /test HTTP/1.0" 200 40 1 c40a5dd3-29b7-4d1b-b73d-e93b31b5f6e3 "curl/7.81.0" "-" 10.244.0.111:10000 backend_cluster -
[2025-12-23T10:20:46.003Z] "GET /test HTTP/1.0" 200 40 1 1656452c-4571-469b-b2b7-3d43bd703c6d "curl/7.81.0" "-" 10.244.0.114:10000 backend_cluster -
EDS小結

手搓了一個能夠響應eds的服務,並且將envoy指向該服務,envoy也能夠獲取後端endpoint的地址,成功轉發的請求
演示中的腳本,是將配置寫死在代碼中的
s.endpoints = []*endpointpb.LbEndpoint{
newEndpoint("10.244.0.111", 10000),
newEndpoint("10.244.0.114", 10000),
}
只需要將這部分改造一下。如果在k8s裏面,那就watch k8s的endpoint,動態獲取就行。如果是在k8s集羣之外,可以封裝一個web 容器,在頁面上管理後端endpoint也行。總之,後端服務的配置,完全由eds接管,不管ip:port怎 麼變化,只需要在eds服務中配置,就會推送至envoy,完成endpoint服務發現
envoy RDS
現在已經擁有了EDS服務,能夠動態獲取endpoint,但是http的路由配置依然是直接在配置文件裏面的
...
static_resources:
listeners:
- name: ingress_listener
address:
socket_address:
address: 0.0.0.0
port_value: 10000
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
http_protocol_options:
accept_http_10: true
common_http_protocol_options:
idle_timeout: 300s
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: app
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: backend_cluster
...
比如想要修改match: { prefix: "/" },envoy並不會感知,還是需要重啓。所以引入RDS服務,與EDS服務類似,自動發現HTTP路由配置
創建rds服務端
手搓一個簡單的rds_server
rds服務
該腳本啓動18001端口,接收gRPC請求,並且響應RDS,只要envoy來連接18001,就會下發http route到envoy
修改envoy配置
static_resources:
listeners:
- name: ingress_listener
address:
socket_address:
address: 0.0.0.0
port_value: 10000
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
http_protocol_options:
accept_http_10: true
codec_type: AUTO
rds:
route_config_name: local_route
config_source:
api_config_source:
api_type: GRPC
grpc_services:
- envoy_grpc:
cluster_name: rds_server
...
clusters:
...
- name: rds_server
connect_timeout: 1s
type: STATIC
http2_protocol_options: {}
load_assignment:
cluster_name: rds_server
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 10.22.12.178
port_value: 18001
驗證
配置完之後,首先啓動rds_server
▶ go run rds.go
2025/12/24 17:02:34 RDS server listening on :18001
修改envoy配置之後重啓,檢查rds_server的輸出:
▶ go run rds.go
2025/12/24 17:02:34 RDS server listening on :18001
2025/12/24 17:02:55 RDS stream connected
2025/12/24 17:02:55 >>> Sending RDS response version=1766566954686151045, nonce=1766566975846610006
2025/12/24 17:02:55 DiscoveryRequest resources=[local_route] version="1766561174225337826" nonce=""
2025/12/24 17:02:55 DiscoveryRequest resources=[local_route] version="1766566954686151045" nonce="1766566975846610006"
成功了,啓動的envoy之後,envoy與rds_server建立連接,並且rds_server推送相關配置給envoy,再訪問一下試試curl 10.22.12.178:30785/test
[2025-12-24T09:03:16.252Z] "GET /test HTTP/1.0" 200 40 1 bea0ccf1-0621-4be1-919f-3dbb24e93ff5 "curl/7.81.0" "-" 10.244.0.114:10000 backend_cluster -
[2025-12-24T09:03:16.916Z] "GET /test HTTP/1.0" 200 40 1 f22c01e4-8120-4cb1-837e-a6c0b27f7410 "curl/7.81.0" "-" 10.244.0.111:10000 backend_cluster -
RDS小結

演示中的腳本,是將配置寫死在代碼中的
Match: &routepb.RouteMatch{
PathSpecifier: &routepb.RouteMatch_Prefix{
Prefix: "/test",
},
},
只需要將這部分改造一下。如果在k8s裏面,那就watch k8s的ingress,動態獲取就行。如果是在k8s集羣之外,可以封裝一個web 容器,在頁面上管理後端http router也行
envoy ADS
目前我們完成了EDS、RDS,可以自動發現對應的endpoint、http router資源,但是他們都是gRPC協議,能不能整合在一起呢?並且xDS還有其他的資源,什麼CDS、LDS等等,每個種類都監聽一次接口,管理難度也太冗餘了。於是ADS就應運而生了,它是一個聚合發現服務,一個特殊的 gRPC 端點,將所有 xDS API 聚合在一起
創建ads服務端
ads服務
該腳本啓動18000端口,接收gRPC請求,並且響應聚合請求ADS,再根據不同的查詢類型(EDS、RDS等),響應不同的資源,並且下發到envoy
修改envoy的配置
這裏修改較為複雜,直接給出配置文件即可
node:
id: envoy-1
cluster: demo-proxy
dynamic_resources:
ads_config:
api_type: GRPC
grpc_services:
- envoy_grpc:
cluster_name: ads_server
static_resources:
listeners:
- name: ingress_listener
address:
socket_address:
address: 0.0.0.0
port_value: 10000
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
http_protocol_options:
accept_http_10: true
codec_type: AUTO
rds:
route_config_name: local_route
config_source:
ads: {}
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
access_log:
- name: envoy.access_loggers.stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
log_format:
text_format: "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %BYTES_SENT% %DURATION% %REQ(X-REQUEST-ID)% \"%REQ(USER-AGENT)%\" \"%REQ(X-FORWARDED-FOR)%\" %UPSTREAM_HOST% %UPSTREAM_CLUSTER% %RESPONSE_FLAGS%\n"
clusters:
- name: ads_server
connect_timeout: 1s
type: STATIC
http2_protocol_options: {}
load_assignment:
cluster_name: ads_server
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 10.22.12.178
port_value: 18000
- name: backend_cluster
type: EDS
connect_timeout: 0.25s
lb_policy: ROUND_ROBIN
eds_cluster_config:
eds_config:
ads: {}
驗證
首先啓動ADS服務,再修改envoy配置,最後重啓envoy服務。驗證部分同EDS、ADS,這裏就不贅述
ADS小結

至此,通過ADS聚合服務,可以接受不同類型的xDS請求,在文中我們實現了EDS與RDS,當然如果有需求,可以持續的把LDS、CDS等全部加上
小結
“修改配置之後如何自動生效”,本文通過這一切入點,詳細探討了envoy的另外一種服務發現策略xDS,並且手搓了諸如EDS、RDS等服務,成功響應了envoy的需求,完成了配置生效。並且最終使用ADS,將EDS與RDS聚合在一起,形成了一個統一且管理型強的服務入口
後記
有位老哥説了,這不就是istio嘛?沒錯,istio的數據面就是使用envoy
所謂服務治理,也是從解決最基本的問題而誕生的,本系列從“記錄後端真實pod ip”為切入口,通過常見的場景需求,不斷的解決需求,發現問題,解決問題,最終將這些功能全部聚合一起,就是服務治理的基本框架
而問題的提出、解決問題的過程以及需求的滿足,不光是服務治理,也是所有軟件誕生的基本思想
聯繫我
- 聯繫我,做深入的交流

至此,本文結束
在下才疏學淺,有撒湯漏水的,請各位不吝賜教...