专栏首页k8s技术圈Envoy 的健康检查

Envoy 的健康检查

本章节我们将学习如何添加一个健康检查,来检查集群中的服务是否可用于接收流量。启用健康检查后,如果服务崩溃了,则 Envoy 将停止发送流量。

1. 代理配置

首先创建一个 Envoy 配置文件 envoy.yaml,配置将任何域名的请求都代理到 172.17.0.3172.17.0.4 这两个上游服务去。完整的配置如下所示:

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
                - "*"
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: targetCluster
          http_filters:
          - name: envoy.router
  clusters:
  - name: targetCluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    hosts: [
      { socket_address: { address: 172.17.0.3, port_value: 80 }},
      { socket_address: { address: 172.17.0.4, port_value: 80 }}
    ]

假设目前 172.17.0.3 这个上游服务出现了故障,现在的 Envoy 代理还是会继续向该服务转发流量过来的,这样当用户访问服务的时候就会遇到不可用的情况。对于这种情况我们更希望的是 Envoy 能够检测到服务不可用的时候自动将其从节点中移除掉,这其实就可以通过向集群中添加健康检查来完成。

2. 添加健康检查

健康检查可以添加到 Envoy 的集群配置中,如下所示的配置将在定义的每个节点内使用 /health 端点来进行健康检查,Envoy 会根据端点返回的 HTTP 状态来确定其是否健康。

health_checks:
- timeout: 1s
  interval: 10s
  interval_jitter: 1s
  unhealthy_threshold: 6
  healthy_threshold: 1
  http_health_check:
    path: "/health"

这里我们简单对上面配置的健康检查的关键字段进行下说明:

  • interval:执行一次健康检查的时间间隔
  • unhealthy_threshold:将主机标记为不健康状态之前需要进行的不健康状态检查数量(相当于就是检测到几次不健康就认为是不健康的)
  • healthy_threshold:将主机标记为健康状态之前需要进行的健康状态检查数量(相当于就是检测到几次健康就认为是健康的)
  • http_health_check.path:用于健康检查请求的路径

关于健康检查的更多字段介绍可以查看官方的文档说明:https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/core/health_check.proto

3. 启动代理

添加了健康检查之后,Envoy 将检查集群中定义的每个节点的运行状况。同样使用如下所示的命令启动 Envoy 代理:

$ docker run -d --name proxy1 -p 80:8080 -v $(pwd)/manifests:/etc/envoy envoyproxy/envoy:latest

然后启动两个节点,都处于正常运行状态:

$ docker run -d cnych/docker-http-server:healthy; docker run -d cnych/docker-http-server:healthy;

启动完成后,我们可以向 Envoy 发送请求,正常都可以从上面的两个上游服务中返回正常的请求:

$ curl localhost -i
HTTP/1.1 200 OK
date: Wed, 15 Apr 2020 04:13:01 GMT
content-length: 63
content-type: text/html; charset=utf-8
x-envoy-upstream-service-time: 0
server: envoy

<h1>A healthy request was processed by host: b6336e79951d</h1>
$ curl localhost -i
HTTP/1.1 200 OK
date: Wed, 15 Apr 2020 04:13:02 GMT
content-length: 63
content-type: text/html; charset=utf-8
x-envoy-upstream-service-time: 0
server: envoy

<h1>A healthy request was processed by host: 9a4c07cc4306</h1>

4. 测试

接下来我们来测试下 Envoy 是如何处理不正常的节点的。在一个独立的命令行终端中,启动一个循环来发送请求,可以让我们来观察状态变化:

$ while true; do curl localhost; sleep .5; done
......

然后使用如下命令,我们可以来确定哪个 Docker 容器的 IP 为 172.17.0.3,然后将这个节点变成不健康的,然后 Envoy 就会自动将其从负载均衡中移除掉。

$ docker ps -q | xargs -n 1 docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}} {{ .Config.Hostname }}' | sed 's/ \// /'
172.17.0.4 b6336e79951d
172.17.0.3 9a4c07cc4306
172.17.0.2 6928df882c4f

要让该一个节点变成不健康的状态,我们可以直接请求 unhealthy 的端点:

$ curl 172.18.0.3/unhealthy

这个时候可以看到另外一个终端中循环请求的日志信息中就出现了 unhealthy 的相关信息:

......
<h1>A unhealthy request was processed by host: 9a4c07cc4306</h1>
<h1>A unhealthy request was processed by host: 9a4c07cc4306</h1>
<h1>A healthy request was processed by host: b6336e79951d</h1>
<h1>A unhealthy request was processed by host: 9a4c07cc4306</h1>
......

这个时候访问该容器就会返回 500 状态码了:

$ curl 172.18.0.3 -i
HTTP/1.1 500 Internal Server Error
Date: Wed, 15 Apr 2020 04:23:59 GMT
Content-Length: 65
Content-Type: text/html; charset=utf-8

<h1>A unhealthy request was processed by host: 9a4c07cc4306</h1>

在这段时间内,Envoy会将请求发送到健康检查的端点。如果健康检查的端点发生了故障,它将继续向该服务发送流量,直到达到 unhealthy_threshold 这么多次不健康的请求,此时,Envoy 将从负载均衡器中将其删除。这个时候可以看到另外一个终端中循环请求的日志信息中就只有一个容器的信息了:

......
<h1>A healthy request was processed by host: b6336e79951d</h1>
<h1>A healthy request was processed by host: b6336e79951d</h1>
<h1>A healthy request was processed by host: b6336e79951d</h1>
<h1>A healthy request was processed by host: b6336e79951d</h1>
......

与此同时,Envoy 还会继续检查健康状态的端点,来查看它是否再次变得可用了,一旦可用,它将又会被添加回到 Envoy 的上游服务器集群中去。

我们可以访问下上面不健康容器的 healthy 端点让其变成正常运行状态:

$ curl 172.17.0.3/healthy

我们健康检查的间隔是10s,healthy_threshold 阈值是1,所以检测到成功后 Envoy 就会将该容器再次添加回来。这个时候可以看到另外一个终端中循环请求的日志信息中就又出现了两个容器的信息:

......
<h1>A healthy request was processed by host: 9a4c07cc4306</h1>
<h1>A healthy request was processed by host: 9a4c07cc4306</h1>
<h1>A healthy request was processed by host: b6336e79951d</h1>
<h1>A healthy request was processed by host: b6336e79951d</h1>
......

接下来我们再来测试下所有服务均不可用时发生的情况。目前已经有两个运行正常的上游服务器,Envoy 代理会在它们之间进行负载均衡。

和上面方法一样,对两个上游服务访问 unhealthy 端点,这样就可以将两个服务变成不健康的状态:

$ curl 172.18.0.3/unhealthy
$ curl 172.18.0.4/unhealthy

现在两个上游服务都已经不健康了,所以当我们请求 Envoy 时,将得到如下所示的信息:

$ curl localhost -i
HTTP/1.1 500 Internal Server Error
date: Wed, 15 Apr 2020 06:19:01 GMT
content-length: 65
content-type: text/html; charset=utf-8
x-envoy-upstream-service-time: 0
server: envoy

<h1>A unhealthy request was processed by host: b6336e79951d</h1>

5. 被动健康检查

和前面的主动健康检查不同,被动健康检查从真实的请求响应来确定端点是否健康。一旦端点被删除后,Envoy 将使用基于超时的方法进行重新插入,使用该方法可以通过配置 interval 将不正常的主机重新添加到集群中去,后续的每次删除都会增加一定的时间间隔,这样的话不健康的端点对用户的流量影响就会尽可能小。

和前面的主动健康检查一样,被动健康检查也需要针对每个集群进行配置。如下所示的配置表示返回3个连续的5xx错误时,该配置会将主机删除30s:

outlier_detection:
  consecutive_5xx: "3"
  base_ejection_time: "30s"
  • consecutive_5xx:表示上游主机返回一定数量的连续 5xx 状态,则将其移除。需要注意的是在这种情况下,5xx表示实际的5xx响应码值,或者是一个导致 HTTP 路由器返回一个上游的事件行为(比如重置、连接失败等)
  • base_ejection_time:表示移除主机的基准时间。真实的时间等于基准时间乘以主机移除的次数,默认为 30000ms 或 30s。

当启用被动健康检查过后,Envoy 会根据实际的请求响应来删除主机。同样首先我们先运行两个新的上游节点:

$ docker run -d cnych/docker-http-server:healthy; docker run -d cnych/docker-http-server:healthy;

然后启动一个新的 Envoy 代理,对应的配置文件为 envoy1.yaml,内容如下所示:

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
                - "*"
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: targetCluster
          http_filters:
          - name: envoy.router
  clusters:
  - name: targetCluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    hosts: [
      { socket_address: { address: 172.17.0.5, port_value: 80 }},
      { socket_address: { address: 172.17.0.6, port_value: 80 }}
    ]
    outlier_detection:
        consecutive_5xx: "3"
        base_ejection_time: "30s"

然后执行如下命令启动 Envoy 代理:

$ docker run -d --name proxy2 -p 81:8080 \
    -v $(pwd)/manifests/envoy1.yaml:/etc/envoy/envoy.yaml \
    envoyproxy/envoy

启动完成后,在单独的一个命令行终端中,执行下面的命令来循环发送请求观察状态的变化:

$ while true; do curl localhost:81; sleep .5; done

然后我们将 172.17.0.5 这个端点变成不健康的状态:

$ curl 172.17.0.5/unhealthy

该命令会将该端点的所有请求变成 500 错误:

$ curl 172.17.0.5 -i
HTTP/1.1 500 Internal Server Error
Date: Wed, 15 Apr 2020 06:55:02 GMT
Content-Length: 65
Content-Type: text/html; charset=utf-8

<h1>A unhealthy request was processed by host: 55e0950029b8</h1>

然后我们会在循环的终端中看到会收到3个不健康的请求,然后 Envoy 就会将该上游服务给移除掉:

......
<h1>A healthy request was processed by host: 5749edc61125</h1>
<h1>A healthy request was processed by host: 55e0950029b8</h1>
<h1>A healthy request was processed by host: 5749edc61125</h1>
<h1>A unhealthy request was processed by host: 55e0950029b8</h1>
<h1>A unhealthy request was processed by host: 55e0950029b8</h1>
<h1>A healthy request was processed by host: 5749edc61125</h1>
<h1>A unhealthy request was processed by host: 55e0950029b8</h1>
<h1>A healthy request was processed by host: 5749edc61125</h1>
<h1>A healthy request was processed by host: 5749edc61125</h1>
<h1>A healthy request was processed by host: 5749edc61125</h1>
......

然后我们也可以再次将 172.17.0.5 标记为健康,执行如下命令即可:

$ curl 172.17.0.5/healthy

然后差不多 30s 过后,我们查看 Envoy 又将该端点添加回来参与负载均衡了:

......
<h1>A healthy request was processed by host: 5749edc61125</h1>
<h1>A healthy request was processed by host: 5749edc61125</h1>
<h1>A healthy request was processed by host: 5749edc61125</h1>
<h1>A healthy request was processed by host: 55e0950029b8</h1>
<h1>A healthy request was processed by host: 5749edc61125</h1>
<h1>A healthy request was processed by host: 5749edc61125</h1>
<h1>A healthy request was processed by host: 55e0950029b8</h1>
<h1>A healthy request was processed by host: 5749edc61125</h1>
......

到这里我们就完成了在 Envoy 中的健康检查相关的配置。

本文分享自微信公众号 - k8s技术圈(kube100),作者:阳明

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-06-18

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 使用 Elastic Stack 构建 Kubernetes 全栈监控(1/4)

    在本系列文章中,我们将学习如何使用 Elastic 技术栈来为 Kubernetes 构建监控环境。可观测性的目标是为生产环境提供运维工具来检测服务不可用的情况...

    我是阳明
  • KEDA-Kubernetes 中基于事件驱动的自动伸缩

    事件驱动计算并不是什么新的想法,在数据库领域中就已经使用数据库触发器有很多年了。这个概念很简单:就是每当你添加、更改或删除数据时,就会触发一个事件来执行各种操作...

    我是阳明
  • 使用 Cobra 创建 CLI 应用

    虽然现在我们使用的大多数软件都是可视化的,很容易上手,但是这并不代表 CLI(命令行)应用就没有用武之地了,特别是对于开发人员来说,还是会经常和 CLI 应用打...

    我是阳明
  • Python 远程开机

    用 Python 关机你肯定听过或者实践过,那么用 Python 开机呢?这是一个神奇的方法,教你如何用 Python 来开机。

    李英杰同学
  • Spring系列之新注解配置+Spring集成junit+注解注入

    Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率 你本来要写一段很长的...

    一只胡说八道的猴子
  • 干货 | 阿里小蜜-电商领域的智能助理技术实践

    在全球人工智能领域不断发展的今天,包括Google、Facebook、Microsoft、Amazon、Apple等互联公司相继推出了自己的智能私人助理和机器人...

    华章科技
  • 使用 TIMSDK 的自定义字段 iOS 示例

    "用户资料自定义字段","好友自定义字段","群成员维度自定义字段","群维度自定义字段" 均已键值对 Key-Value 形式存储并使用。扩展相应的字段 Ke...

    腾讯云 - zjiezhu
  • Python的初学者你现在可以自己“看”到代码的运行了!

    最近小编一直在给群里小伙伴解决各种的错误,尤其是对一些基础薄弱的同学来说,出现错误后更是一脸懵逼!直到有一天,小编找到了Python Tutor,终于解脱了。 ...

    企鹅号小编
  • 教你0基础快速编程

    如果你想往It行业发展,那么我这里只能大概给一些建议。专业的建议的话,还是自己百度吧

    ZackSock
  • CentOS7安装Grafana(Yum)

    Grafana是一个跨平台的开源的分析和可视化工具,可以通过将采集的数据查询然后可视化的展示,并及时通知。

    py3study

扫码关注云+社区

领取腾讯云代金券