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镜像:

  1. > docker search envoy-dev
  2. NAME DESCRIPTION STARS OFFICIAL AUTOMATED
  3. envoyproxy/envoy Images for tagged releases. Use envoy-dev fo 96
  4. > docker image pull envoyproxy:envoy-dev
  5. latest: Pulling from envoyproxy/envoy-dev
  6. 171857c49d0f: Pull complete
  7. 419640447d26: Pull complete
  8. 61e52f862619: Pull complete
  9. 3f2a8c910457: Pull complete
  10. b2ce823b3fd3: Pull complete
  11. ec09faba9bc7: Pull complete
  12. b0b9168845d0: Pull complete
  13. 39a220277151: Pull complete
  14. 9081a11f5983: Pull complete
  15. 1880b475bc3a: Pull complete
  16. Digest: sha256:cd8dbbbd8ce4c8c6eb52e4f8eebf55f29d1e597ca8311fecf9eda08b8cca813a
  17. Status: Downloaded newer image for envoyproxy/envoy-dev:latest
  18. docker.io/envoyproxy/envoy-dev:latest

该Docker 镜像将包含最新版本的 Envoy 和一个基本的 Envoy 配置,可以将10000端口的入站请求路由到www.google.com

下面启动容器测试:

  1. > docker run -d --name envoy -p 10000:10000 envoyproxy/envoy-dev:latest
  2. 27e422f34b389d99e9180e47d8109a19975ccd139f42ac2f4fa9f724906b72f6
  3. > docker ps | findstr 'envoy'
  4. 27e422f34b38 envoyproxy/envoy-dev:latest "/docker-entrypoint.?? 2 minutes ago Up 2 minutes 0.0.0.0:10000->10000/tcp envoy
  5. > curl -I http://localhost:10000
  6. HTTP/1.1 200 OK
  7. content-type: text/html; charset=ISO-8859-1
  8. p3p: CP="This is not a P3P policy! See g.co/p3phelp for more info."
  9. date: Sat, 17 Oct 2020 04:38:38 GMT
  10. server: envoy
  11. x-xss-protection: 0
  12. x-frame-options: SAMEORIGIN
  13. expires: Sat, 17 Oct 2020 04:38:38 GMT
  14. cache-control: private
  15. set-cookie: 1P_JAR=2020-10-17-04; expires=Mon, 16-Nov-2020 04:38:38 GMT; path=/; domain=.google.com; Secure
  16. set-cookie: NID=204=h0EoJXNOTbQA11L-tVowqcwloS0-BCTR71IeN4irsmpubdPIIS4sU8Gco79pt1NhONAxxFdUJ46SKvbX4Ni-jKMWbSW0k_kn3fFkVrfLm7OOBbAtUWtxGGOCRJGbSNIRyOPfDB7_wMngEWW3yoFEs9diSCtZK9DWFZdtJJZtWuI; expires=Sun, 18-Apr-2021 04:38:38 GMT; path=/; domain=.google.com; HttpOnly
  17. 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"
  18. x-envoy-upstream-service-time: 37
  19. transfer-encoding: chunked

PS: 请确保本地机器能访问Google,否则curl -I http://localhost:10000 会出错。

接下来我们进入容器内部,查看下配置文件,默认路径为/etc/envoy/envoy.yaml

  1. docker exec -it envoy /bin/bash
  2. root@27e422f34b38:/# cat /etc/envoy/envoy.yaml
  3. admin:
  4. access_log_path: /tmp/admin_access.log
  5. address:
  6. socket_address:
  7. protocol: TCP
  8. address: 127.0.0.1
  9. port_value: 9901
  10. static_resources:
  11. listeners:
  12. - name: listener_0
  13. address:
  14. socket_address:
  15. protocol: TCP
  16. address: 0.0.0.0
  17. port_value: 10000
  18. filter_chains:
  19. - filters:
  20. - name: envoy.filters.network.http_connection_manager
  21. typed_config:
  22. "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
  23. stat_prefix: ingress_http
  24. route_config:
  25. name: local_route
  26. virtual_hosts:
  27. - name: local_service
  28. domains: ["*"]
  29. routes:
  30. - match:
  31. prefix: "/"
  32. route:
  33. host_rewrite_literal: www.google.com
  34. cluster: service_google
  35. http_filters:
  36. - name: envoy.filters.http.router
  37. clusters:
  38. - name: service_google
  39. connect_timeout: 30s
  40. type: LOGICAL_DNS
  41. # Comment out the following line to test on v6 networks
  42. dns_lookup_family: V4_ONLY
  43. lb_policy: ROUND_ROBIN
  44. load_assignment:
  45. cluster_name: service_google
  46. endpoints:
  47. - lb_endpoints:
  48. - endpoint:
  49. address:
  50. socket_address:
  51. address: www.google.com
  52. port_value: 443
  53. transport_socket:
  54. name: envoy.transport_sockets.tls
  55. typed_config:
  56. "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
  57. 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

  1. > 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
  2. > docker ps | findstr 'envoy'
  3. 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
  4. 3cd12b5f6ddd envoyproxy/envoy-dev:latest "/docker-entrypoint.?? About an hour ago Up About an hour 0.0.0.0:10000->10000/tcp envoy
  5. > curl -I http://localhost:15001
  6. HTTP/1.1 200 OK
  7. accept-ranges: bytes
  8. cache-control: private, no-cache, no-store, proxy-revalidate, no-transform
  9. content-length: 277
  10. content-type: text/html
  11. date: Sat, 17 Oct 2020 05:41:01 GMT
  12. etag: "575e1f65-115"
  13. last-modified: Mon, 13 Jun 2016 02:50:13 GMT
  14. pragma: no-cache
  15. server: envoy
  16. 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启动三个容器进行测试。由于项目文件结构简单,这里不再过多阐述,主要包含四个部分:

  1. City Api
  2. Weather Api
  3. Envoy 代理配置
  4. docker compose 配置

整体解决方案如下图所示。源码路径:K8S.NET.Envoy

Envoy 代理配置基于第一节的基础上进行修改,如下所示:

  1. admin:
  2. access_log_path: /tmp/admin_access.log
  3. address:
  4. socket_address:
  5. protocol: TCP
  6. address: 0.0.0.0
  7. port_value: 9903
  8. static_resources:
  9. listeners:
  10. - name: listener_0
  11. address:
  12. socket_address:
  13. protocol: TCP
  14. address: 0.0.0.0
  15. port_value: 10003
  16. filter_chains:
  17. - filters:
  18. - name: envoy.filters.network.http_connection_manager
  19. typed_config:
  20. "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
  21. stat_prefix: ingress_http
  22. route_config:
  23. name: local_route
  24. virtual_hosts:
  25. - name: local_service
  26. domains: ["*"]
  27. routes:
  28. - match:
  29. prefix: "/c"
  30. route:
  31. prefix_rewrite: "/city"
  32. cluster: city_service
  33. - match:
  34. prefix: "/w"
  35. route:
  36. prefix_rewrite: "/weather"
  37. cluster: weather_service
  38. http_filters:
  39. - name: envoy.filters.http.router
  40. clusters:
  41. - name: city_service
  42. connect_timeout: 0.25s
  43. type: LOGICAL_DNS
  44. # Comment out the following line to test on v6 networks
  45. dns_lookup_family: V4_ONLY
  46. lb_policy: ROUND_ROBIN
  47. load_assignment:
  48. cluster_name: city_service
  49. endpoints:
  50. - lb_endpoints:
  51. - endpoint:
  52. address:
  53. socket_address:
  54. address: cityapi
  55. port_value: 80
  56. - name: weather_service
  57. connect_timeout: 0.25s
  58. type: LOGICAL_DNS
  59. # Comment out the following line to test on v6 networks
  60. dns_lookup_family: V4_ONLY
  61. lb_policy: ROUND_ROBIN
  62. load_assignment:
  63. cluster_name: weather_service
  64. endpoints:
  65. - lb_endpoints:
  66. - endpoint:
  67. address:
  68. socket_address:
  69. address: weatherapi
  70. port_value: 80

以上配置Envoy监听10003端口,通过指定prefix_rewrite重写前缀,将/c路由至cityapi/city路径,将/w路由至weatherapi/weather路径。

docker-compose配置如下:

  1. version: '3'
  2. services:
  3. envoygateway:
  4. build: Envoy/
  5. ports:
  6. - "9903:9903"
  7. - "10003:10003"
  8. volumes:
  9. - ./Envoy/envoy.yaml:/etc/envoy/envoy.yaml
  10. cityapi:
  11. build: K8S.NET.CityApi/
  12. ports:
  13. - "8080:80"
  14. environment:
  15. ASPNETCORE_URLS: "http://+"
  16. ASPNETCORE_ENVIRONMENT: "Development"
  17. weatherapi:
  18. build: K8S.NET.WeatherApi/
  19. ports:
  20. - "8082:80"
  21. environment:
  22. ASPNETCORE_URLS: "http://+"
  23. ASPNETCORE_ENVIRONMENT: "Development"

从上可以看到,主要用来启动三个服务:

  1. envoy gateway:其中将项目路径下/Envoy/envoy.yaml挂载到容器目录/etc/envoy/envoy.yaml。同时暴露2个端口,9903,10003。
  2. city api
  3. weather api

因此最终可以通过以下路径进行访问:

  1. http://localhost:10003/c 访问city api。
  2. http://localhost:10003/w 访问weather api。

执行以下命令,启动应用和代理,并测试:

  1. > docker-compose up -d
  2. Starting k8snetenvoy_envoygateway_1 ... done
  3. Starting k8snetenvoy_cityapi_1 ... done
  4. Starting k8snetenvoy_weatherapi_1 ... done
  5. > docker-compose ps
  6. Name Command State Ports
  7. -----------------------------------------------------------------------------------------------------------------------
  8. k8snetenvoy_cityapi_1 dotnet K8S.NET.CityApi.dll Up 443/tcp, 0.0.0.0:8080->80/tcp
  9. k8snetenvoy_envoygateway_1 /docker-entrypoint.sh envo ... Up 10000/tcp, 0.0.0.0:10003->10003/tcp,
  10. 0.0.0.0:9903->9903/tcp
  11. k8snetenvoy_weatherapi_1 dotnet K8S.NET.WeatherApi.dll Up 443/tcp, 0.0.0.0:8082->80/tcp
  12. > curl http://localhost:10003/c
  13. Shanghai
  14. > curl http://localhost:10003/w
  15. Cool

3. eShopOnContainers 中的应用

eShopOnContainer 中主要定义了四个API 网关(BFF 模式),服务间通信方式主要有两种,一种是HTTP,一种是gRPC。如果启用Service Mesh并且部署至K8S,服务整体通信架构如下图所示:

有两点需要补充说明:

  1. Linkerd是一种Service Mesh,其核心思想是借助Sidecar模式无侵入式对应用进行服务治理,包括服务发现、流量管理、负载均衡、路由等。
  2. 了解过Istio(目前比较流行的Service Mesh)应该知道,Envoy在Istio中作为Sidecar而存在,而在eShopOnContainers中Envoy被充当API Gateways。

基于上面的基础,再来看eShopOnContainers中的配置,其实就很明白了,主要是配置文件从Ocelot 转变到envoy.yaml,配置如下图所示。

路由配置如下:

  1. /m/ 、/marketing-api/ 路由至:marketing api
  2. /c/、/catalog-api/ 路由至:catalog api
  3. /o/、/ordering-api/ 路由至:ordering api
  4. /b/、/basket-api/ 路由至:basket api
  5. / 路由至: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 进行嗅探和统计,包括:MongoDBDynamoDB 等。

  • 可观测性 : Envoy 内置 stats 模块,可以集成诸如 prometheus/statsd 等监控方案。还可以集成分布式追踪系统,对请求进行追踪。

再来看下Ocelot:其本质还是ASP.NET Core中的一个请求中间件。只能进行7层代理,不支持 gRPC,不支持监控。因此总体而言,Envoy更契合云原生对网络代理的诉求。

5. 总结

本文简要梳理了Envoy的基本用法,以及其在eShopOnContainers中的运用。Envoy作为一个比肩Nginx的服务代理,其特性在Service Mesh中有着灵活的运用。本文就讲到这里了,下次有机会在和大家分享下Envoy在Service Mesh中的应用。

参考资料:

  1. Envoy 介绍 - Envoy 中文指南
  2. Build an API Gateway with Envoy and use with .NET Core APIs

eShopOnContainers 知多少[12]:Envoy gateways的更多相关文章

  1. Git / 程序员需要知道的12个Git高级命令

    众所周知,Git目前已经是分布式版本控制领域的翘楚,围绕着Git形成了完整的生态圈.学习Git,首先当然是学习Git的基本工作流.相比于SVN等传统版本控制系统来说,Git是专为分布式版本控制而生的强 ...

  2. eShopOnContainers 知多少[1]:总体概览

    引言 在微服务大行其道的今天,Java阵营的Spring Boot.Spring Cloud.Dubbo微服务框架可谓是风水水起,也不得不感慨Java的生态圈的火爆.反观国内.NET阵营,微服务却不愠 ...

  3. 每个IT安全专业人员应该知道的12种根本漏洞

    每个IT安全专业人员应该知道的12种根本漏洞 每年,IT安全专业人员都面临着数千个新的软件漏洞和数百万个不同的恶意软件程序,但只有12种根本漏洞会让这些软件漏洞和恶意软件程序攻击你的设备.了解这些根本 ...

  4. eShopOnContainers 知多少[9]:Ocelot gateways

    引言 客户端与微服务的通信问题永远是一个绕不开的问题,对于小型微服务应用,客户端与微服务可以使用直连的方式进行通信,但对于对于大型的微服务应用我们将不得不面对以下问题: 如何降低客户端到后台的请求数量 ...

  5. eShopOnContainers 知多少[8]:Ordering microservice

    1. 引言 Ordering microservice(订单微服务)就是处理订单的了,它与前面讲到的几个微服务相比要复杂的多.主要涉及以下业务逻辑: 订单的创建.取消.支付.发货 库存的扣减 2. 架 ...

  6. eShopOnContainers 知多少[5]:EventBus With RabbitMQ

    1. 引言 事件总线这个概念对你来说可能很陌生,但提到观察者(发布-订阅)模式,你也许就很熟悉.事件总线是对发布-订阅模式的一种实现.它是一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需 ...

  7. 你需要知道的12个Git高级命令

    众所周知,Git目前已经是分布式版本控制领域的翘楚,围绕着Git形成了完整的生态圈.学习Git,首先当然是学习Git的基本工作流.相比于SVN等传统版本控制系统来说,Git是专为分布式版本控制而生的强 ...

  8. 每个Web开发人员应该知道的12个终端命令

    Tips 原文作者:Danny Markov 原文地址:12 Terminal Commands Every Web Developer Should Know About 终端是开发人员的武器库中最 ...

  9. eShopOnContainers 知多少[10]:部署到 K8S | AKS

    1. 引言 断断续续,感觉这个系列又要半途而废了.趁着假期,赶紧再更一篇,介绍下如何将eShopOnContainers部署到K8S上,进而实现大家常说的微服务上云. 2. 先了解下 Helm 读过我 ...

随机推荐

  1. [LeetCode]198. 打家劫舍(DP)

    题目 你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给定一个 ...

  2. [程序员代码面试指南]数组和矩阵-数组的partition调整

    题目 补充问题:数组只含0,1,2,对数组排序,要求时间复杂度O(n),额外空间复杂度O(1) 题解 维护三个变量,l,idx,r.左区间[0,l],中间区间[l+1,idx],右区间[idx+1,r ...

  3. springboot中图标的定制

    因为我用的版本是org.springframework.boot spring-boot-starter-parent 2.3.3.RELEASE 第一种方法: 配置一个application.yml ...

  4. hystrix文档翻译之如何使用

    Hello World! 使用HystrixCommand实现“Hello World”. public class CommandHelloWorld extends HystrixCommand& ...

  5. hystrix源码之概述

    概述 hystrix核心原理是通过代理执行用户命令,记录命令执行的metrics信息,通过这些metrics信息进行降级和熔断. 源码结构包括一下几个部分: 熔断器 熔断器就是hystrix用来判断调 ...

  6. Thread、ThreadLocal源码解析

    今天来看一下Thread和ThreadLocal类的源码. 一.Thread (1)首先看一下线程的构造方法,之后会说每种参数的用法,而所有的构造函数都会指向init方法 //空构造创建一个线程 Th ...

  7. MySql约束_设计_备份还原(资料二)

    今日内容 1. DQL:查询语句 1. 排序查询 2. 聚合函数 3. 分组查询 4. 分页查询 2. 约束 3. 多表之间的关系 4. 范式 5. 数据库的备份和还原 DQL:查询语句 1. 排序查 ...

  8. Java基础一篇过(三)I/O流总结

    一.啥是I/O 概念:I/O为输入,输出流的统称,流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象. 本质:本质是数据传输,即数据在两设备间的传输称为流,根据数据传输特性将流抽象为各 ...

  9. 如何使用NuGet package .nupkg文件?

    如果你本来就有.nupkg文件并且你只需要.dll文件的话,你可以通过打开.zip下的lib文件夹来获取. 例如:

  10. 微服务实战系列(二)-注册中心Springcloud Eureka客户端

    1. 场景描述 前几天介绍了下springcloud的Eureka注册中心(springcloud-注册中心快速构建),今天结合springboot-web介绍下eureka客户端服务注册. 2. 解 ...