service mesh envoy

一、 编译和安装

1、 编译

Envoy使用 Bazel工具 构建系统。
为了简化初次构建以及快速入门,我们提供了一个基于Ubuntu16的Docker容器镜像,其中包含了构建静态链接Envoy所需的所有内容,请参阅 ci/README.md

目前有3个基础的编译用的镜像:
(1) envoyproxy/envoy-build 等同于 envoyproxy/envoy-build-ubuntu.
(2) envoyproxy/envoy-build-ubuntu 基于 Ubuntu 16.04 (Xenial) ,使用 GCC 5.4 compiler.
(3) envoyproxy/envoy-build-centos 基于 CentOS 7,使用 GCC 5.3.1 compiler (devtoolset-4).

构建envoy二进制文件:

# 首先 clone 代码
git clone https://github.com/envoyproxy/envoy.git
cd envoy

# 构建 dev 版本的 envoy
./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.dev'

# 构建默认使用的是 envoyproxy/envoy-build-ubuntu 镜像, 如果要使用其他的镜像,则如下
IMAGE_NAME=envoyproxy/envoy-build-centos \
./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.dev'

# 如果要使用代理
IMAGE_NAME=envoyproxy/envoy-build-centos \
http_proxy=http://10.0.209.105:17012 \
https_proxy=http://10.0.209.105:17012 \
./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.dev'

# dev 版本编译后的envoy二进制文件默认位于宿主机的 /tmp/envoy-docker-build/envoy/source/exe/envoy-fastbuild
# 你可以通过变量 ENVOY_DOCKER_BUILD_DIR=~/build 更改此位置为 ~/build

# 构建 release 版本的 envoy
IMAGE_NAME=envoyproxy/envoy-build-centos \
./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.release.server_only'

# release 版本编译后的envoy二进制文件默认位于宿主机的 /tmp/envoy-docker-build/envoy/source/exe/envoy
# 你可以通过变量 ENVOY_DOCKER_BUILD_DIR=~/build 更改此位置为 ~/build

# 构建 debug 版本的 envoy
IMAGE_NAME=envoyproxy/envoy-build-centos \
./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.debug.server_only'

# debug 版本编译后的envoy二进制文件默认位于宿主机的 /tmp/envoy-docker-build/envoy/source/exe/envoy-debug
# 你可以通过变量 ENVOY_DOCKER_BUILD_DIR=~/build 更改此位置为 ~/build

# 使用自定义的镜像tag
IMAGE_NAME=envoyproxy/envoy-build-centos \
IMAGE_ID=latest \
./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.release.server_only'

# 最终的构建命令 (IMAGE_ID=latest可选)
# 代理只是在外面执行命令时访问网络有用,在容器内编译时如果不能直接访问网络,编译仍然会失败
# 至于如何设置容器内的环境变量,以及设置哪些环境变量,待续
IMAGE_NAME=envoyproxy/envoy-build-centos \
http_proxy=http://1.1.1.1:x \
https_proxy=http://1.1.1.1:x \
./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.release.server_only'

我使用 envoyproxy/envoy-build-centos 编译了一个 release 版本的 envoy:
链接: https://pan.baidu.com/s/1s7N4ON6blG3277MHfDEs7g 密码: bsc8

如果需要手动构建,请按照bazel/README.md 中的说明进行操作。
(手动构建略)

2、 预构建的二进制文件

目前提供了3个带有 envoy二进制程序的 docker 镜像,如下所示:

(1) envoyproxy/envoy:基于Ubuntu Xenial存放带有符号的二进制文件版本。
(2) envoyproxy/envoy-alpine:基于glibc alpine无符号二进制文件版本。
(3) envoyproxy/envoy-alpine-debug:基于glibc alpine可调试的二进制文件版本。

(不知道在CentOS 7下能用哪一个?)

3、 工具

(1) 配置加载检查工具

配置加载检查工具 校验 JSON格式的配置文件 是否符合JSON编码规范 和 Envoy JSON模式。
该工具利用 test/config_test/config_test.cc 中的配置进行校验。
在服务配置初始化中加载JSON配置时,会使用到它进行校验。

(
建议:
构建工具可以进入到 envoyproxy/envoy-build-centos 镜像内执行,例如:
docker run -it envoyproxy/envoy-build-centos:xxx bash
cd /bazel-prebuilt-output/external/envoy_api
然后在执行 bazel 构建命令
)

构建 config_load_check_tool

http_proxy=http://1.1.1.1:x \
https_proxy=http://1.1.1.1:x \
bazel build //test/tools/config_load_check:config_load_check_tool
# 构建成功后,可执行文件位于 bazel-bin/test/tools/config_load_check/config_load_check_tool

运行 config_load_check_tool

bazel-bin/test/tools/config_load_check/config_load_check_tool PATH
# 该工具将以递归方式遍历文件目录结构,并对每个文件运行配置测试。
# 请记住,该工具将尝试所加载路径中的所有文件
# 如果存在JSON文件格式不正确或不符合Envoy JSON模式的配置文件,则该工具将以状态EXIT_FAILURE退出。
# 如果该工具成功加载所有找到的配置文件,它将以状态EXIT_SUCCESS退出。

(2) 路由表检查工具

路由表检查工具 检查路由器返回的路由参数是否与预期相符。
该工具还可用于检查重定向路径,路径重写或主机重写是否与预期相符。

构建 router_check_tool

bazel build //test/tools/router_check:router_check_tool
# 构建成功后,可执行文件位于 bazel-bin/test/tools/router_check/router_check_tool
# 由于网络原因, 编译总是不成功

运行 router_check_tool

bazel-bin/test/tools/router_check/router_check_tool router_config.json tool_config.json --details

# 如果测试失败,则该工具将以状态 EXIT_FAILURE 退出。
# 目前不支持 valid runtime values , 这在将来可能会支持

(3) Schema Validator check tool

Schema Validator check tool 验证传入的JSON是否符合配置规范

构建 schema_validator_tool

bazel build //test/tools/schema_validator:schema_validator_tool
# 构建成功后,可执行文件位于 bazel-bin/test/tools/schema_validator/schema_validator_tool

运行 router_check_tool

bazel-bin/test/tools/schema_validator/schema_validator_tool --schema-type SCHEMA_TYPE --json-path PATH

# 如果测试失败,则该工具将以状态 EXIT_FAILURE 退出。否则以 EXIT_SUCCESS 退出。

二、 使用

1、 快速开始

使用Envoy的最简单的方式就是使用预编译的 Docker 镜像.
例如以 envoyproxy/envoy:latest 镜像(为ubuntu系统准备,可惜我用的是CentOS7)为基础镜像,
然后 加入自己的配置文件(json或yaml格式), 制作你自己的镜像,如下所示:
( 配置文件后面再介绍,这里略过 )

# 生成Dockerfile
mkdir customEnvoyImage
cat >> customEnvoyImage/Dockerfile <

三、 参考配置 (Reference Configuration)

1、 使用场景

源代码发布包括了三个主要 Envoy部署类型 中的每一个的一组示例配置模板:

  • Service to service

  • Front proxy

  • Double proxy

(1) Service to service

这是最简单的部署场景
Service to service 表示使用 Envoy 作为面向服务架构(SOA)内部的所有流量的通信总线。
在这种场景下,Envoy 公开了几个 listeners, 用于 local origin traffic 和 service to service traffic.

Service to service egress(出口) listener

这是应用程序与基础结构中的其他服务对话所使用的端口。
例如,http://localhost:9001

HTTP和gRPC请求使用 HTTP/1.1 host header 或 HTTP/2 :authority header来指示请求指向哪个远程群集。
根据配置中的详细信息,Envoy处理服务发现,负载平衡,速率限制等。
服务只需要了解 local Envoy ,不需要关心网络拓扑结构,无论他们是在开发还是在生产中运行。

此侦听器支持 HTTP/1.1 或 HTTP/2 ,具体取决于应用程序的 capabilities 。

Service to service ingress(入口) listener

这是 remote Envoys 要与 local Envoy 交谈时使用的端口
例如 http://localhost:9211
传入请求将在配置的端口上路由到本地服务
根据应用程序或负载平衡需求(例如,如果服务需要HTTP端口和gRPC端口),可能会涉及多个应用程序端口
local Envoy 根据需要执行缓冲,断路等

默认对所有 Envoy to Envoy communication 的通信使用 HTTP/2 , 无论应用程序在从 local Envoy 出去时使用的是 HTTP/1.1 or HTTP/2。
HTTP/2 通过长期连接和显式重置通知提供更好的性能。

Optional external service egress listeners

一般而言,本地服务与每个想要通话的外部服务都需要一个明确的出口端口。
这是因为一些外部服务SDK不轻易支持覆盖 host header 以允许标准HTTP反向代理行为
例如: http://localhost:9250 可能会被分配给发往DynamoDB的连接
为了保持一致, 我们建议为 所有外部服务 使用 本地端口路由,而不是使用 主机路由 和 其他专用本地端口路由。

集成服务发现

建议为所有的cluster lookups 使用外部的服务发现
这为Envoy提供了执行负载平衡,统计收集等时可能使用的最详细信息。

(2) Front proxy

就是在 Service to service 的基础上, 专门为外部访问单独部署了一个 Enovy 提供反向代理, 类似于Nginx提供的功能
它有如下 Features:

  • Terminates TLS.
  • Supports both HTTP/1.1 and HTTP/2.
  • Full HTTP L7 routing support.
  • 使用标准的 ingress port 并使用服务发现进行host lookup. 它只是没有与自己搭配的服务. 这意味着它和其他的Envoy的运行方式相同,并且可以发出相同的统计数据

(3) Double proxy

在 Front proxy 的基础上,在加一层,就是多个 Envoy集群 之间进行代理,叫什么双向代理,没看太明白

2、 配置生成器(Configuration generator)

Envoy的配置可能会变得相对复杂。
Lyft 中, 我们使用 jinja 模版来使配置更易于创建和管理。
在源代码发行版中,我们包含了 配置生成器 的一个版本, 它大致接近我们在 Lyft 中使用的配置生成器。
我们还为以上三种部署场景( Service to serviceFront proxyDouble proxy )各自提供了 示例配置模版。

  • Generator script: configs/configgen.py

  • Service to service template: configs/envoy_service_to_service.template.json

  • Front proxy template: configs/envoy_front_proxy.template.json

  • Double proxy template: configs/envoy_double_proxy.template.json

要想生成配置示例,执行下面的命令(在 envoy repo的根目录处执行):
下面的命令会产出3个完全展开的配置, 配置内容是根据 configs/configgen.py 中定义的一些变量生成的。
参看 configs/configgen.py 中的注释获取详细信息

mkdir -p generated/configs
bazel build //configs:example_configs
tar xvf $PWD/bazel-genfiles/configs/example_configs.tar -C generated/configs

四、 配置参考 (Configuration Reference)

1、 Overview (v1 API)

注意: v1 configuration/API 目前仍可用,但已经被列在 deprecated schedule 中了
所以, 不介绍它了

2、 Overview (v2 API)

Envoy v2 API 使用 proto3 Protocol Buffers 定义.

查看 xDS protocol description 详细了解 Envoy 和 management server 之间的 v2 message 交互。

2.1 Bootstrap Configuration

要使用 v2 API,需要提供一个 bootstrap configuration file
这个配置文件提供了静态的 server Configuration ,并配置 Envoy 访问动态配置。
使用 -c 命令行参数提供该配置文件:

./envoy -c .{json,yaml,pb,pb_text} --v2-config-only
# 文件的后缀名表明了配置文件使用的 v2 config 形式.
# --v2-config-only 不是必须的,它表示强制使用 v2 config 格式解析文件

一个关键的概念是 静态资源和动态资源。
资源(例如 Listener 或 Cluster) 可以静态设置,也可以是动态地通过xDS service(例如 LDS、CDS)设置

2.2 例子

下面的例子使用 yaml 格式,其内容是 代理 HTTP 从 0.0.0.0:10000 to 10.0.209.147:80

静态配置

admin:
  access_log_path: /tmp/envoy_admin_access.log
  address:
    socket_address: { address: 127.0.0.1, port_value: 9901 }

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 10000 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route: { cluster: some_service }
          http_filters:
          - name: envoy.router
  clusters:
  - name: some_service
    connect_timeout: 0.25s
    type: STATIC
    lb_policy: ROUND_ROBIN
    hosts: [{ socket_address: { address: 10.0.209.147, port_value: 80 }}]

Mostly static with dynamic EDS

admin:
  access_log_path: /tmp/envoy_admin_access.log
  address:
    socket_address: { address: 127.0.0.1, port_value: 9901 }

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 10000 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route: { cluster: some_service }
          http_filters:
          - name: envoy.router
  clusters:
  - name: some_service
    connect_timeout: 0.25s
    lb_policy: ROUND_ROBIN
    type: EDS
    eds_cluster_config:
      eds_config:
        api_config_source:
          api_type: GRPC
          cluster_names: [xds_cluster]
  - name: xds_cluster
    connect_timeout: 0.25s
    type: STATIC
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    hosts: [{ socket_address: { address: 127.0.0.3, port_value: 5678 }}]

上面的例子中, EDS management server (127.0.0.3:5678) 会返回一个 DiscoveryResponse 的protoco encoding, DiscoveryResponse的内容是:

version_info: "0"
resources:
- "@type": type.googleapis.com/envoy.api.v2.ClusterLoadAssignment
  cluster_name: some_service
  endpoints:
  - lb_endpoints:
    - endpoint:
        address:
          socket_address:
            address: 10.0.209.147
            port_value: 80

动态配置

admin:
  access_log_path: /tmp/envoy_admin_access.log
  address:
    socket_address: { address: 127.0.0.1, port_value: 9901 }

dynamic_resources:
  lds_config:
    api_config_source:
      api_type: GRPC
      cluster_names: [xds_cluster]
  cds_config:
    api_config_source:
      api_type: GRPC
      cluster_names: [xds_cluster]

static_resources:
  clusters:
  - name: xds_cluster
    connect_timeout: 0.25s
    type: STATIC
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    hosts: [{ socket_address: { address: 127.0.0.3, port_value: 5678 }}]

上面的例子中,
management server (127.0.0.3:5678) 响应 LDS 请求会返回:

version_info: "0"
resources:
- "@type": type.googleapis.com/envoy.api.v2.Listener
  name: listener_0
  address:
    socket_address:
      address: 127.0.0.1
      port_value: 10000
  filter_chains:
  - filters:
    - name: envoy.http_connection_manager
      config:
        stat_prefix: ingress_http
        codec_type: AUTO
        rds:
          route_config_name: local_route
          config_source:
            api_config_source:
              api_type: GRPC
              cluster_names: [xds_cluster]
        http_filters:
        - name: envoy.router

management server (127.0.0.3:5678) 响应 RDS 请求会返回:

version_info: "0"
resources:
- "@type": type.googleapis.com/envoy.api.v2.RouteConfiguration
  name: local_route
  virtual_hosts:
  - name: local_service
    domains: ["*"]
    routes:
    - match: { prefix: "/" }
      route: { cluster: some_service }

management server (127.0.0.3:5678) 响应 CDS 请求会返回:

version_info: "0"
resources:
- "@type": type.googleapis.com/envoy.api.v2.Cluster
  name: some_service
  connect_timeout: 0.25s
  lb_policy: ROUND_ROBIN
  type: EDS
  eds_cluster_config:
    eds_config:
      api_config_source:
        api_type: GRPC
        cluster_names: [xds_cluster]

management server (127.0.0.3:5678) 响应 EDS 请求会返回:

version_info: "0"
resources:
- "@type": type.googleapis.com/envoy.api.v2.ClusterLoadAssignment
  cluster_name: some_service
  endpoints:
  - lb_endpoints:
    - endpoint:
        address:
          socket_address:
            address: 10.0.209.147
            port_value: 80

2.3 Management server

一个 v2 xDS management server 应该实现下面的 endpoints (为了服务 gRPC 和/或 REST).
在 流式 gRPC 和 REST-JSON 情形中, server 接收一个 DiscoveryRequest ,并返回一个 DiscoveryResponse, 遵循 xDS protocol

(1) gRPC streaming endpoints

(a) cds endpoint

POST /envoy.api.v2.ClusterDiscoveryService/StreamClusters

查看 cds.proto

Envoy作为一个client,访问该endpoint,在 cds_config 中配置:

dynamic_resources:
  cds_config:
    api_config_source:
      api_type: GRPC
      cluster_names: [some_xds_cluster]

(b) eds endpoint

POST /envoy.api.v2.ClusterDiscoveryService/StreamEndpoints

查看 eds.proto

Envoy作为一个client,访问该endpoint,在 eds_config 中配置:

static_resources:
  clusters:
  - name: some_service
    eds_cluster_config:
      eds_config:
        api_config_source:
          api_type: GRPC
          cluster_names: [xds_cluster]
  - name: xds_cluster
    connect_timeout: 0.25s
    type: STATIC
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    hosts: [{ socket_address: { address: 127.0.0.3, port_value: 5678 }}]

(c) lds endpoint

POST /envoy.api.v2.ClusterDiscoveryService/StreamListeners

查看 lds.proto

Envoy作为一个client,访问该endpoint,在 lds_config 中配置:

dynamic_resources:
  lds_config:
    api_config_source:
      api_type: GRPC
      cluster_names: [some_xds_cluster]

(d) rds endpoint

POST /envoy.api.v2.ClusterDiscoveryService/StreamRoutes

查看 rds.proto

Envoy作为一个client,访问该endpoint,在 rds 中配置:

static_resources:
  listeners:
  - name: listener_0
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          stat_prefix: ingress_http
          codec_type: AUTO
          rds:
            route_config_name: local_route
            config_source:
              api_config_source:
                api_type: GRPC
                cluster_names: [xds_cluster]
          http_filters:
          - name: envoy.router
 
  clusters:
  - name: xds_cluster
    connect_timeout: 0.25s
    type: STATIC
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    hosts: [{ socket_address: { address: 127.0.0.3, port_value: 5678 }}]

(2) REST endpoints

除了API和 gRPC streaming endpoints 不同之外,
在 Envoy 中的只是将 api_type 设置为 REST

(a) cds endpoint

POST /v2/discovery:clusters

(b) eds endpoint

POST /v2/discovery:endpoints

(c) lds endpoint

POST /v2/discovery:listeners

(d) rds endpoint

POST /v2/discovery:routes

2.4 Aggregated Discovery Service(ADS)

ADS 仅适用于 gRPC streaming(不适用于 REST).
其 gRPC endpoint 是
POST /envoy.api.v2.AggregatedDiscoveryService/StreamAggregatedResources

在Envoy中的配置如下:

dynamic_resources:
  ads_config:
    api_type: GRPC
    cluster_names: [some_ads_cluster]

当设置了 ads_config 之后, 上面的示例中的配置都可以是这个 ADS channel
例如, LDS config 可以被更改为

lds_config: {ads: {}}

3、 Listeners

每个单独的 listener 的配置的 v2 API 格式如下:

{
  "name": "...",
  "address": "{...}",
  "filter_chains": [],
  "per_connection_buffer_limit_bytes": "{...}",
  "metadata": "{...}",
  "drain_type": "...",
  "listener_filters": []
}

listener_filters 用于提供一个机会,来操作和扩充 connection metadata.
这些过滤器在 filter_chains 之前运行。

listener 接收一个 socket 之后执行 listener_filters ,然后 connection 被创建。

listener_filtersname 必须是内置的 filter , 可用的 filters 有:

  • envoy.listener.original_dst

4、 Network Filters

除了可以配置 足够大的 HTTP connection manager 之外, Envoy还有如下的内置的 network filters

4.1 Client TLS authentication

filter.name = envoy.client_ssl_auth

4.2 Echo

filter.name = envoy.echo

4.3 Mango proxy

filter.name = envoy.mango_proxy

4.4 Rate limit

filter.name = envoy.ratelimit
v2 API 格式如下:

{
  "stat_prefix": "...",
  "domain": "...",
  "descriptors": [],
  "timeout": "{...}"
}

domain 必须提供, 表示要限制rate的服务的domain
timeout 表示要限制的服务RPC的超时毫秒数,默认为 20ms
descriptors 表示决定最终的rate limit key和允许的limit
例子:
下面的设置表示 限制所有 未认证的、来自 10.0.0.1 的 traffic

["authenticated": "false"], ["remote_address": "10.0.0.1"]

下面的设置表示 限制所有 未认证的、访问 /foo/bar 的 traffic

["authenticated": "false"], ["path": "/foo/bar"]

4.5 Redis Proxy

filter.name = envoy.redis_proxy

v2 API 格式如下:

{
  "stat_prefix": "...",
  "cluster": "...",
  "settings": "{...}"
}

settings 必须提供,用于设置 connection pool 的网络设置
其格式如下:

{
  "op_timeout": "{...}"
}

4.6 TCP proxy

filter.name = envoy.tcp_proxy

v2 API 格式如下:

{
  "stat_prefix": "...",
  "cluster": "...",
  "metadata_match": "{...}",
  "idle_timeout": "{...}",
  "access_log": [],
  "deprecated_v1": "{...}",
  "max_connect_attempts": "{...}"
}

5、 HTTP connection manager

filter.name = envoy.http_connection_manager

5.1 路由匹配

当 envoy 匹配路由时,她使用如下的步骤:
(1) 匹配请求头中的 host:authority 信息匹配到一个 virtual host
(2) 按顺序检查 virtual host 中的每个 route entry ,如果匹配到,就使用这个 route ,然后不再检查后面的 route
(3) 另外,还按顺序检查 virtual host 中的每个 virtual cluster。 如果匹配到,就使用这个 virtual cluster,然后不再检查后面的 virtual cluster

5.2 Traffic Shifting/Splitting(转移/拆分)

virtual host 中的route可以将请求 路由到 2+ 个 upstream clusters。
这一般有2个用处:
(1) 版本升级: 请求被逐渐从cluster A 转义到 cluster B
(2) A/B testing 或 multivariate(多变量) testing: 相同服务的多个版本同时被测试.

5.3 HTTP header manipulation(操作)

5.4 HTTP header sanitizing(消毒)

出于安全方面的原因

5.5 Runtime设置

http_connection_manager 的 v2 API 格式如下:

{
  "codec_type": "...",
  "stat_prefix": "...",
  "rds": "{...}",
  "route_config": "{...}",
  "http_filters": [],
  "add_user_agent": "{...}",
  "tracing": "{...}",
  "http_protocol_options": "{...}",
  "http2_protocol_options": "{...}",
  "server_name": "...",
  "idle_timeout": "{...}",
  "drain_timeout": "{...}",
  "access_log": [],
  "use_remote_address": "{...}",
  "xff_num_trusted_hops": "...",
  "generate_request_id": "{...}",
  "forward_client_cert_details": "...",
  "set_current_client_cert_details": "{...}",
  "proxy_100_continue": "...",
  "represent_ipv4_remote_address_as_ipv4_mapped_ipv6": "..."
}

codec_type 可选值有 AUTO、HTTP1、HTTP2
rds 是配置 resource discovery service 内容
route_config 是配置路由部分
...

route_config 的 API 格式:

{
  "name": "...",
  "virtual_hosts": [],
  "internal_only_headers": [],
  "response_headers_to_add": [],
  "response_headers_to_remove": [],
  "request_headers_to_add": [],
  "validate_clusters": "{...}"
}

virtual_hosts 的 API 格式:

{
  "name": "...",
  "domains": [],
  "routes": [],
  "require_tls": "...",
  "virtual_clusters": [],
  "rate_limits": [],
  "request_headers_to_add": [],
  "response_headers_to_add": [],
  "response_headers_to_remove": [],
  "cors": "{...}"
}

6、 HTTP Filters

6.1 Buffer

6.2 CORS

6.3 DynamoDB

6.4 Fault Injection

6.5 gRPC HTTP/1.1 bridge

6.6 gRPC-JSON transcoder

6.7 gRPC-Web

6.8 Gzip

6.9 Health check

6.10 IP Tagging

6.11 Lua

6.12 Rate limit

6.13 Router

在 出口/请求 路径 和 入口/响应 路径 中,router 会消费和设置很多 HTTP 头。

  • x-envoy-expected-rq-timeout-ms

  • x-envoy-max-retries

  • x-envoy-retry-on

  • x-envoy-retry-grpc-on

  • x-envoy-upstream-alt-stat-name

  • x-envoy-upstream-canary

  • x-envoy-upstream-rq-timeout-alt-response

  • x-envoy-upstream-rq-timeout-ms

  • x-envoy-upstream-rq-per-try-timeout-ms

  • x-envoy-upstream-service-time

  • x-envoy-original-path

  • x-envoy-immediate-health-check-fail

  • x-envoy-overloaded

  • x-envoy-decorator-operation

6.14 Squash

7、 Cluster manager

7.1 Runtime配置

7.2 Health checking

每个 upstream cluster 都可以配置 Active health checking(主动健康检查)

Envoy 支持三种不同类型的主动健康检查,每种类型的检查都有 check interval, failures required before marking a host unhealthy, successes required before marking a host healthy 等等配置内容

  • HTTP : Envoy 会发送 HTTP 请求到 upstream 主机。它期望host返回 200 response code 表示健康。 upstream 如果想“立即”通知 downstream 主机不要在转发流量给它的话,可以返回 503 response code

  • L3/L4 : Envoy 会发送可配置的byte buffer 到 upstream 主机。它期望host echo byte buffer back 表示健康。 Envoy 也支持 connect only L3/L4 health checking

  • Redis : Envoy 会发送 Redis PING 命令,并期望一个 PONG 回应。 upstream 回应其他的任何内容都会立即导致检查失败。 另外,Envoy 可以检查某个指定的key是否 EXISTS ,如果key不存在,则健康检查通过。

Passive health checking

Envoy 通过使用 outlier detection(异常值检测) 还支持 passive health checking

outlier detection 和 ejection(弹出) 是动态决定upstream cluster 中的某些主机出现异常并将其从 health load balancing 组中移除的过程。

这些异常性能指标可能是 consecutive failures(连续失败),temporal success rate(暂时成功率), temporal latency(暂时延迟)等

outlier detection 是 passive health checking 的一种形式。

Active health checking 和 Passive health checking 可以同时启用,也可以单独启用。
通常, 它们一起组成全面的健康检查解决方案。

(1) Ejection algorithm

基于 outlier detection 的类型,ejection 或者以 inline(例如在连续5xx的情况下)或以指定的间隔(例如在 periodic success rate 的情况下)运行。

Ejection 算法的工作原理如下:
(i) host 被确定为异常
(ii) Envoy 检查被 ejected hosts的数量在允许的 threshold (通过 outlier_detection.max_ejection_percent 设置)。如果已经超过了 threshold,那么host将不会被 ejected
(iii) host 会被弹出数毫秒。 被 ejected(弹出) 意味着主机会被标记为unhealthy,而且不会在load balancing中使用,除非load balancer处于panic(恐慌)状态。 host被弹出的毫秒数为 outlier_detection.base_ejection_time_ms * (被弹出的次数) 。 这样 host 如果持续失败,被弹出的时间会越来越长。
(iv) 弹出时间结束后,被弹出的 host 会自动重新投入使用。

(2) Dection types(检测类型)

  • Consecutive 5xx
    如果 upstream host 连续返回一定数量(通过 outlier_detection.consecutive_5xx 设置)的 5xx 返回码,它会被 ejected

  • Consecutive Gateway Failure
    如果 upstream host 连续返回一定数量(通过 outlier_detection.consecutive_gateway_failure 设置)的 “gateway errors” (502, 503 or 504 status code),它会被 ejected

  • Success Rate
    Success Rate 检测基于 cluster 内每个host的聚合的 success rate 数据。
    然后以给定的interval 基于异常统计信息弹出主机。
    如果 host 在 aggregation interval 内的请求量小于outlier_detection.success_rate_request_volume值,则不会被计算。
    此外,如果在 aggregation interval 内 cluster 中的 hosts 数量 小于outlier_detection.success_rate_minimum_hosts值,则不会对 cluster 执行检测

(3) Ejection event logging

Envoy可以选择生成 outlier ejection events 的日志。
(在 bootstrap 中的 cluster_manager 中设置 outlier_detection 的 event_log_path)

这在日常操作中非常有用,因为全局统计信息不能提供关于哪些主机正在被弹出的信息以及出于何种原因被弹出。
日志使用JSON格式,每行一个json对象,格式为:

{
  "time": "...",
  "secs_since_last_action": "...",
  "cluster": "...",
  "upstream_url": "...",
  "action": "...",
  "type": "...",
  "num_ejections": "...",
  "enforced": "...",
  "host_success_rate": "...",
  "cluster_success_rate_average": "...",
  "cluster_success_rate_ejection_threshold": "..."
}

Connection pool interactions

HTTP health checking filter

当你在部署的Envoy网格中cluster之间配置了 Active health checking , 这会造成大量的 健康检查流量。

Envoy包含一个 HTTP health checking filter ,可以安装在已配置的HTTP listener 中。
这个过滤器有几种不同的操作模式:
(1) No pass through : 在这种模式下,健康检查请求不会被传递给本地服务。Envoy会基于当前server的 draining state 直接返回 200 或 503 返回码
(2) No pass through, computed from upstream cluster health: 在这种模式下,除了基于当前server的 draining state 外, 还会判断一个或多个upstream cluster 中的健康server的百分比是否打标,以确定是返回 200 还是 503
(3) Pass through : 健康检查请求 会被传递给本地服务
(4) Pass through with caching : 健康检查请求 会被传递给本地服务, 然后 Envoy 会缓存本地服务响应的返回码 一段时间

Active health checking fast failure

Active health checking 和 Passive health checking 共同使用时,一般会使用一个长的健康检查间隔以避免大量的健康检查流量。
此时,我们仍然需要快速的收回upstream host,也就是让其快速失败。
为了支持这个特性, router filter 会在响应在返回头中的 x-envoy-immediate-health-check-fail 。
如果 upstream host 在返回头中设置了该项,Envoy会立即标记此host为failed。
HTTP health checking filter会自动设置这个header(如果Envoy已经被标记为failed)。

Health check identity

只验证 upstream host 是否响应特定的健康检查url并不一定意味着其是有效的。
例如: ip:port 消失后 然后被另外一种类型的主机使用。

解决此问题的一个办法是针对每种服务类型都有不同的HTTP健康检查URL。
该方法的缺点是整体配置变得更加复杂,因为每个健康检查URL都是完全自定义的。

Envoy HTTP health checker 支持 service_name 选项。
如果设置了此选项, health checker 会将x-envoy-upstream-healthchecked-cluster响应标头的值与service_name进行比较。如果值不匹配,则健康检查不通过。
upstream health check filter 将x-envoy-upstream-healthchecked-cluster附加到响应标头。
附加值由 --service-cluster 命令行选项确定。

7.3 Circuit breaking(断路,熔断)

Circuit breaking 是分布式系统中的一个关键组件。
几乎总是应该快速失败并尽快向 downstream 施加反压。
Envoy网格的主要优点之一是,Envoy自动在网络级别强制实现断路限制。
Envoy支持各种类型的 fully distributed (not coordinated) circuit breaking:

(1) Cluster maximum connections : Envoy 为每个 upstream cluster 创建的所有的连接的最大数量。
在实际使用中,这只对 HTTP/1.1 有效, 因为 HTTP/2 为每个 host 只创建一个连接。

(2) Cluster maximum pending requests : 等待 connection pool 中的 connection 的请求队列的最大数量。
在实际使用中,这只对 HTTP/1.1 有效, 因为 HTTP/2 的 connection pool 从不 queue requests 。
HTTP/2 的请求会立即复用。
如果这个 circuit breaker 溢出了,cluster 的 upstream_rq_pending_overflow counter 会递增。

(3) Cluster maximum requests : 在任意时刻, cluster 中的所有 hosts 可以处理的请求的最大数量。
在实际使用中,这只对 HTTP/2 有效,因为 HTTP/1.1 cluster 使用 maximum connections circuit breaker 控制。
如果这个 circuit breaker 溢出了,cluster 的 upstream_rq_pending_overflow counter 会递增。

(4) Cluster maximum active retries : 在任意时刻, cluster 中的所有 hosts 执行重试的最大数量。
一般来说,我们推荐进行 circuit breaking retries ,以便允许零星故障的retries,而不会引起整体的 retry volume 进而爆炸为大规模的级联故障。
如果这个 circuit breaker 溢出了,cluster 的 upstream_rq_retry_overflow counter 会递增。

每种 circuit breaking limit 都可以基于 upstream cluster 和 priority 配置和追踪。
这允许分布式系统的不同组件独立调整,并且有不同的limits

注意: 如果发生 circuit breaking ,Envoy的 router filter 会在 HTTP 请求的返回头中增加 x-envoy-overloaded 头

API配置格式

{
  "thresholds": [
    {
      "priority": "...",
      "max_connections": "{...}",
      "max_pending_requests": "{...}",
      "max_requests": "{...}",
      "max_retries": "{...}"
    }
  ]
}

priority 默认为 DEFAULT, 可设置值为 DEFAULT / HIGH
max_connections 默认为 1024
max_pending_requests 默认为 1024
max_requests 默认为 1024
max_retries 默认为 3,表示每个cluster允许的同时retries的最大数量

Runtime

所有的 circuit breaking 设置都允许 运行时配置。
使用 circuit_breakers... 这样的 scheme

8、 Access logging

access logs 是 http_connection_manager 或 tcp_proxy 的配置的一部分

9、 Rate limit service

10、 Runtime

运行时配置 是指定本地文件系统中的包含 reloadable 配置元素的位置。
如果未配置 runtime,那么会使用 "null" provider,他使用编译到代码中的默认值。

配置格式

{
  "symlink_root": "...",
  "subdirectory": "...",
  "override_subdirectory": "..."
}

runtime key 中的 . 表示文件树中的一个目录,并且最后一个元素表示具体的文件,文件的名称是key,文件的内容是 value

override_subdirectory 与命令行中提供的 --service-cluster 选项一起工作.
假设命令行选项是 --service-cluster my-cluster , 那么 envoy 如果要查找 health_check.min_interval key的值,它会优先在下面的路径查找文件:
${symlink_root}/${override_subdirectory}/my-cluster/health_check/min_interval

如果找到了文件,它会覆盖之前找到的值。

文件中可以使用 # 作为行开头表示注释

11、 Statistics

12、 Route table check tool


五、 Operation and administration

1、 Command line options

-c --config-path 指定配置文件路径,必须提供
--v2-config-only 强制使用 v2 API 格式解析文件
--mode : 模式: serve(默认值) 或 validate
--admin-address-path 指定将 admin 的地址和端口 写入到哪个文件中
--local-address-ip-version : v4(默认) 或 v6
--concurrency 指定 worker threads 的数量,默认为硬件上的硬件线程数
--service-cluster 

...

2、 Hot restart Python wrapper

Envoy 具有“热”或“实时”重启的能力。
这意味着Envoy可以完全重新加载自己(代码和配置)而不会丢失任何连接。

但是,在很多情况下,用户会希望使用标准进程管理器,例如 monitrunit等。
我们提供 /restarter/hot-restarter.py 来使这个过程简单明了。

使用 restarter

hot-restarter.py start_envoy.sh

start_envoy.sh 大概的内容是:

#!/bin/bash

ulimit -n {{ pillar.get('envoy_max_open_files', '102400') }}
exec /usr/sbin/envoy -c /etc/envoy/envoy.cfg \
--restart-epoch $RESTART_EPOCH \
--service-cluster {{ grains['cluster_name'] }} \
--service-node {{ grains['service_node'] }} \
--service-zone {{ grains.get('ec2_availability-zone', 'unknown') }}

restarter 会处理如下的信号:

  • SIGTERM : 会干净的终止所有的子进程然后退出
  • SIGHUP: 会 hot restart
  • SIGCHLD: 如果任意的子进程非预期退出,重启脚本会关闭所有然后退出,以避免进入非预期的状态。然后需要重新启动 restarter脚本 来再次启动 Envoy
  • SIGUSR1: 会转发该信息到 Envoy 让其重新打开所有的 access logs。用于 atomic move and reopen log rotation

3、 Administration interface

envoy 会暴露一个本地管理界面,用于查询和修改server

配置格式

{
  "access_log_path": "...",
  "profile_path": "...",
  "address": "{...}"
}

access_log_path 指定访问 administration server 的日志要写入的文件,默认为 /dev/null

4、 Statistics overview

Envoy会基于 server 的配置输出很多统计信息。
可以通过 administration interface 的 GET /stats 获取
并且一般会发送给一个 statsd cluster

5、 Runtime

6、 File system flags

通常 运行时配置 文件名称为 key ,值为value,
但是某些设置只有一个flag,那么只要文件存在就表示要设置该flag
目前支持的 flag 有

  • drain

五、 扩展 Envoy

how to add a network filter and structure the repository and build dependencies


六、 FAQ

1、 我设置了 health checking。 当某些 hosts fail 时,Envoy 仍然路由到它们。这是为什么?

其实这是一个 feature .
当负载均衡时, panic threshold 用于 当 upstream hosts 大量的产生健康检查失败时 阻止级联失败。
panic threshold 默认是50%

 



作者:坚持到底v2
链接:https://www.jianshu.com/p/0a1f67b42fdb
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

你可能感兴趣的:(service mesh envoy)