在这里,我们将给大家分享关于eShopOnContainers知多少[12]:Envoygateways的知识,让您更了解eshoponcontainer讲解的本质,同时也会涉及到如何更有效地.NET
在这里,我们将给大家分享关于eShopOnContainers 知多少 [12]:Envoy gateways的知识,让您更了解eshoponcontainer讲解的本质,同时也会涉及到如何更有效地.NET微服务最佳实践eShopOnContainers、ASP.NET Core基于微软微服务eShopOnContainer事件总线EventBus的实现、Catalog Service - 解析微软微服务架构 eShopOnContainers(三)、Docker在eShopOnContainer项目中的使用方法的内容。
本文目录一览:- eShopOnContainers 知多少 [12]:Envoy gateways(eshoponcontainer讲解)
- .NET微服务最佳实践eShopOnContainers
- ASP.NET Core基于微软微服务eShopOnContainer事件总线EventBus的实现
- Catalog Service - 解析微软微服务架构 eShopOnContainers(三)
- Docker在eShopOnContainer项目中的使用方法
eShopOnContainers 知多少 [12]:Envoy gateways(eshoponcontainer讲解)

1. 引言
在最新的 eShopOnContainers 3.0 中 Ocelot 网关被 Envoy Proxy 替换。下面就来简要带大家了解下 Envoy,并尝试梳理下为什么要使用 Envoy 替代 Ocelot。
2. Hello Envoy
ENVOY IS AN OPEN SOURCE EDGE AND SERVICE PROXY, DESIGNED FOR CLOUD-NATIVE APPLICATIONS.Enovy (信使) 是一款开源的专为云原生应用设计的服务代理。
2.1. 快速体验
首先基于本地 Dockers 快速体验一下,先启动本地 Docker-Desktop,拉取 Envoy 镜像:
> docker search envoy-dev
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
envoyproxy/envoy Images for tagged releases. Use envoy-dev fo… 96
> docker image pull envoyproxy:envoy-dev
latest: Pulling from envoyproxy/envoy-dev
171857c49d0f: Pull complete
419640447d26: Pull complete
61e52f862619: Pull complete
3f2a8c910457: Pull complete
b2ce823b3fd3: Pull complete
ec09faba9bc7: Pull complete
b0b9168845d0: Pull complete
39a220277151: Pull complete
9081a11f5983: Pull complete
1880b475bc3a: Pull complete
Digest: sha256:cd8dbbbd8ce4c8c6eb52e4f8eebf55f29d1e597ca8311fecf9eda08b8cca813a
Status: Downloaded newer image for envoyproxy/envoy-dev:latest
docker.io/envoyproxy/envoy-dev:latest
该 Docker 镜像将包含最新版本的 Envoy 和一个基本的 Envoy 配置,可以将 10000 端口的入站请求路由到 www.google.com
。下面启动容器测试:
> docker run -d --name envoy -p 10000:10000 envoyproxy/envoy-dev:latest
27e422f34b389d99e9180e47d8109a19975ccd139f42ac2f4fa9f724906b72f6
> docker ps | findstr ''envoy''
27e422f34b38 envoyproxy/envoy-dev:latest "/docker-entrypoint.?? 2 minutes ago Up 2 minutes 0.0.0.0:10000->10000/tcp envoy
> curl -I http://localhost:10000
HTTP/1.1 200 OK
content-type: text/html; charset=ISO-8859-1
p3p: CP="This is not a P3P policy! See g.co/p3phelp for more info."
date: Sat, 17 Oct 2020 04:38:38 GMT
server: envoy
x-xss-protection: 0
x-frame-options: SAMEORIGIN
expires: Sat, 17 Oct 2020 04:38:38 GMT
cache-control: private
set-cookie: 1P_JAR=2020-10-17-04; expires=Mon, 16-Nov-2020 04:38:38 GMT; path=/; domain=.google.com; Secure
set-cookie: NID=204=h0EoJXNOTbQA11L-tVowqcwloS0-BCTR71IeN4irsmpubdPIIS4sU8Gco79pt1NhONAxxFdUJ46SKvbX4Ni-jKMWbSW0k_kn3fFkVrfLm7OOBbAtUWtxGGOCRJGbSNIRyOPfDB7_wMngEWW3yoFEs9diSCtZK9DWFZdtJJZtWuI; expires=Sun, 18-Apr-2021 04:38:38 GMT; path=/; domain=.google.com; HttpOnly
alt-svc: h3-Q050=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-T050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
x-envoy-upstream-service-time: 37
transfer-encoding: chunked
PS: 请确保本地机器能访问 Google,否则 curl -I http://localhost:10000
会出错。
接下来我们进入容器内部,查看下配置文件,默认路径为 /etc/envoy/envoy.yaml
:
docker exec -it envoy /bin/bash
root@27e422f34b38:/# cat /etc/envoy/envoy.yaml
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address:
protocol: TCP
address: 127.0.0.1
port_value: 9901
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
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
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
host_rewrite_literal: www.google.com
cluster: service_google
http_filters:
- name: envoy.filters.http.router
clusters:
- name: service_google
connect_timeout: 30s
type: LOGICAL_DNS
# Comment out the following line to test on v6 networks
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service_google
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: www.google.com
port_value: 443
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
sni: www.google.com
我们把上面的配置文件拷贝到本地,将上面的 www.google.com
改为 www.baidu.com
,将 admin.address.socket_address.address: 127.0.0.1
改
为 0.0.0.0
,然后把配置文件命名为 envoy-baidu.yaml
,然后挂载到容器的 /etc/envoy/envoy.yaml
。
> docker run --rm -d --name envoy-baidu-v $Home/k8s/envoy-baidu.yaml:/etc/envoy/envoy.yaml -p 9901:9901 -p 15001:15001 envoyproxy/envoy-dev:latest
> docker ps | findstr ''envoy''
f07f6a1e9305 envoyproxy/envoy-dev:latest "/docker-entrypoint.?? 2 minutes ago Up 2 minutes 10000/tcp, 0.0.0.0:9901->9901/tcp, 0.0.0.0:15001->15001/tcp envoy-baidu
3cd12b5f6ddd envoyproxy/envoy-dev:latest "/docker-entrypoint.?? About an hour ago Up About an hour 0.0.0.0:10000->10000/tcp envoy
> curl -I http://localhost:15001
HTTP/1.1 200 OK
accept-ranges: bytes
cache-control: private, no-cache, no-store, proxy-revalidate, no-transform
content-length: 277
content-type: text/html
date: Sat, 17 Oct 2020 05:41:01 GMT
etag: "575e1f65-115"
last-modified: Mon, 13 Jun 2016 02:50:13 GMT
pragma: no-cache
server: envoy
x-envoy-upstream-service-time: 24
使用浏览器访问 http://localhost:9901 即可访问 envoy 管理页面,如下图所示:
2.2. 配置简介
第一次看 Envoy 的配置文件,和第一次接触 Nginx 的配置文件一样,绝对一脸懵逼。没关系,咱们来理一理。
作为一个代理,不管是 Nginx、HAProxy,还是 Envoy,其处理流程都是一样的。其首先都是要监听指定端口获取请求流量,然后分析请求数据,进行请求转发。脑补完大致流程后,再来看 Envoy 是如何组织配置信息的。先来了几个核心配置:
-
listener : Envoy 的监听地址,用来接收请求,处理入站请求。Envoy 会暴露一个或多个 Listener 来监听客户端的请求。 -
filter : 过滤器是处理入站和出站流量的链式结构的一部分。在过滤器链上可以集成很多特定功能的过滤器,例如,通过集成 GZip 过滤器可以在数据发送到客户端之前压缩数据。 -
route_config : 路由规则配置。即将请求路由到后端的哪个集群。 -
cluster : 集群定义了流量的目标端点,同时还包括一些其他可选配置,如负载均衡策略等。
整体流程如下图所示:

2.3. 代理 ASP.NET Core WebApi
有了上面的基础,下面尝试使用 Envoy 代理 ASP.NET Core WebApi。首先创建两个简单 API,然后创建一个 Envoy 配置文件,最后通过 docker compose 启动三个容器进行测试。由于项目文件结构简单,这里不再过多阐述,主要包含四个部分:
-
City Api -
Weather Api -
Envoy 代理配置 -
docker compose 配置
整体解决方案如下图所示。源码路径:K8S.NET.Envoy。

Envoy 代理配置基于第一节的基础上进行修改,如下所示:
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 9903
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 10003
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/c"
route:
prefix_rewrite: "/city"
cluster: city_service
- match:
prefix: "/w"
route:
prefix_rewrite: "/weather"
cluster: weather_service
http_filters:
- name: envoy.filters.http.router
clusters:
- name: city_service
connect_timeout: 0.25s
type: LOGICAL_DNS
# Comment out the following line to test on v6 networks
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: city_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: cityapi
port_value: 80
- name: weather_service
connect_timeout: 0.25s
type: LOGICAL_DNS
# Comment out the following line to test on v6 networks
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: weather_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: weatherapi
port_value: 80
以上配置 Envoy 监听 10003
端口,通过指定 prefix_rewrite
重写前缀,将 /c
路由至 cityapi
的 /city
路径,将 /w
路由至 weatherapi
的 /weather
路径。
docker-compose 配置如下:
version: ''3''
services:
envoygateway:
build: Envoy/
ports:
- "9903:9903"
- "10003:10003"
volumes:
- ./Envoy/envoy.yaml:/etc/envoy/envoy.yaml
cityapi:
build: K8S.NET.CityApi/
ports:
- "8080:80"
environment:
ASPNETCORE_URLS: "http://+"
ASPNETCORE_ENVIRONMENT: "Development"
weatherapi:
build: K8S.NET.WeatherApi/
ports:
- "8082:80"
environment:
ASPNETCORE_URLS: "http://+"
ASPNETCORE_ENVIRONMENT: "Development"
从上可以看到,主要用来启动三个服务:
-
envoy gateway:其中将项目路径下 /Envoy/envoy.yaml
挂载到容器目录/etc/envoy/envoy.yaml
。同时暴露 2 个端口,9903,10003。 -
city api -
weather api
因此最终可以通过以下路径进行访问:
-
http://localhost:10003/c 访问 city api。 -
http://localhost:10003/w 访问 weather api。
执行以下命令,启动应用和代理,并测试:
> docker-compose up -d
Starting k8snetenvoy_envoygateway_1 ... done
Starting k8snetenvoy_cityapi_1 ... done
Starting k8snetenvoy_weatherapi_1 ... done
> docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------------------------------------
k8snetenvoy_cityapi_1 dotnet K8S.NET.CityApi.dll Up 443/tcp, 0.0.0.0:8080->80/tcp
k8snetenvoy_envoygateway_1 /docker-entrypoint.sh envo ... Up 10000/tcp, 0.0.0.0:10003->10003/tcp,
0.0.0.0:9903->9903/tcp
k8snetenvoy_weatherapi_1 dotnet K8S.NET.WeatherApi.dll Up 443/tcp, 0.0.0.0:8082->80/tcp
> curl http://localhost:10003/c
Shanghai
> curl http://localhost:10003/w
Cool
3. eShopOnContainers 中的应用
eShopOnContainer 中主要定义了四个 API 网关(BFF 模式),服务间通信方式主要有两种,一种是 HTTP,一种是 gRPC。如果启用 Service Mesh 并且部署至 K8S,服务整体通信架构如下图所示:

有两点需要补充说明:
-
Linkerd 是一种 Service Mesh,其核心思想是借助 Sidecar 模式无侵入式对应用进行服务治理,包括服务发现、流量管理、负载均衡、路由等。 -
了解过 Istio(目前比较流行的 Service Mesh)应该知道,Envoy 在 Istio 中作为 Sidecar 而存在,而在 eShopOnContainers 中 Envoy 被充当 API Gateways。
基于上面的基础,再来看 eShopOnContainers 中的配置,其实就很明白了,主要是配置文件从 Ocelot 转变到 envoy.yaml,配置如下图所示。
路由配置如下:
-
/m/ 、/marketing-api/ 路由至:marketing api -
/c/、/catalog-api/ 路由至:catalog api -
/o/、/ordering-api/ 路由至:ordering api -
/b/、/basket-api/ 路由至:basket api -
/ 路由至:web bff aggregator api
部署时,基于 helm 将 envoy.yaml
保存至 ConfigMap
,在基于 envoyproxy/enovy
镜像构建容器,将配置从 ConfigMap
挂载到容器中,容器内部即可基于配置启动 Envoy 网关了。
4. Why Envoy
经过上面的了解发现,Envoy 还是充当的网关角色,那为什么要替换呢?先来了解下 Envoy 的优势:
-
非侵入式架构 :
Envoy
基于Sidecar
模式,是一个独立进程,对应用透明。(在 eShopOnContainer 中还是独立的网关项目,并非以Sidecar
模式注入到服务中。) -
基于 C++ 开发实现:拥有强大的定制化能力和优异的性能。
-
L3/L4/L7 架构 : 传统的网络代理,要么在
HTTP
层工作,要么在TCP
层工作。而Envoy
同时支持 3/4 层和 7 层代理。 -
顶级 HTTP/2 支持 : 它将
HTTP/2
视为一等公民,并且可以在HTTP/2
和HTTP/1.1
之间相互转换(双向),建议使用HTTP/2
。 -
gRPC 支持 : Envoy 完美支持 HTTP/2,也可以很方便地支持
gRPC
(gRPC 使用HTTP/2
作为底层多路复用传输协议)。 -
服务发现和动态配置 : 与
Nginx
等代理的热加载不同,Envoy
可以通过API
接口动态更新配置,无需重启代理。 -
特殊协议支持 : Envoy 支持对特殊协议在 L7 进行嗅探和统计,包括:MongoDB、DynamoDB 等。
-
可观测性 :
Envoy
内置stats
模块,可以集成诸如prometheus/statsd
等监控方案。还可以集成分布式追踪系统,对请求进行追踪。
再来看下 Ocelot:其本质还是 ASP.NET Core 中的一个请求中间件。只能进行 7 层代理,不支持 gRPC,不支持监控。因此总体而言,Envoy 更契合云原生对网络代理的诉求。
5. 总结
本文简要梳理了 Envoy 的基本用法,以及其在 eShopOnContainers 中的运用。Envoy 作为一个比肩 Nginx 的服务代理,其特性在 Service Mesh 中有着灵活的运用。本文就讲到这里了,下次有机会在和大家分享下 Envoy 在 Service Mesh 中的应用。
参考资料:
Envoy 介绍 - Envoy 中文指南 Build an API Gateway with Envoy and use with .NET Core APIs
本文分享自微信公众号 - dotNET 跨平台(opendotnet)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与 “OSC 源创计划”,欢迎正在阅读的你也加入,一起分享。
.NET微服务最佳实践eShopOnContainers
本文翻译自微软Docs, 内嵌译者多年使用的参悟,如理解有误,请不吝赐教。
微软与社区专家合作,开发了功能齐全的云原生微服务示例应用eShopOnContainers。
该应用旨在展示使用.NET、Docker以及可选的Azure,Kubernetes技术来构建电商平台。

功能 & 要求
简要回顾eShopOnContainers应用的业务功能和技术目标,示例应用代表一个出售各种实体产品的(例如T恤和咖啡杯)电商平台。
电商平台要实现的一些基本功能:
•列出商品目录•按类型过滤商品•按品牌过滤商品•将商品添加到购物车•编辑或删除购物车中的物品•支付•注册帐号•登录•登出•订单审核
示例应用还具有以下非功能性要求:
•必须具有高可用性,并且必须自动扩展以满足不断增长的流量(并在流量减少后再缩减)。•提供易于使用的运行状态监视和诊断日志,以帮助解决遇到的问题。•它应该支持敏捷开发,包括对持续集成和部署(CI/CD)的支持。•除了支持传统的Web前端和SPA Web前端,该应用程序还必须支持不同系统的移动客户端应用程序。•支持跨平台托管和跨平台开发。

Web或移动客户端通过HTTPS访问ASP.NET Core MVC服务器程序或API网关程序
。
API网关具有多种优势,例如将后端服务与各个前端客户端解耦,并提供更好的安全性。
该应用程序还利用了BFF模式(服务于前端的后端)
,该模式建议为每个前端客户端创建单独的API网关。
上面的体系图演示了基于请求是来自Web客户端还是来自移动客户端的API网关
。
示例应用的功能被分解为许多不同的微服务:
•负责身份验证和身份•列出产品目录中的商品•购物车管理以及订单管理。这些独立的服务都有其自己的持久化存储,没有可以与所有服务交互的单个主数据存储,
服务之间的协调和通信是通过消息总线
来完成的。
每个微服务根据其各自的需求独立设计。因此它们的技术堆栈是可以不同的(目前服务均是.NET构建并为云设计)。
简单的服务提供了基本的创建、读取、更新、删除访问(CRUD),而更高级的服务则使用领域驱动设计方法
和模式来管理业务复杂性。

代码结构
因为eShopOnContainers示例程序使用微服务,其GitHub存储库中包含许多独立的项目文件。
除了独立的项目方案和可执行文件之外,各种服务还被设计为在独立的容器中运行。
下图显示了完整的Visual Studio解决方案,管理组织了各种不同的项目。

该代码被组织为支持不同的微服务,并且在每个微服务中,代码分为领域逻辑、基础设施以及用户界面/服务端点。
Ref
• https://docs.microsoft.com/en-us/dotnet/architecture/cloud-native/introduce-eshoponcontainers-reference-app• https://github.com/dotnet-architecture/eShopOnContainers


更多干货及最佳实践分享
关注并星标我们