数智资源网
首页 首页 大数据 查看内容

使用Kubernetes最常犯的10个错误

木马童年 2020-11-4 17:50 65 0

在我们多年使用Kubernetes的经验中,我们有幸看到了很多集群(包括托管和非托管——在GCP,AWS和Azure上),并且看到了一些错误不断的被重复。这没什么丢人的,大多数错误我们也会犯!我会试着展示一些我们经常看到 ...

在我们多年使用Kubernetes的经验中,我们有幸看到了很多集群(包括托管和非托管——在GCP,AWS和Azure上),并且看到了一些错误不断的被重复。这没什么丢人的,大多数错误我们也会犯!

我会试着展示一些我们经常看到的错误,并且讨论怎样避免这样的错误。

资源(resources)——requests和limits

这个是最值得注意以及最先拿出来讲解的。

通常我们要么不设置CPU请求(request)要么将CPU请求设置得很低(这样我们就可以在每个节点上容纳很多Pod),因此节点的使用量会过大。在需求旺盛的时候,节点的CPU会被充分利用,我们的工作负载仅获得“所请求的部分”,并且受到CPU的限制,从而导致应用程序时延,超时等问题。

BestEffort(不要使用):

resources: {}

非常低的CPU(不要使用):

resources:

requests:

cpu: "1m"

另一方面,CPU设限可能会限制Pod的使用,即使节点的CPU还没有被充分使用,这又会导致应用程序时延的增加。有一个公开的讨论是关于Linux内核中CPU CFS配额(quota)的以及基于设置CPU限额(limits)和关闭CFS配额相关的CPU限流(throttling)。

CPU限额可能会导致更多的问题无法解决。可以在下面的链接中查看更多信息。

内存的过量使用会带来更多的问题。达到CPU的限额会产生限流后果,达到内存限额会导致pod被杀掉。曾经见过OOMkill吗?没错,这就是我们现在讨论到的。想要最小化这种事情发生的频率?不要过度使用内存,并且使用Guaranteed QoS(服务质量)设置内存请求等于限额,就像下面的例子所示。可以参考Henning Jacobs’ (Zalando)[1]获得更多这方面的主题。

突增型的(更有可能导致OOMkilled发生):

resources:

requests:

memory: "128Mi"

cpu: "500m"

limits:

memory: "256Mi"

cpu: 2

保证型的(Guaranteed):

resources:

requests:

memory: "128Mi"

cpu: 2

limits:

memory: "128Mi"

cpu: 2

那么在设置资源时还有什么可以帮助你的呢?

你可以通过metrics-server查看Pod(以及Pod中的容器)的当前CPU和内存的使用情况。很有可能你已经在使用它了。可以通过如下方式简单的使用它们:

kubectl top pods

kubectl top pods --containers

kubectl top nodes

但是这些都是展示的当前使用情况。如果你只是想要获得粗略的情况,这些足够了,但是你有可能想要及时查看这些使用情况指标(比如:CPU峰值使用情况,昨天早上使用情况等)。对于这种需求,你可以使用Prometheus,DataDog以及很多其他工具。这些工具仅仅是从metrics-server获取指标并且存储它们,然后你可以查询并且以图表方式查看。

VerticalPodAutoscaler[2]可以帮助你自动完成这个手动过程--及时查看CPU、内存使用情况并且基于这些指标设置新的requests和limits。

有效的利用你的电脑不是一件容易的任务。就像一直不停的玩俄罗斯方块一样。如果你发现你花了很多钱配置了一个高配电脑,但是利用率很低(比如说大约10%),你可能想去查看基于AWS Fargate或者Virtual Kubelet的产品,这些产品更多的使用无服务(Serverless)/按使用量计费模式,这种模式对你来说可能更便宜。

Liveness和Readiness探针

默认情况下Liveness和Readiness探针是没有被设置的。并且有时候一直保持这种情况。

但是当出现不可恢复的错误,你的服务该怎样重启?负载平衡器如何知道特定的Pod可以开始处理流量?或者处理更多的流量?

人们通常不知道这两者的区别。

Liveness探针在失败的时候会重启Pod

Readiness探针在失败后会将失败的Pod和Kubernetes服务(可以通过kubectl get endpoints检测)断开连接,并且流量不再分发给这个Pod,除非探测再次成功

在整个Pod的生命周期这两个都会一直运行。这是很重要的。

人们常常认为Readiness探针仅仅在开始的时候运行,用于通知Pod什么时候准备好了并且可以接受流量了。但是这仅仅是其中的一点。

另一方面是在一个Pod的生命周期中,这个Pod在处理太多流量(或者昂贵的计算)变得太繁忙(hot),这样我们就不给她安排更多的工作,同时等待她不繁忙,然后Readiness探针成功,接着我们可以重新给她安排更多的工作。在这种情况下(当Readiness探针失败时),如果Liveness探针也失败,那么它会产生非常适得其反的效果。为什么你会重启一个健康的并且正在做很多工作的Pod?

有时候一个探针都不定义要比他们定义错了好。正如上面提到的,如果Liveness探针和Readiness探针定义相同,你就会遇到大麻烦。你可能想在开始的时候只定义Readiness探针,因为Liveness探针很危险。

如果你共享依赖的任何一个Pod挂机了,那么不要让这些探针失败,因为它会导致所有相关Pod级联失败。那你就是自己搬起石头砸自己的脚。

为每个http服务都设置负载均衡

很大可能在你的集群中存在很多个http服务,这些服务可能都会暴露给外部世界。

如果你按照type:LoadBalancer方式把Kubernetes服务暴露出去,它的控制器(和特定提供商(vendor)相关)会提供以及调谐一个外部负载均衡器(不一定是L7负载均衡器,更可能是L4负载均衡器),并且如果你创建很多资源(外部的静态IPv4地址,算力,每秒钟的价格……),这些资源可能会很昂贵。

在这种情况下,共享一个外部负载均衡器可能更有意义,并且你可以把你的服务按照type:NodePort方式暴露出去。或者更好的方式是部署类似于nginx-ingress-controller(或traefik)作为单个NodePort端点,然后再把它暴露给外部的负载均衡器,并且在集群中基于Kubernetes的Ingress资源方式路由流量。

集群中其他需要互相通信的(微)服务可以通过ClusterIP服务或者开箱即用的dns服务发现来完成。注意不要使用公共DNS / IP,因为这可能会影响服务时延和云成本。

非Kubernetes感知的集群自动扩展

当向集群中添加或者从集群中删除节点时,你不应该只考虑一些简单的指标,比如节点CPU的使用率。当调度Pod时,你可以基于许多调度约束条件(constraints)做决定,比如Pod和节点的亲缘性(affinities),污点(taints)和容忍(tolerations),以及资源请求,QoS等。如果使用的外部自动扩展器不理解这些约束条件,就会比较麻烦。

想象一下,有一个新的Pod要被调度,但是所有可获得的CPU都被请求(requested)了并且这个pod此时卡在挂起状态。外部的扩展器查看当前被使用的(used)CPU的平均值(非请求值)并且不会做扩展(也就是不会添加一个新的节点)。这个Pod就不会被调度成功。

缩容(从集群中删除节点)一直以来更难。想象一下,你有一个有状态的Pod(附加持久卷)并且因为持久卷通常是属于特定可用性区域的资源,并且在该区域中不可复制,如果你自定义的扩展器删除了一个有这种pod的节点,那么调度器不会把这个Pod调度到其他不同的节点上,因为它被严格限定在拥有持久化磁盘所在的可用性区域。此时Pod又会处于挂起状态。

社区现在广泛使用的是集群自动扩展器[3],它运行在你的集群中并且和大部分主要的公有云厂商API集成在一起,理解所有这些约束条件才能在上面提到的案例中成功扩展。它也能够分辨出在不影响你设定的约束条件前提下,做出优雅的缩容,这可以给你在算力上省出一笔。

没有利用IAM/RBAC的强大功能

不要给IAM用户提供机器和应用程序的永久私钥,也不要在使用角色和服务账号产生临时私钥。

我们经常看到这种情况--硬编码访问以及把私钥保存在应用程序配置中,即使使用Cloud IAM,也从来不循环(rotating)使用私钥。在适当的地方使用IAM角色和服务账号代替用户方式。

使用Kubernetes最常犯的10个错误

跳过kube2iam,直接为服务账号设定IAM角色,可以参考těpán Vrany这篇博客[4]。

apiVersion: v1

kind: ServiceAccount

metadata:

annotations:

eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-app-role

name: my-serviceaccount

namespace: default

只需一个注解(annotation)。不是很难,对吧?

另外,如果没有必要,就不要给服务账号或者实例配置admin和cluster-admin权限。做到这点可能有点难,特别是在Kubernetes的RBAC中,但是仍然值得努力去做。

Pod的自我反亲缘性(self anti-affinities)

例如运行3个Pod副本在一个节点上,然后这个节点宕机了。啊?所有副本运行在一个节点上?Kubernetes不应该是具有魔法性并且提供HA吗?!

你不能预期的认为kubernetes调度器会为你的Pod强制实行反亲缘性。你必须明确的定义它们。

// 省略其他部分

labels:

app: zk

// 省略其他部分

affinity:

podAntiAffinity:

requiredDuringSchedulingIgnoredDuringExecution:

- labelSelector:

matchExpressions:

- key: "app"

operator: In

values:

- zk

topologyKey: "kubernetes.io/hostname"

就是这样。这能够确保pod会被调度到不同节点上(这仅仅在调度期间被检测,运行起来后不会,所以叫做requiredDuringSchedulingIgnoredDuringExecution)。

我们讨论的pod反亲缘性是基于不同的节点的名称 -- topologyKey: "kubernetes.io/hostname" --而不是不同的可用性区域。如果你真的需要合适的HA相关功能,你可以在这个主题上深挖下去。

没有使用PodDisruptionBudget

你在生产环境中使用Kubernetes。随着时间的推移,你的节点或者集群肯定需要做升级或者停止。PodDisruptionBudget(pdb)是一种API,用于在群集管理员和群集用户之间提供服务保证。

确保创建pdb以避免由于节点耗尽而造成不必要的服务中断。

apiVersion: policy/v1beta1

kind: PodDisruptionBudget

metadata:

name: zk-pdb

spec:

minAvailable: 2

selector:

matchLabels:

app: zookeeper

通过这个配置,集群用户就可以告诉集群管理员:“嗨,我这有ZooKeeper服务,不管你做什么,我这边总是有至少两个副本可用”。

我在这篇博客[5]中对这个主题讨论的更深入。

共享集群中有更多的租户或环境

Kubernetes的命名空间不提供强隔离。

人们看上去很期待这种情况,如果他们把非生产环境和生产环境工作负载分割到不同的命名空间,其中一方的工作负载永远不会影响到另一方。这是有可能达到的,比如一定级别的公平——资源请求和限制,配额,优先级类——以及隔离——亲缘性,容忍,污点(或者节点选择器)——当然也可以“物理上”分割数据面板中的工作负载,不过这种分割十分复杂。

如果你需要在同一个集群中拥有两种类型的工作负载,那么你就不得不忍受这种复杂性。如果你不需要并且再建一个集群对你来说相对更便宜(比如在公有云中),那么把它放到不同的集群中能够获得更强级别的隔离。

externalTrafficPolicy: Cluster

经常看到这种情况,所有的流量都被路由到集群中的一个NodePort服务上,默认情况下,这个服务有externalTrafficPolicy: Cluster标签。这意味着这个NodePort在每个节点上都是打开着的,所以你可以使用任何一个节点去和期望的服务(Pod集合)进行通信。

使用Kubernetes最常犯的10个错误

通常,以NodePort服务为目标的实际Pod仅在这些节点的子集上运行。这意味着,我和一个节点通信时,如果该节点没有我们预期的Pod在上面运行,它会把流量转发到其他节点,这会产生额外的网络跳跃(hop)以及增加的时延(如果节点位于不同的AZ/数据中心中,这个时延可能会很高并且还有额外的出口成本)。

在kubernetes服务上设置externalTrafficPolicy: Local就不会在每个节点上打开NodePort了,而是仅仅在运行对应pod的节点上打开。如果你使用外部负载均衡器(如AWS ELB)对其端点进行健康检查,它会仅将流量发送到应该去往的那些节点,从而改善了时延,计算开销,出口费用。

很大可能你正在使用traefik或者nginx-ingress-controller类似的东西,同时把它们作为NodePort(或者LoadBalancer,这也是使用NodePort机制)暴露出去,然后用来处理入口http流量路由,并且这种设置对于这类请求可以在很大程度上减少时延。

可以查看这篇externalTrafficPolicy and their trade-offs[6]博客,了解更深入的相关信息。

宠物(Pet)集群过多的对控制面板施加压力

你以前可能会给你的服务命名为Anton,HAL9000以及Colossus,或者为你的节点产生随机的id,但是你有通过名字来命名你的集群吗?

你知道在Kubernetes中如何以概念验证(Proof Of Concept)开始,将集群命名为“测试”并且仍在生产环境中使用它,最后每个人都不敢碰它?(真实的故事)

宠物集群并不好玩,随着时间的推移你可能想去删除你的集群,那么要做好灾难恢复的练习以及对控制面板要格外关注。害怕去操作控制面板是一个不好的信号。etcd挂了?好吧,你惹上大麻烦了。

另一方面,过多的操作控制面板也是不好的。随着时间的推移,当控制面板变慢了,很大可能是你创建了许多对象(objects)而从没有循环使用它们(非常常见,比如在使用helm时,它的默认配置并没有循环利用configmaps/secrets中的状态(state),这会导致你的控制面板中会有成千上万个对象),又或者你时常通过kube-api删除以及编辑大量的内容(比如自动伸缩,cicd,监控,事件日志,控制器等)。

另外,也要检测托管的kubernetes提供的“SLA”/SLO以及服务保证(guarantee)。厂商可能会保证控制面板(或它的子组件)的可用性,但不能保证你发送请求的低延迟。换句话说,你可能使用kubectl get nodes,然后在10分钟内获得正确响应,但是这个仍然在服务保证的范围内。

补充:使用latest标签

这是一个典型的问题。我很晚才意识到它,这种情况我看到的不多,因为我们大多数人被这种情况折腾过好多次,所以我们都不使用:lastest标签并且都会固定使用相应的版本。

ECR有个很好的功能——标签不能变更,值得一看。

总结

不要期待任何东西都可以自动的工作很好——Kubernetes不是银弹。一个坏的应用即使在Kubernetes上也是坏的(实际上可能比坏更糟糕)。如果你不够细心,你可能会遇到很多复杂性,过多压力并且缓慢的控制面板以及没有相应的DR策略。不要期待开箱即用的多租户和高可用性。多花点时间让你的应用变成云原生的。

可以查看由Henning整理的失败故事合集[7]。

想看其他容易犯的错误?可以在Twitter上关注我们(@MarekBartik、@MstrsObserver)。

相关链接:

https://www.slideshare.net/try_except_/optimizing-kubernetes-resource-requestslimits-for-costefficiency-and-latency-highload

https://cloud.google.com/kubernetes-engine/docs/concepts/verticalpodautoscaler

https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler

https://blog.pipetail.io/posts/2020-04-13-more-eks-tips/

https://blog.marekbartik.com/posts/2018-06-29_kubernetes-in-production-poddisruptionbudget/

https://www.asykim.com/blog/deep-dive-into-kubernetes-external-traffic-policies

https://k8s.af/

原文链接:https://blog.pipetail.io/posts/2020-05-04-most-common-mistakes-k8s/

声明:文章收集于网络,版权归原作者所有,为传播信息而发,如有侵权,请联系小编删除,谢谢!

欢迎加入本站公开兴趣群

软件开发技术群

兴趣范围包括:Java,C/C++,Python,PHP,Ruby,shell等各种语言开发经验交流,各种框架使用,外包项目机会,学习、培训、跳槽等交流

QQ群:26931708

应用程序 负载均衡 提供商 云成本 公有云 灾难恢复
0
为您推荐
HIVE数据仓库完美实战课程,资源教程下载

HIVE数据仓库完美实战课程,资源教程下载

课程名称【快速掌握HIVE视频教程】HIVE数据仓库完美实战课程课程目录├第一周:hive基…...

尚硅谷大数据Flink技术与实战,资源教程下载

尚硅谷大数据Flink技术与实战,资源教程下载

课程名称尚硅谷大数据Flink技术与实战课程目录理论_Flink基础 001__Flink理论_Flink…...

廖雪峰-2019大数据分析精品资料价值1980元,资源教程下载

廖雪峰-2019大数据分析精品资料价值1980元,资源教程

课程介绍:廖雪峰大神历时3个月打磨出来的《数据分析必备技能》的视频学习资料,由浅…...

尚硅谷-大数据项目之电商数仓教程下载

尚硅谷-大数据项目之电商数仓教程下载

课程介绍:本课程以国内电商巨头实际业务应用场景为依托,对电商数仓的常见实战指标以…...

小码哥李明杰Java版《恋上数据结构与算法》 ,资源教程下载

小码哥李明杰Java版《恋上数据结构与算法》 ,资源教

课程目录01-学前须知01-为什么要学习数据结构与算法02-编程语言的选择03-课程大纲04-…...

阿里云大数据分析师ACP认证视频教程下载

阿里云大数据分析师ACP认证视频教程下载

课程介绍阿里云大数据行业认证-大数据分析师认证(ACP-Alibaba Cloud Certified Prof…...

恋上数据结构与算法(第二季),视频教程下载

恋上数据结构与算法(第二季),视频教程下载

课程介绍:课程由MJ老师和名企算法大咖共同研发,在保证易懂的同时确保课程的系统全面…...

社交网络分析与挖掘,视频教程下载

社交网络分析与挖掘,视频教程下载

课程介绍:社交网络和数据挖掘是计算机学科相关研究中的热点,其具体研究涵盖理论、关…...