Envoy 前端代理(Front Proxy)实战:基于 Docker Compose 的边缘反向代理与负载均衡指南
2026/9/24 21:45:51 网站建设 项目流程
  • 教程
  • 云原生
  • 容器编排

【免费下载链接】kubernetes-handbook

Kubernetes 架构与生态:从云原生到 AI 原生基础设施的构建指南

项目地址:https://gitcode.com/gh_mirrors/ku/kubernetes-handbook
点击查看免费下载

导读

本文以 Kubernetes Handbook 仓库中 usecases/envoy-front-proxy.md 为核心,完整讲解如何使用 Envoy 作为前端(边缘)反向代理:通过 Docker 容器与 docker-compose 在单机环境编排front-envoyservice1service2三个服务,从底层理解 Envoy 的路由、负载均衡与 admin 管理端点。读完本文你将掌握 Envoy 的 YAML 静态配置(listener / cluster / admin)、进程外(out-of-process)与无侵入式架构原理,并为后续将 Envoy 作为 Istio Service Mesh 数据平面(data plane)打下扎实基础。

Envoy 与前端代理的定位

Envoy 是 Lyft 开源、使用 C++ 编写的 L7 代理和通信总线,是 CNCF 旗下的毕业项目,也是 Istio 服务网格默认的数据平面。其关键特性包括:进程外架构(不侵入应用进程)、L3/L4 与 HTTP L7 filter 架构、HTTP/2 支持、L7 路由、动态配置(xDS)、最佳可观测性、front/edge proxy 支持、高级负载均衡、健康检查与服务发现等。

从 usecases/envoy.md 可知,Envoy 本身无法构成完整的 Service Mesh,但可以作为 service mesh 中应用间流量的代理,负责数据层。而"前端代理"正是 Envoy 支持的一种部署角色:Edge envoy,即流量进出 mesh 时的入口代理,相当于 Kubernetes 中的 Ingress。与之相对的是随每个服务实例一起运行的Service envoy(在 Kubernetes 中作为 Sidecar 与应用容器共存于同一 Pod),详见 usecases/envoy-terminology.md。

本文的示例正对应"边缘反向代理"这一角色:Envoy 类似于 Nginx,但与之不同的是,它还可以作为进程伴随每个服务运行在同一个容器/Pod 中(Sidecar 模式),这也是它无侵入、进程外架构的体现。

快速开始:克隆 Envoy 源码

Envoy 中的所有规则配置与 Kubernetes 一样,都是通过 YAML 文件完成的。在继续之前,先克隆 Envoy 的 GitHub 仓库:

git clone https://github.com/envoyproxy/envoy.git

Envoy 官方提供了多个可直接使用docker-compose运行的打包用例(sandbox),代码位于 Envoy 仓库的examples目录下:

  • Front Proxy(前端代理)
  • Zipkin Tracing
  • Jaeger Tracing
  • gRPC Bridge

本文的核心示例即取自其中的Front proxy用例(envoy/examples/front-proxy)。

Front Proxy 示例的整体架构

本示例的部署结构如下图所示,此时 Envoy 作为反向代理运行在 mesh 边缘,承担边缘网关的角色。

从图中可以看到三组角色的分工:

  • front-envoy:边缘(前端)Envoy,监听 80 端口接收外部流量,根据 URL 前缀将请求反向代理到后端的 service1 / service2,同时暴露 8001 端口提供 admin 管理接口;
  • service1 / service2:两个后端业务服务,每个服务都与一个 service-envoy 共同运行(示例中通过SERVICE_NAME环境变量区分实例编号),对外只暴露 80 端口;
  • envoymesh 网络:三个容器共享的自定义 docker 网络,front-envoy通过 DNS 名称(service1service2)发现后端。

这与 usecases/envoy-terminology.md 中描述的 mesh 概念一致:一组互相协调以提供一致网络拓扑的主机,其中 edge envoy 负责流量进出,service envoy 与应用进程无感知地共存。

编写 docker-compose.yml 编排文件

在此示例中一共有 3 个服务,首先为其创建容器编排的docker-compose.yml文件:

version: '2' services: front-envoy: build: context: . dockerfile: Dockerfile-frontenvoy volumes: - ./front-envoy.yaml:/etc/front-envoy.yaml networks: - envoymesh expose: - "80" - "8001" ports: - "8000:80" - "8001:8001" service1: build: context: . dockerfile: Dockerfile-service volumes: - ./service-envoy.yaml:/etc/service-envoy.yaml networks: envoymesh: aliases: - service1 environment: - SERVICE_NAME=1 expose: - "80" service2: build: context: . dockerfile: Dockerfile-service volumes: - ./service-envoy.yaml:/etc/service-envoy.yaml networks: envoymesh: aliases: - service2 environment: - SERVICE_NAME=2 expose: - "80" networks: envoymesh: {}

该编排文件的关键设计点:

  • 网络别名(aliases)service1service2在网络envoymesh中注册了 DNS 别名,这使得front-envoy的 cluster 配置可以直接用主机名service1service2寻址后端;
  • 端口映射front-envoy将容器内 80 端口映射到宿主机的8000端口(对外流量入口),将 8001 端口直接透出(admin 管理接口);两个后端服务仅通过expose声明端口,不映射到宿主机,只能在envoymesh网络内部被访问;
  • 配置挂载./front-envoy.yaml挂载到容器内/etc/front-envoy.yaml./service-envoy.yaml挂载到/etc/service-envoy.yaml,实现配置与镜像分离。

使用docker-compose up --build启动后,三个服务都会处于frontproxy_envoymesh这个网络中(网络名前缀为项目目录名),从而保证相互可达。

front-envoy 镜像与启动方式

front-envoy使用Dockerfile-frontenvoy文件构建镜像,内容如下:

FROM envoyproxy/envoy:latest RUN apt-get update && apt-get -q install -y \ curl CMD /usr/local/bin/envoy -c /etc/front-envoy.yaml --service-cluster front-proxy

该 Dockerfile 有两个值得注意的地方:

  • 基础镜像为官方envoyproxy/envoy:latest,并额外安装了curl,方便在容器内做连通性验证;
  • 启动命令中-c /etc/front-envoy.yaml指定静态配置文件(由宿主机./front-envoy.yaml挂载进来),--service-cluster front-proxy设置 Envoy 实例所属的服务集群名,该名称会出现在统计信息中,便于多实例场景下区分。

front-envoy.yaml 静态配置详解

/etc/front-envoy.yaml是本次示例的核心配置文件,完整内容如下:

static_resources: listeners: - address: socket_address: address: 0.0.0.0 port_value: 80 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: - "*" routes: - match: prefix: "/service/1" route: cluster: service1 - match: prefix: "/service/2" route: cluster: service2 http_filters: - name: envoy.router config: {} clusters: - name: service1 connect_timeout: 0.25s type: strict_dns lb_policy: round_robin http2_protocol_options: {} hosts: - socket_address: address: service1 port_value: 80 - name: service2 connect_timeout: 0.25s type: strict_dns lb_policy: round_robin http2_protocol_options: {} hosts: - socket_address: address: service2 port_value: 80 admin: access_log_path: "/dev/null" address: socket_address: address: 0.0.0.0 port_value: 8001

配置整体包含三大顶级配置项:

  • static_resources:静态资源定义,包含 listener(监听器)与 cluster(集群)两部分;
  • clusters:envoymesh 中的服务注册信息(此处为静态注册,也可通过 SDS/xDS 动态发现);
  • admin:管理接口,监听 8001 端口,可通过/stats获取当前 Envoy 的统计信息,通过/server_info获取版本信息。

Listener:HTTP 连接管理器

listeners定义 Envoy 监听的网络位置与流量处理链。示例中监听0.0.0.0:80,通过filter_chains挂载一个envoy.http_connection_manager(HTTP 连接管理器)过滤器,其中:

  • codec_type: auto:自动协商 HTTP/1.1 与 HTTP/2 编解码;
  • stat_prefix: ingress_http:统计信息前缀,用于区分不同 listener 的度量;
  • route_config.virtual_hosts:虚拟主机配置,domains: ["*"]匹配所有域名,routes内通过prefix(URL 路径前缀)与cluster(目标集群)建立映射:/service/1service1/service/2service2
  • http_filters中最后挂载envoy.router过滤器,负责真正的路由转发动作。

结合 usecases/envoy-terminology.md 中的术语说明,virtual_hosts必须包含name(服务名称)、domains(DNS 域名,必须能跟 virtual host 的 URL 匹配)、routes(路由列表);每个路由可包含prefix(URL 路径前缀)、cluster(处理请求的 envoy cluster)、timeout_ms(超时时间)。这里的内联路由配置即为静态 RDS,若采用动态配置则可由 Route Discovery Service(RDS)下发。

Cluster:服务发现与负载均衡

clusters定义了一组逻辑上相似的上游主机。示例中service1service2两个 cluster 的关键参数:

  • name:cluster 名称,即服务名称,与路由中引用的 cluster 一一对应;
  • connect_timeout: 0.25s:与上游建立连接的超时时间;
  • type: strict_dns:服务发现类型,Envoy 持续监听 DNS,每个匹配的 A 记录都认定为有效主机(DNS 解析出的每个 IP 都会加入 cluster);
  • lb_policy: round_robin:负载均衡策略,轮询访问各上游主机;
  • http2_protocol_options: {}:启用 HTTP/2 上游协议支持(Envoy 对上游默认优先协商 HTTP/2);
  • hosts:上游主机地址列表,此处通过 socket_address 指定 DNS 名称service1:80service2:80

关于type(服务发现方式),usecases/envoy-terminology.md 汇总了四种取值:

  • static:静态配置,监听 cluster 中列出的所有主机;
  • strict_dns:Envoy 持续监听 DNS,每个匹配的 A 记录都认定为有效;
  • logical_dns:Envoy 使用 DNS 增加主机,但即使 DNS 不再返回该主机也不会删除这些主机信息;
  • sds:Service Discovery Service,Envoy 访问外部的 REST 接口获取 cluster 成员信息(即 usecases/envoy-mesh-in-kubernetes-tutorial.md 中讨论的 SDS 方案,用于发现服务的所有 endpoint 而非仅 ClusterIP)。

Admin:管理接口

admin块配置管理服务监听地址为0.0.0.0:8001access_log_path设为/dev/null关闭访问日志。启动后访问http://localhost:8001即可看到管理端点列表(详见下文"admin 端点"一节)。

启动并验证环境

envoy/examples/front-proxy目录下执行:

$ pwd envoy/examples/front-proxy $ docker-compose up --build -d $ docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------------------------------- example_service1_1 /bin/sh -c /usr/local/bin/ ... Up 80/tcp example_service2_1 /bin/sh -c /usr/local/bin/ ... Up 80/tcp example_front-envoy_1 /bin/sh -c /usr/local/bin/ ... Up 0.0.0.0:8000->80/tcp, 0.0.0.0:8001->8001/tcp

三个容器全部启动成功:两个后端服务仅监听 80 端口,front-envoy将宿主机的8000映射到容器 80(流量入口)、8001映射到容器 8001(admin 接口)。

路由验证

访问 service1(http://localhost:8000/service/1):

$ curl -v localhost:8000/service/1 * Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 8000 (#0) > GET /service/1 HTTP/1.1 > Host: localhost:8000 > User-Agent: curl/7.54.0 > Accept: */* > < HTTP/1.1 200 OK < content-type: text/html; charset=utf-8 < content-length: 89 < server: envoy < date: Fri, 20 Apr 2018 08:26:33 GMT < x-envoy-upstream-service-time: 14 < Hello from behind Envoy (service 1)! hostname: a3e4185a9a49 resolvedhostname: 172.18.0.4 * Connection #0 to host localhost left intact

访问 service2(http://localhost:8000/service/2)时返回:

* Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 8000 (#0) > GET /service/2 HTTP/1.1 > Host: localhost:8000 > User-Agent: curl/7.54.0 > Accept: */* > < HTTP/1.1 200 OK < content-type: text/html; charset=utf-8 < content-length: 89 < server: envoy < date: Fri, 20 Apr 2018 08:27:27 GMT < x-envoy-upstream-service-time: 10 < Hello from behind Envoy (service 2)! hostname: f6650e1911a0 resolvedhostname: 172.18.0.3 * Connection #0 to host localhost left intact

响应特征印证了 Envoy 的路由与代理行为:

  • 响应头中server: envoy表明流量确实经过 Envoy 转发;
  • x-envoy-upstream-service-time头记录了上游服务的处理耗时(单位毫秒),这是 Envoy 可观测性的一部分;
  • 返回体中的hostnameresolvedhostname是后端示例应用打印的容器 ID 与解析到的 IP,两者不同(一个指向 service1,一个指向 service2),说明请求被正确路由到了对应的后端服务。

负载均衡验证

通过docker-compose scale将 service1 扩容到 3 个实例(注意:新版 docker-compose 中 scale 命令已废弃,推荐使用up --scale参数):

$ docker-compose scale service1=3 WARNING: The scale command is deprecated. Use the up command with the --scale flag instead. Starting frontproxy_service1_1 ... done Creating frontproxy_service1_2 ... done Creating frontproxy_service1_3 ... done $ docker-compose ps Name Command State Ports --------------------------------------------------------------------------------------------------------------------------- frontproxy_front-envoy_1 /usr/bin/dumb-init -- /bin ... Up 10000/tcp, 0.0.0.0:8000->80/tcp, 0.0.0.0:8001->8001/tcp frontproxy_service1_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 80/tcp frontproxy_service1_2 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 80/tcp frontproxy_service1_3 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 80/tcp frontproxy_service2_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 80/tcp

此时 service1 已有 3 个实例。循环访问 service1 观察负载均衡效果:

$ while true;do curl localhost:8000/service/1;sleep 1;done Hello from behind Envoy (service 1)! hostname: a3e4185a9a49 resolvedhostname: 172.18.0.4 Hello from behind Envoy (service 1)! hostname: fe44dba64122 resolvedhostname: 172.18.0.5 Hello from behind Envoy (service 1)! hostname: c5b9f1289e0f resolvedhostname: 172.18.0.6 Hello from behind Envoy (service 1)! hostname: a3e4185a9a49 resolvedhostname: 172.18.0.4 Hello from behind Envoy (service 1)! hostname: fe44dba64122 resolvedhostname: 172.18.0.5 Hello from behind Envoy (service 1)! hostname: c5b9f1289e0f resolvedhostname: 172.18.0.6

三个不同 hostname(对应三个容器实例)循环出现,说明round_robin轮询负载均衡已生效——这一策略正是在front-envoy.yamlcluster配置项中通过lb_policy: round_robin声明的。值得注意的是,这里的负载均衡发生在 Envoy 层:由于strict_dns会持续解析service1的 DNS 记录,Envoy 动态感知到了扩容后新增的容器地址并纳入轮询池。

admin 端点与运维能力

访问http://localhost:8001可以看到 Envoy admin 提供的管理 API 端点:

命令描述
/Admin 主页
/certs打印机器上的 certs
/clustersupstream cluster 状态
/config_dump输出当前的 Envoy 配置
/cpuprofiler开启/关闭 CPU profiler
/healthcheck/fail导致服务失败健康检查
/healthcheck/ok导致服务通过健康检查
/help打印管理命令的帮助信息
/hot_restart_version打印热重启兼容版本
/listeners打印 listener 地址
/logging查询/更改日志级别
/quitquitquit退出服务
/reset_counters将计数器重置为 1
/runtime打印运行时值
/runtime_modify修改运行时值
/server_info打印服务器版本/状态信息
/stats打印服务器状态统计信息
/stats/prometheus打印 prometheus 格式的服务器状态统计信息

这些端点覆盖了日常运维的主要场景:/stats/stats/prometheus提供监控数据(后者可直接被 Prometheus 抓取);/config_dump可用于核对线上实际生效的配置;/clusters查看上游集群健康与成员状态;/logging动态调整日志级别;/healthcheck/fail/healthcheck/ok可人为触发健康检查失败/通过以测试故障转移逻辑。Enovy 通过这些管理 API 端点提供了运行时动态配置与观测能力。

从前端代理到数据平面:与 Istio 的衔接

本示例的意义不止于单机实验。把 Envoy 部署在应用进程之外、与应用容器同 Pod(Sidecar)正是 Istio 数据平面的基本形态:

  • 在 usecases/istio.md 的架构描述中,数据平面由一组智能代理(Envoy)以 sidecar 模式部署,协调和控制所有服务之间的网络通信;控制平面负责管理和配置代理路由流量、执行策略;
  • 仓库中的 manifests/istio/istio.yaml 展示了 Istio 的部署形态:istio-ingress(对应本示例中 front-envoy 的边缘入口角色)、istio-manager(负责 discovery,即控制平面的配置下发)、istio-mixer(策略与遥测);
  • manifests/sofa-mesh/sofa-mesh-demo.yaml 中也可以看到istio-proxy(envoy)容器的存在,以及envoyfilters这类用于定制 Envoy 行为的 CRD 定义。

在本示例中,Envoy 的路由与 cluster 全部来自静态 YAML;而在 Istio 中,控制平面通过 xDS(CDS/EDS/RDS/LDS 等发现服务)将配置动态下发给 Envoy,实现无重启的流量管理。理解了本示例中 listener 与 cluster 的静态配置逻辑,再理解 Istio 的动态配置注入就水到渠成。

小结

通过 docker-compose 在单机运行 Envoy Front Proxy 示例,我们可以得出以下与生产实践直接相关的结论:

  1. 进程外、无侵入:Envoy 以独立进程运行在应用之外(同一容器或同一 Pod),应用代码无需任何改动即可获得代理、路由、负载均衡与可观测性能力;
  2. YAML 驱动的声明式配置:listener(含 HTTP connection manager 与路由表)、cluster(服务发现 + 负载均衡策略)、admin 三大配置块覆盖了边缘代理的核心能力;
  3. 边缘入口角色:front-envoy 充当流量进出 mesh 的网关(类似 Kubernetes Ingress),支持基于 URL 前缀的路由与基于strict_dns+round_robin的动态负载均衡;
  4. admin 端点提供运行时运维能力:统计、配置导出、日志级别调整、健康检查开关等均可通过 8001 端口的 HTTP 端点完成;
  5. 为 Service Mesh 打基础:本示例的静态配置模式正是 Istio 数据平面 Envoy 代理的雏形,理解了它便能更快掌握 xDS 动态配置与 Sidecar 注入机制。

如需继续深入,建议阅读仓库中 usecases/envoy-terminology.md(Envoy 架构与基本术语、xDS 概念)、usecases/envoy-mesh-in-kubernetes-tutorial.md(Envoy 在 Kubernetes 中做 mesh 的完整实战,包括 edge envoy 与 SDS 服务发现),以及 usecases/istio.md(Istio 数据平面与控制平面架构)。

  • 教程
  • 云原生
  • 容器编排

【免费下载链接】kubernetes-handbook

Kubernetes 架构与生态:从云原生到 AI 原生基础设施的构建指南

项目地址:https://gitcode.com/gh_mirrors/ku/kubernetes-handbook
点击查看免费下载
上一篇:揭秘gh_mirrors/box/boxes核心功能:命令行参数与设计模板全解析
下一篇:图层导出效率提升指南:Photoshop自动化工具的工作流优化方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询