暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

云原生架构下的微服务之:3 Envoy 配置解释

运维老狗 2021-12-03
1335

3 Envoy 配置解释

3.1 Listeners 配置解释

listeners 是 envoy 接入请求流量的非常关键的组件,要想接入流量进来无论是本地还是远程的,我们必须要定义 listeners ,而 envoy 支持两种 listeners 分别是 TCP
UDP

而后每一个监听器都是独立进行定义的,应该有自己独立的 filter chains (过滤器链),那么有哪些过滤器可以通过我们使用呢?

其实我们提到的各种各样高级功能比如:超时、重试、限速、等等 都是需要额外手动配置过滤器来实现

总结:

  • 独立部署时,建议每个主机仅部署单个 Envoy 实例,并在必要时于此实例上运行一到多个侦听器;

  • Enovy 支持 TCP 和 UDP 两种类型的侦听器;

  • 每个侦听器都独立配置了一些网络级(L3/L4)过滤器。

  • 侦听器收到的连接请求将由其过滤器链中的各过滤器进行处理;

  • 通用侦听器体系结构用于执行特使用于的绝大多数不同代理任务

    • 速率限制

    • TLS 客户端身份验证

    • HTTP 连接管理

    • 原始 TCP 代理


在 envoy 上可以使用的过滤器分为两类:

  • 3L/4L 过滤器

  • 7L 过滤器


3.2 3L/4L 过滤器

3L/4L 过滤器也就意味着只能在 OSI 网络模型的 3,4 层模型上去做一些处理,比如过滤一下源地址目标地址,或检查一下源端口目标端口更复杂的就做不到了,但 7L 过滤器必须在某个 3、4 层过滤器基础上来实现。

比如说 4L 过滤器有 http_connection_manager
:意思就是我要把它的解码能力上升至第 7 层支持 HTTP 协议,所以我们必须把 http_connection_manager
这个 3,4 层过滤器加载以后才能使用 7 层过滤器

比如我们要自定义访问日志格式,做 http 的限流,我们抓取 http 的请求标头和响应标头,以及基于标头做各种高级路由等等这些都需要使用到 7 层过滤器。

所以必须要串接各种过滤器来完成各种各样的功能


L3/L4 过滤器构成 envoy 连接处理的核心。

  • FilterAPI 允许将不同的过滤器集混合、匹配并连接到给定的侦听器。

  • 有三种不同类型的网络筛选器:

    • 读取:当 envoy 从下游连接接收数据时,将调用读取 filter 。

    • 写入:当特使将要向下游连接发送数据时,将调用写入 filter。

    • 读/写:当特使从下游连接接收数据和将要向下游连接发送数据时,都会调用读/写筛选器。

  • 网络级过滤器的API相对简单,因为过滤器最终会对原始字节和少量连接事件进行操作

  • 链中的过滤器可以停止,然后继续迭代以进一步过滤。


Enovy内置了许多L3/L4过滤器,例如:

  • 代理类:TCP Proxy、HTTP connection manager、Thrift Proxy、Mongo proxy、Dubbo Proxy、ZooKeeper proxy、MySQL proxy 和 Redis proxy等,

  • 其它:Client TLS authentication、Rate limit、Role Based Access Control (RBAC) Network Filter 和 Upstream Cluster from SNI 等。


HTTP connection manager 能够支持加载出来各种各样的 7 层过滤器

  • HTTP connection manager 自身是L3/L4过路器,它能够将原始字节转换为 HTTP 级别消息和事件(例如,headers 和 body 等)

  • 它还处理所有 HTTP 连接和请求共有的功能,例如访问日志记录、请求 ID 生成和跟踪、请求/响应头操作、路由表管理和统计信息等;

  • 与 L3/L4 过滤器堆栈相似,Envoy 还支持在 HTTP 连接管理器中使用 HTTP 级过滤器堆栈;

    • HTTP 过滤器在 L7 运行,它们访问和操作 HTTP 请求和响应;例如,gRPC-JSON Transcoder Filter 为 gRPC 后端公开 REST API,并将请求和响应转换为相应的格式;

    • 常用的HTTP过路器有Router、Rate limit、Health check、Gzip和Fault Injection等;


3.3 L3/L4 过滤器 和 HTTP 过滤器

在这个图上大概描述了我们过滤器的类型,我们只有了解上图这些过滤器才能够知道他的高级功能是怎么工作的

上图依次从左往右分别是:newtwork filters
UDP listener filters
Listener filters
HTTP filters

network filters 可能会用到的过滤器:

  • Rate limit(限速)

  • TCP Proxy

  • http connection manager :一旦启动以后马上就能支持各式各样的 7 层过滤器也就是 HTTP filters
    ,只有启用了 http connection manager
    才能使用这些 7 层过滤器

HTTP filters 可能会用到的过滤器:

  • JWT Authentication(java token 认证)

  • Fault Injection(故障注入)

  • Router(7 层高级路由):流量分割、流量迁移、等等

  • Health check(健康状态检测)

  • Gzip:实现报文的压缩和解压缩


3.4 upstream cluster(上游集群)

如上图:

对 envoy 来说,我们要定义 listener 以接入客户端流量,而对每个 listener 内部应该有 filter chains ,而 filter chains 其实就是定义 1至多个过滤器,而关键的过滤器叫做  http connection manager
,一旦  http connection manager
 启动之后就能够支持 7 层过滤器,而 7 层过滤器里面有个过滤器叫做 router。

而在这里头需要注意的是:

首先 listener 本身的配置是可以基于 LDS 发现的,而这里的 router 所生成的路由配置是可以基于 RDS 发现,虽然路由是嵌套在监听器内部的但是他们可以使用各自不同的协议来发现。

也就是说 router 是基于 RDS 做路由发现就可以找对应的服务器来发现,listener 则基于对应的 LDS 服务器来发现

接着再说 cluster ,对于多个 cluster 而言每一个 cluster 都由 cluster manager 来管理,所有每一个集群都可以基于 CDS 来发现,就是集群自己的定义比如包括负载均衡策略、集群类型、集群名称等,这些都是基于 CDS 来发现。

每一个集群都需要一到多个端点 endpoint,而这些 endpoint 都可以基于 EDS 发现。

其实不仅仅是这些,我们都知道集群内部还能对上游服务器做健康状态检测而健康状态检测可以使用 HDS 来发现


一个 envoy 可以支持多个 cluster 定义,所以 Envoy 可配置任意数量的上游集群,并使用 Cluster Manager 进行管理,而 cluster manager 通常不用配置他的默认配置就能实现绝大多数场景;

  • 由集群管理器负责管理的各集群可以由用户静态配置,也可借助于 CDS(cluster discovery) API 动态获取

  • 集群中的每个成员由 endpoint 进行标识,它可由用户静态配置,也可动态发现;而 endpoint 动态发现有两种方式分别是通过 EDS 或 DNS 服务

    • Static
      :静态配置,表示在 envoy.yaml 中 cluster 里面的地址和端口都是手动指定

    • Strict DNS
      :严格 DNS,Envoy 将持续和异步地每隔几分钟或者几秒钟就请求解析指定的 DNS 目标,并将 DNS 结果中的返回的每个 IP 地址视为上游集群中可用成员,比如说每隔 30s 解析一次,如果说这次和上一次解析得到的结果不一样也就意味着替换上游集群的 ip

    • Logical DNS
      :逻辑 DNS,集群仅使用在需要启动新连接时返回的第一个 IP 地址,而非严格获取 DNS 查询的结果并假设它们构成整个上游集群;适用于必须通过 DNS 访问的大规模 Web 服务集群;使用 logical DNS 请求解析域名,如果 cluster 有 5 个端点并返回了 5 个地址,但是 logical DNS 只把第一个地址作为上游端点使用,整个集群规模有多少个不用在乎

    • Original destination
      :当传入连接通过 iptables 的 REDIRECT 或 TPROXY target 或使用代理协议重定向到 Envoy 时,可以使用原始目标集群;

    • Endpoint discovery service (EDS)
      :EDS 是一种基于 GRPC 或 REST-JSON API 的 xDS 管理服务器获取集群成员的服务发现方式;

    • Custom cluster
      :Envoy 还支持在集群配置上的 cluster_type 字段中指定使用自定义集群发现机制;

  • 什么情况下会用 Logical DNS(逻辑 DNS) 什么情况下会用 Strict DNS(严格 DNS):

    • Strict DNS
      :一般而言如果是本地集群,DNS 也是本地的 DNS 服务那我们就可以使用严格 DNS

    • Logical DNS
      :如果是做正向代理访问互联网上的其他服务,比如访问 baidu.com 会解析出一大串 IP ,这在这情况下我们只用第一个 IP 作为上游服务器就可以了


使用较多的 static
strict DNS
Logical DNS


3.4.1 演示 strict DNS

想要实现如下:

以 egress 为例子,假如说 egress 的两个端点就是 webserver01、webserver02 为我们本地服务,docker-compose 内置的 DNS 服务能够实现解析,所以我们将这两个服务视为是在一个相同的域,而且在 yaml 文件中给他们两个 service 都定义 myservice
的别名

然后将 envoy 视为上游服务器使用的时候,我们完全可以使用 Strict DNS
来解析 myservice
这个域名,解析的结果要么是 10.0.10.11
要么就是 10.0.10.12
,因为他们两个是同一个 myservice
的别名,这是 docker-compose 内置的 DNS 服务功能


环境说明

两个 Service:

  • webserver01:第一个后端服务,地址为 10.0.10.11

  • webserver02:第二个后端服务,地址为 10.0.10.12


1.编写 docker-compose.yaml

root@envoy:~/servicemesh_in_practise-develop/Envoy-Basics/http-egress# vim docker-compose.yaml 
# Author: zgy
version: '3.3'

services:
# 定义 envoy
envoy:
  image: envoyproxy/envoy-alpine:v1.18-latest
  volumes:
  - ./envoy.yaml:/etc/envoy/envoy.yaml
  networks:
    envoymesh:
      ipv4_address: 10.0.10.2 # 定义 envoy 容器的 ip
      aliases:
      - front-proxy
  depends_on:
  - webserver01
  - webserver02

# 定义 client 共享了 envoy 的网络空间,也就是 10.0.10.2 这个 ip
client:
  image: ikubernetes/admin-toolbox:v1.0 # 为了等会跑起来之后模拟客户端的交互式,所以这里自己做了一个镜像,里面内置了一些 curl 命令等工具
  network_mode: "service:envoy"
  depends_on:
  - envoy

# server 01 定义
webserver01:
  image: ikubernetes/demoapp:v1.0
  hostname: webserver01
  networks:
    envoymesh:
      ipv4_address: 10.0.10.11
      aliases:
      - webserver01
      - myservice # 注意定义别名

# server 02 定义
webserver02:
  image: ikubernetes/demoapp:v1.0
  hostname: webserver02
  networks:
    envoymesh:
      ipv4_address: 10.0.10.12
      aliases:
      - webserver02
      - myservice # 注意定义别名

# 定义网络
networks:
envoymesh:
  driver: bridge
  ipam:
    config:
      - subnet: 10.0.10.0/24


2.编辑 envoy.yaml 配置文件

root@envoy:~/servicemesh_in_practise-develop/Envoy-Basics/http-egress# vim envoy.yaml 
# Author: ZGY
static_resources:
listeners:
- name: listener_0
  address:
    socket_address: { address: 127.0.0.1, port_value: 80 }
  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
        codec_type: AUTO
        route_config:
          name: local_route
          virtual_hosts:
          - name: web_service_1
            domains: ["*"]
            routes:
            - match: { prefix: "/" }
              route: { cluster: web_cluster } # 绑定 cluster
        http_filters:
        - name: envoy.filters.http.router

clusters:
- name: web_cluster
  connect_timeout: 0.25s
  type: STRICT_DNS # 将类型改为 STRICT_DNS 就表示说我们要基于 STRICT_DNS 代理
  lb_policy: ROUND_ROBIN
  load_assignment:
    cluster_name: web_cluster
    endpoints:
    - lb_endpoints:
      - endpoint:
          address:
            socket_address: { address: myservice, port_value: 80 } # 并将 address 改为 myservice 也就是在 docker-compose 中指定的别名,随后 envoy 会解析 myservice 这个地址


3.启动

root@envoy:~/servicemesh_in_practise-develop/Envoy-Basics/http-egress# docker-compose up


4.因为这里采用的是 egress 方式,所以我们需要进入到容器中进行 curl 测试

root@envoy:~# cd servicemesh_in_practise-develop/Envoy-Basics/http-egress/
root@envoy:~/servicemesh_in_practise-develop/Envoy-Basics/http-egress# docker-compose exec client /bin/sh
[root@b82b6b6d9b7f /]# curl myservice
iKubernetes demoapp v1.0 !! ClientIP: 10.0.10.2, ServerName: webserver02, ServerIP: 10.0.10.12!
[root@b82b6b6d9b7f /]# curl myservice
iKubernetes demoapp v1.0 !! ClientIP: 10.0.10.2, ServerName: webserver02, ServerIP: 10.0.10.12!
[root@b82b6b6d9b7f /]# curl myservice
iKubernetes demoapp v1.0 !! ClientIP: 10.0.10.2, ServerName: webserver01, ServerIP: 10.0.10.11!
[root@b82b6b6d9b7f /]# curl myservice
iKubernetes demoapp v1.0 !! ClientIP: 10.0.10.2, ServerName: webserver02, ServerIP: 10.0.10.12!
[root@b82b6b6d9b7f /]# curl myservice
iKubernetes demoapp v1.0 !! ClientIP: 10.0.10.2, ServerName: webserver01, ServerIP: 10.0.10.11!

# 可以看到我们 curl 对于的 myservice 会得到后端 cluster 服务的解析如:webserver01、webserver02


总结:

通过 STRICT_DNS
的 DNS 服务解析 myservice ,事实上可以发现我们只定义了一个 myservice
端点,但是他发现出来的端点可能是多个

对于 cluster 而言的配置其实也是有着一大堆的配置参数,能够非常精确的去定义 cluster 逻辑的,但是最为简单的配置其实也就如下几项:

  • 名称:每个 Cluster 主要由集群名称,以及集群中的端点(通常是提供服务的IP地址和端口)所组成

  • 类型:static
    strict DNS
    Logical DNS
    ...

  • endpoint:Envoy Cluster支持纯静态定义方式来指定端点,也允许以动态方式发现各端点,甚至还支持自定


文章转载自运维老狗,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论