专栏首页圣杰的专栏eShopOnContainers 知多少[12]:Envoy gateways

eShopOnContainers 知多少[12]:Envoy gateways

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启动三个容器进行测试。由于项目文件结构简单,这里不再过多阐述,主要包含四个部分:

  1. City Api
  2. Weather Api
  3. Envoy 代理配置
  4. 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"

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

  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。

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

> 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,服务整体通信架构如下图所示:

有两点需要补充说明:

  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/2HTTP/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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • eShopOnContainers 知多少[9]:Ocelot gateways

    客户端与微服务的通信问题永远是一个绕不开的问题,对于小型微服务应用,客户端与微服务可以使用直连的方式进行通信,但对于对于大型的微服务应用我们将不得不面对以下问题...

    圣杰
  • Istio 知多少 | 下一代微服务的守护者

    在写完eShopOnContainers 知多少[12]:Envoy gateways后,就一直想进一步探索Service Mesh,最近刚在极客时间上学完《S...

    圣杰
  • eShopOnContainers 知多少[4]:Catalog microservice

    Catalog microservice(目录微服务)维护着所有产品信息,包括库存、价格。所以该微服务的核心业务为:

    圣杰
  • eShopOnContainers 知多少[3]:Identity microservice

    通常,服务所公开的资源和 API 必须仅限受信任的特定用户和客户端访问。那进行 API 级别信任决策的第一步就是身份认证——确定用户身份是否可靠。

    圣杰
  • eShopOnContainers 知多少[8]:Ordering microservice

    Ordering microservice(订单微服务)就是处理订单的了,它与前面讲到的几个微服务相比要复杂的多。主要涉及以下业务逻辑:

    圣杰
  • eShopOnContainers 知多少[7]:Basket microservice

    Basket microservice(购物车微服务)主要用于处理购物车的业务逻辑,包括:

    圣杰
  • eShopOnContainers 知多少[5]:EventBus With RabbitMQ

    事件总线这个概念对你来说可能很陌生,但提到观察者(发布-订阅)模式,你也许就很熟悉。事件总线是对发布-订阅模式的一种实现。它是一种集中式事件处理机制,允许不同的...

    圣杰
  • eShopOnContainers 知多少[2]:Run起来

    执行命令git clone https://github.com/dotnet/eShopOnContainers.gitclone代码到本地。使用默认DEV分...

    圣杰
  • istio实现灰度发布的流量策略

    将流量从基础设施扩展中解耦,这样就可以让 Istio 提供各种独立于应用程序代码之外的流量管理功能。除了 A/B 测试的动态请求路由,逐步推出和金丝雀发布之外,...

    dogfei
  • eShopOnContainers 知多少[1]:总体概览

    在微服务大行其道的今天,Java阵营的Spring Boot、Spring Cloud、Dubbo微服务框架可谓是风水水起,也不得不感慨Java的生态圈的火爆。...

    圣杰
  • eShopOnContainers 知多少[10]:部署到 K8S | AKS

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

    圣杰
  • Service Mesh - Istio安装与部署

    在当前版本Istio的安装与部署已经变得非常简单了,只需要几个简单的步骤就能将Istio环境搭建起来。首先要做的是下载Istio(在文档中核对Istio支持的k...

    端碗吹水
  • eShopOnContainers 知多少[6]:持久化事件日志

    事件总线解决了微服务间如何基于集成事件进行异步通信的问题。然而只有事件总线正常运行,微服务之间基于事件的通信才得以运转。 而现实情况是,总有这样或那样的问题,...

    圣杰
  • eShopOnContainers 知多少[11]:服务间通信之gRPC

    最近翻看最新3.0 eShopOncontainers源码,发现其在架构选型中补充了 gRPC 进行服务间通信。那就索性也写一篇,作为系列的补充。

    圣杰
  • 基于istio 的traffic mirror为预发布环境导入线上真实流量

    流量镜像,也叫影子流量(Traffic shadowing),是一种通过复制生产环境的流量到非生产环境(一般是staging环境)进行测试开发的工作模式。

    机械视角
  • Istio路由管理简介

    本文以Istio 1.3.0 在Kubernetes中的部署为例,结合其bookinfo例子(https://istio.io/docs/examples/bo...

    王录华
  • Istio的运维-诊断工具(istio 系列五)

    在参考官方文档的时候发现环境偶尔会出现问题,因此插入一章与调试有关的内容,便于简单问题的定位。涵盖官方文档的诊断工具章节

    charlieroro
  • Istio入门——了解什么是服务网格以及如何在微服务体系中使用

    最近几年,软件体系结构领域发生了巨大的变化。我们都见证了这一重大转变,就是将大型的整体应用程序和粗粒度应用程序分解为被称为微服务的细粒度部署单元,主要通过同步R...

    云原生
  • 使用 Istio 实现非侵入流量治理

    现在最火的后端架构无疑是微服务了,微服务将之前的单体应用拆分成了许多独立的服务应用,每个微服务都是独立的,好处自然很多,但是随着应用的越来越大,微服务暴露出来的...

    我是阳明

扫码关注云+社区

领取腾讯云代金券