教训:避免两台物理机组建k8s集群

💡
内容有点水

由于各种财政原因,我管理的集群现在只有两个节点,而且这两个节点是两台物理机。
然后就出现了这样一个图:


大量该集群服务不可用

发现这个问题是因为注意到集群中的大量服务突然不可用。
所有位于其中的Longhorn卷都变成了Degraded状态,大量容器等待重启。

值得注意的是,由于其中一个节点崩溃,Nexus服务也崩溃了,进而导致Docker镜像仓库也不可用。这进一步导致其他服务在重启时无法获取到镜像。
这种影响是全局的,跨集群的。幸运的是,另外两个集群并没有同时立刻需要获取镜像。


闪崩的原因

当前还没有找到闪崩的直接原因。但是从监控数据来看,蓝色节点的内存占用一直超过80%。
再加上我当时触发了两个React项目的构建,可以推断,由于构建恰好被分配到了这个节点,导致该节点的内存完全耗尽。

当内存耗尽时,发生了以下事情(个人推测):
首先受到影响的应该是Longhorn,因为Longhorn会同步两个节点上的卷。当内存达到极限时,系统负载激增导致一台节点的各方面性能下降,最终导致Longhorn认为某个节点上的卷失去响应。
我隐约记得,Longhorn的处理方式很可能会让这个卷变成只读状态,从而导致所有需要写入硬盘的服务挂掉,如Jenkins、Gitea、Nexus和Postgres等等。


负载不平衡的原因

这是由于定期进行的patch导致的。

首先,需要明确的是,这个集群的每个node都直接对应一个物理机。
与云平台不同,云平台通常会在进行patch时启动一个新的node,并将该node加入到集群,然后再驱逐出一个老的node上的pod,最后将该老node移出集群并销毁。
而对于这个物理集群,无论如何驱逐,最终都需要重启该node。因此,进行一次patch后,无论如何,所有的pod都会移动到其他的node上。

而在当前情况下,该集群只有两台node,这就意味着,当一台node进行更新并重启时,所有的负载都会集中到另一台node上,导致负载极度不平衡。


缓慢的自动恢复

由于大量的Longhorn卷需要恢复,因此在集群开始恢复之后,整个集群的CPU占用率会非常高。同时,由于涉及大量的读写操作,集群的硬盘压力也很大(因成本考虑,硬盘为机械硬盘而非SSD)。

虽然好的方面是,整个集群的自动恢复过程不需要人工干预,但坏的方面是,所有的服务恢复需要花费约一个小时。
当然,这也是因为该集群包含了许多基础设施,导致需要先恢复基础设施后再恢复服务。


如何解决

要解决集群负载不平衡的问题,可以增加一个节点来分担负载。
但更重要的是,为什么不减少这个集群的负载?比如为什么不把部分服务迁移到别的集群(如果这些集群还能承担)?

需要注意的是,这里的讨论前提是每个node都对应着一个物理机。

在这种情况下,我们可以得出这样的结论:对于一个拥有12核24G的集群来说,使用两台6核12G的机器最高的利用率只能到50%,而使用三台4核8G的机器则可以用到66%。也就是说,node越多,硬件资源的利用率上限也就越高。

不过,这种估算并未考虑操作系统本身对内存的占用。如果不考虑这一点,那么把12核24G的集群拆成100个node显然是荒谬的。


更正式结论

负载不平衡的问题背后其实是集群容错率的问题。

当我们考虑需要多少个node时,不仅要考虑是否满足业务需求,还要考虑异常情况。我们需要考虑集群最多能接受多少个node同时down掉,以及如何避免多个node同时down掉。

举个例子,如果我们需要一个8核16G的集群,选择两台6核12G的机器组成集群,那么任何一台node都不能down掉。
反过来,如果选择三台4核8G的机器组成集群,那么理论上可以有一台node down掉。为了确保集群的稳定性,我们需要尽量确保这三台node不在同一地区。


后记

尽管内容相对简单,但这个例子提醒我们一定要动手实操,真正落地。

在创建这个两个node的集群时,我就意识到存在问题。但问题是当时我考虑的不止这一个,以至于我没有意识到这个问题的致命性。
之前我也曾考虑到etcd的问题、Longhorn卷的可用性问题(另外两个集群是3个node存2份)、未来扩展的维护问题,以及patch挂一台的影响等等。

当时我站在的角度认为恢复是自动的,因此Longhorn卷的可用性和扩展是主要的问题。
至于patch时挂一台,当时的考虑是反正可以自动恢复,没必要太纠结。但这不是一个逻辑和理性判断的问题,而是一个价值判断的问题。
只有在真正亲身经历过之后,才能对这些不同的点做出感性的价值判断。

现在站在今天的角度看,Longhorn的可用性其实并不是那么大的问题。因为Longhorn本身只要有一个卷活着就可以正常的读写。问题无非是卷的恢复必须等待node恢复,这个可以通过错开node的patch时间轻松解决。
至于集群的扩展,无非是在扩展时需要将原先做纯worker的node移除,然后重新以etcd和control plane加入即可。
但是patch问题将会在扩展成三节点之前一直困扰着集群,并且由于这个集群主要是负责基础设施,最总我的体验是非常差的。

前后对比:
以前:反正自动恢复,无非等一会儿。
现在:没人愿意再等那一会儿了。

蜀ICP备19018968号