如何在Kubernetes中将Envoy用作负载均衡器

栏目: IT技术 · 发布时间: 4年前

内容简介:在当今分布式的世界中,单体架构越来越多地被多个,更小,相互连接的服务(不管是好是坏)所取代,代理和负载平衡技术似乎正在复兴。除了老玩家以外,近年来还涌现出几种新的代理技术,它们以各种技术实现,并以不同的功能进行普及,例如易于集成到某些云提供商(“云原生”),高性能和低内存占用,或动态配置。可以说,两种最流行的“经典”代理技术是NGINX(C)和HAProxy(C),而其中的一些新成员是Zuul(Java),Linkerd(Rust),Traefik(Go),Caddy(Go)和Envoy(C++)。所有这些

在当今分布式的世界中,单体架构越来越多地被多个,更小,相互连接的服务(不管是好是坏)所取代,代理和负载平衡技术似乎正在复兴。除了老玩家以外,近年来还涌现出几种新的代理技术,它们以各种技术实现,并以不同的功能进行普及,例如易于集成到某些云提供商(“云原生”),高性能和低内存占用,或动态配置。

可以说,两种最流行的“经典”代理技术是NGINX(C)和HAProxy(C),而其中的一些新成员是Zuul(Java),Linkerd(Rust),Traefik(Go),Caddy(Go)和Envoy(C++)。

所有这些技术具有不同的功能集,并且针对某些特定场景或托管环境(例如,Linkerd经过微调,可在Kubernetes中使用)。

在本文中,我将不做这些比较,而只是关注一个特定的场景:如何将Envoy用作Kubernetes中运行的服务的负载平衡器。

Envoy是最初在Lyft实施的“高性能C++分布式代理”,但此后得到了广泛的采用。它性能高,资源占用少,支持由“控制平面” API管理的动态配置,并提供了一些高级功能,例如各种负载平衡算法,限流,熔断和影子镜像。

由于多种原因,我选择Envoy作为负载平衡器代理:

  • 除了可以通过控制平面API动态控制之外,它还支持基于YAML的简单,硬编码配置,这对我而言很方便,并且易于入门。
  • 它内置了对称为STRICT_DNS的服务发现技术的支持,该技术基于查询DNS记录,并期望看到上游群集每个节点都有IP地址的A记录。这使得Kubernetes中的无头服务变得易于使用。
  • 它支持各种负载平衡算法,其中包括“最少请求”。

在开始使用Envoy之前,我是通过类型为LoadBalancer的服务对象访问Kubernetes中的服务的,这是从Kubernetes中从外部访问服务的一种非常典型的方法。负载均衡器服务的确切工作方式取决于托管环境。我使用的是Google Kubernetes引擎,其中每个负载平衡器服务都映射到TCP级别的Google Cloud负载平衡器,该负载平衡器仅支持循环负载平衡算法。

就我而言,这是一个问题,因为我的服务具有以下特征:

  • 这些请求长期运行,响应时间从100ms到秒不等。
  • 请求的处理占用大量CPU,实际上一个请求的处理使用了一个CPU内核的100%。
  • 并行处理许多请求会降低响应时间。 (这是由于该服务的工作原理的内部原因,它不能有效地并行运行少数几个请求。)

由于上述特性,轮循负载均衡算法不太适合,因为经常(偶然)多个请求最终在同一节点上结束,这使得平均响应时间比群集的平均响应时间差得多。所以需要分配更均匀的负载。

在本文的其余部分中,我将描述将Envoy部署为在Kubernetes中运行的服务之前用作负载平衡器的必要步骤。

1. 为我们的应用创建headless服务

在Kubernetes中,有一种称为headless服务的特定服务,恰好与Envoy的STRICT_DNS服务发现模式一起使用时非常方便。

Headless服务不会为底层Pod提供单个IP和负载平衡,而只是具有DNS配置,该配置为我们提供了一个A记录,其中包含与标签选择器匹配的所有Pod的Pod IP地址。我们希望在实现负载平衡并自己维护与上游Pod的连接的情况下使用此服务类型,这正是我们使用Envoy可以做到的。

我们可以通过将.spec.clusterIP字段设置为“None”来创建headless服务。因此,假设我们的应用程序pod的标签app的值为myapp,我们可以使用以下yaml创建headless服务。

如何在Kubernetes中将Envoy用作负载均衡器

服务的名称不必等于我们的应用程序名称或应用程序标签,但这是一个很好的约定。

现在,如果我们在Kubernetes集群中检查服务的DNS记录,我们将看到带有IP地址的单独的A记录。如果我们有3个Pod,则会看到与此类似的DNS摘要。

$ nslookup myapp 
Server: 10.40.0.10 
Address: 10.40.0.10#53 

Non-authoritative answer: 
Name: myapp.namespace.svc.cluster.local Address: 10.36.224.5 
Name: myapp.namespace.svc.cluster.local Address: 10.38.187.17 
Name: myapp.namespace.svc.cluster.local Address: 10.38.1.8

Envoy的STRICT_DNS服务发现的工作方式是,它维护DNS返回的所有A记录的IP地址,并且每隔几秒钟刷新一次IP组。

2. 创建Envoy镜像

在不以动态API形式提供控制平面的情况下使用Envoy的最简单方法是将硬编码配置添加到静态yaml文件中。

以下是一个基本配置,该配置将负载均衡到域名myapp给定的IP地址。

如何在Kubernetes中将Envoy用作负载均衡器

注意以下几个部分:

type: STRICT_DNS
lb_policy:LEAST_REQUEST
hosts: [{ socket_address: { address: myapp, port_value: 80 }}]

您可以在文档中找到有关各种配置参数的更多信息。

现在,我们必须将以下Dockerfile放在envoy.yaml配置文件同一目录层级。

FROM envoyproxy/envoy:latest 
COPY envoy.yaml /etc/envoy.yaml 
CMD /usr/local/bin/envoy -c /etc/envoy.yaml

最后一步是构建镜像,并将其推送到某个地方(例如Dockerhub或云提供商的容器注册表),以便能够从Kubernetes使用它。

假设我想将此推送到我的个人Docker Hub帐户,可以使用以下命令来完成。

$ docker build -t markvincze/myapp-envoy:1 .  
$ docker push markvincze/myapp-envoy:1

3. 可选项: 使Envoy镜像可参数化

如果我们希望能够使用环境变量自定义Envoy配置的某些部分而无需重建 Docker 镜像,则可以在yaml配置中进行一些env var替换。假设我们希望能够自定义要代理的headless服务的名称以及负载均衡器算法,然后我们必须按以下方式修改yaml配置。

如何在Kubernetes中将Envoy用作负载均衡器

然后实施一个小 shell 脚本(docker-entrypoint.sh),在其中执行环境变量替换。

#!/bin/sh  
set -e 

echo  "Generating envoy.yaml config file..." 
cat /tmpl/envoy.yaml.tmpl | envsubst \$ENVOY_LB_ALG,\$SERVICE_NAME > /etc/envoy.yaml 

echo  "Starting Envoy..." 
/usr/local/bin/envoy -c /etc/envoy.yaml

并更改我们的Dockerfile以运行此脚本,而不是直接启动Envoy。

FROM envoyproxy/envoy:latest 
COPY envoy.yaml /tmpl/envoy.yaml.tmpl 
COPY docker-entrypoint.sh / 

RUN chmod 500 /docker-entrypoint.sh 

RUN apt-get update && \
    apt-get install gettext -y 
    
ENTRYPOINT ["/docker-entrypoint.sh"]

请记住,如果使用这种方法,则必须在Kubernetes部署中指定这些环境变量,否则它们将为空。

4. 创建Envoy deployment

最后,我们必须为Envoy本身创建一个部署。

如何在Kubernetes中将Envoy用作负载均衡器

如何在Kubernetes中将Envoy用作负载均衡器

仅当我们使Envoy Docker镜像可参数化时,才需要env变量。

Apply此Yaml后,Envoy代理应该可以运行,并且您可以通过将请求发送到Envoy服务的主端口来访问基础服务。

在此示例中,我仅添加了类型为ClusterIP的服务,但是如果要从群集外部访问代理,还可以使用LoadBalancer服务或Ingress对象。

下图说明了整个设置的体系结构。

如何在Kubernetes中将Envoy用作负载均衡器

该图仅显示一个Envoy窗格,但是如果需要,您可以将其扩展以具有更多实例。当然,您可以根据需要使用Horizo​​ntal Pod Autoscaler自动创建更多副本。 (所有实例将是自治的且彼此独立。)

实际上,与基础服务相比,代理所需的实例可能要少得多。在当前使用Envoy的生产应用程序中,我们在 〜400个上游Pod上提供了〜1000个请求/秒,但是我们只有3个Envoy实例在运行,CPU负载约为10%。

故障排除和监视

在Envoy配置文件中,您可以看到admin:部分,用于配置Envoy的管理端点。可用于检查有关代理的各种诊断信息。

如果您没有发布admin端口的服务,默认情况下为9901,您仍然可以通过端口转发到带有kubectl的容器来访问它。假设其中一个Envoy容器称为myapp-envoy-656c8d5fff-mwff8,那么您可以使用命令kubectl port-forward myapp-envoy-656c8d5fff-mwff8 9901开始端口转发。然后您可以访问 http://localhost :9901上的页面。

一些有用的端点:

/config_dump
/clusters

进行监视的一种方法是使用Prometheus从代理pods获取统计信息。 Envoy对此提供了内置支持,Prometheus统计信息在管理端口上的/ stats/prometheus路由上发布。

您可以从该存储库下载可视化这些指标的Grafana仪表板,这将为您提供以下图表。

如何在Kubernetes中将Envoy用作负载均衡器

关于负载均衡算法

负载平衡算法会对集群的整体性能产生重大影响。对于需要均匀分配负载的服务(例如,当服务占用大量CPU并很容易超载时),使用最少请求算法可能是有益的。另一方面,最少请求的问题在于,如果某个节点由于某种原因开始发生故障,并且故障响应时间很快,那么负载均衡器会将不成比例的大部分请求发送给故障节点,循环负载均衡算法不会有问题。

我使用 dummy API 进行了一些基准测试,并比较了轮询和最少请求LB算法。事实证明,最少的请求可以带来整体性能的显着提高。

我使用不断增加的输入流量对API进行了约40分钟的基准测试。在整个基准测试中,我收集了以下指标:

  • 服务器执行的请求数("requests in flight")
  • 每台服务器平均正在执行的请求数
  • 请求速率(每5分钟增加一次)
  • 错误率(通常没有,但是当事情开始放慢时,这开始显示出超时)
  • 服务器上记录的响应时间百分位数(0.50、0.90和0.99)

ROUND_ROBIN的统计数据看起来像这样:

如何在Kubernetes中将Envoy用作负载均衡器

这些是LEAST_REQUEST的结果:

如何在Kubernetes中将Envoy用作负载均衡器

您可以从结果中看到LEAST_REQUEST可以导致流量在节点之间的分配更加顺畅,从而在高负载下降低了平均响应时间。

确切的改进取决于实际的API,因此,我绝对建议您也使用自己的服务进行基准测试,以便做出决定。

总结

我希望此介绍对在Kubernetes中使用Envoy有所帮助。顺便说一下,这不是在Kubernetes上实现最少请求负载平衡的唯一方法。可以执行相同操作的各种ingress控制器(其中一个是在Envoy之上构建的Ambassador)。


以上所述就是小编给大家介绍的《如何在Kubernetes中将Envoy用作负载均衡器》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Twenty Lectures on Algorithmic Game Theory

Twenty Lectures on Algorithmic Game Theory

Tim Roughgarden / Cambridge University Press / 2016-8-31 / USD 34.99

Computer science and economics have engaged in a lively interaction over the past fifteen years, resulting in the new field of algorithmic game theory. Many problems that are central to modern compute......一起来看看 《Twenty Lectures on Algorithmic Game Theory》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

MD5 加密
MD5 加密

MD5 加密工具