研发小姐姐:不好了,服务又挂了!——记一次k3s集群节点磁盘扩容

878 阅读10分钟

大早上10:30,我刚一进门研发小姐姐就跑上来说:杂工哥,我们有一些测试服务都访问不了了。机器能ping通,就是一些测试服务好像没啥反应。

问题定位

出问题的是我们的一台陈年老机,没准上面的硬件最大年龄都比实习生年纪要大一些。看了一眼资源占用,CPU、内存和硬盘IO还有网络都正常。通过小姐姐的描述,不能用的服务都来自一个k3s集群中主节点。这个节点平时基本上又当爹又当妈,除了他集群中所有的节点都是ARM的开发板而且稍微有点负载的服务都在这个节点上。

什么是k3s?

K3s是一个轻量级的Kubernetes发行版,它旨在提供一个更小巧、更易于部署和管理的Kubernetes解决方案。Kubernetes是一个用于容器编排和管理的开源平台,但它在部署和管理方面可能需要大量的资源和配置。K3s的目标是简化Kubernetes的部署和管理过程,使其更适合在资源受限的环境中运行,如边缘计算设备、物联网设备或开发人员的本地开发环境。 K3s相对于标准的Kubernetes发行版具有以下特点:

  1. 轻量级:K3s的二进制文件大小只有几十兆字节,相比于标准的Kubernetes发行版要小得多。它删除了一些不常用的组件和依赖项,以减少资源消耗和启动时间。
  2. 简化部署:K3s的安装和配置过程相对简单,可以在几分钟内完成。它默认启用了一些常用的功能和插件,如服务负载均衡、持久存储和网络插件,减少了额外的配置工作。
  3. 低资源消耗:K3s在资源消耗方面比标准的Kubernetes发行版更加节约。它使用较少的内存和处理器资源,并且可以在较低配置的设备上运行,如树莓派或其他嵌入式设备。
  4. 安全性:K3s默认启用了一些安全功能,如TLS证书自动生成和轻量级的RBAC(基于角色的访问控制),以提供更好的安全性。

我为什么用K3S

如果你正面临着和我一样的情况,需要在一些ARM设备上部署和管理应用,而且这些设备的资源比较紧张,那么可能会发现传统的Kubernetes(K8s)并不是最合适的选择。理解K8s的强大之处,但同时也意识到在资源有限的情况下,它可能会显得有点“太过于庞大”。

这就是我为什么转向K3s的原因。K3s就像是为了解决这类问题而生的。它的文件体积小,安装快速简单,对资源的要求低得多,这些特点让它非常适合在ARM这样的设备上运行。

安装K3s真的很轻松,几分钟就能搞定,而且它还自带了很多默认配置,比如服务负载均衡、持久存储等,这让后续的管理和使用变得更加简单。同时,它在安全性方面也做得很好,比如自动生成TLS证书和提供基于角色的访问控制等功能,这些都是开箱即用的。

最开始,我是想在ARM设备上用K3s,然后在主节点上运行K8s,以此来组建一个既轻量又强大的集群。但考虑到实际操作中的资源和精力限制,最终决定全面采用K3s。虽然这意味着放弃了K8s的一些高级功能,但对于我的实际需求来说,K3s已经足够用了,而且它的轻量级和简便性实在是太符合我的情况了。

所以,如果你也在寻找一个既能节省资源又能简化管理流程的解决方案,K3s绝对值得考虑。

# 查看集群资源情况
k3s kubectl describe nodes

# 输出了一堆东西,有一个就是今天的罪魁祸首
Conditions:
  Type             Status  LastHeartbeatTime                 LastTransitionTime                Reason                       Message
  ----             ------  -----------------                 ------------------                ------                       -------
  ...
  DiskPressure     True    Mon, 22 Apr 2024 04:04:37 +0000   Mon, 22 Apr 2024 03:56:58 +0000   KubeletHasDiskPressure       kubelet has disk pressure
  ...

问题找到了,当 Kubernetes 节点上出现 DiskPressure(磁盘压力)条件时,这意味着节点的可用磁盘空间不足。Kubernetes 通过 kubelet 自动监测节点的健康状况,包括磁盘空间。如果检测到磁盘空间不足(即存在磁盘压力),它会采取措施保护节点和整个集群的稳定性,其中一项措施就是驱逐(Evict)节点上的 Pods(低于10%可用空间就会驱离)。

当节点上的磁盘空间达到临界水平时,kubelet 会标记节点具有 node.kubernetes.io/disk-pressure 污点(Taint),这会触发以下行为:

  1. 阻止新的 Pods 调度到该节点上:具有磁盘压力污点的节点不会接受新的 Pods,除非这些 Pods 明确容忍(Tolerate)了这个污点。
  2. 开始驱逐现有的 Pods:为了释放磁盘空间,kubelet 会根据一定的策略开始驱逐一些 Pods。这些策略考虑了 Pod 的优先级、是否是关键系统组件等因素。被驱逐的 Pods 会被标记为 Evicted,集群的调度器(Scheduler)会尝试将这些 Pods 重新调度到其他健康的节点上。

再看看磁盘占用,好家伙df -h100G磁盘使用率已经92%了。这上面除了k3s的服务之外还有一点点其他服务,比如kafka、rocketMQ等市面上常见的消息队列以及MySQL、redis等常见的数据库和一些测试服务。好家伙,一人占一点空间就分毛不剩了。

修复方案

怎么办?加硬盘呗!

于是我和小姐姐说,她平时造的测试数据(faker.py十几亿条吧,MySQL、PG中都有一份)太多了导致硬盘占用过高。给加块500G的硬盘就好了

增加硬盘

在加入一块新的硬盘后,需要执行一系列步骤来初始化这块硬盘,创建文件系统,并将其挂载到系统中以供使用。以下是需要执行的步骤概述:

1. 确认新硬盘

首先,需要确认新硬盘已经被系统识别。可以通过lsblk命令来查看所有连接的存储设备。新硬盘应该会显示在列表中,但没有挂载点。

lsblk

root@test-docker:/home# lsblk
NAME                      MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
#---------------------手动马赛克-------------------------------
sdb                         8:16   0  500G  0 disk # 这块是新增的
sr0                        11:0    1  1.8G  0 rom  

2. 分区

使用fdiskparted工具对新硬盘进行分区。这里以fdisk为例,假设新硬盘被系统识别为/dev/sdb(根据lsblk的输出确认正确的设备名)。

sudo fdisk /dev/sdb

fdisk命令行工具中,可以使用n来创建新分区,p来创建主分区,然后按提示操作。完成后,使用w命令写入并退出fdisk

3. 创建文件系统

创建分区后,需要在新分区上创建文件系统。这里以创建一个ext4文件系统为例:

sudo mkfs.ext4 /dev/sdb1

确保使用的是新分区的正确设备名(在上一步创建的分区,例如/dev/sdb1)。

4. 挂载新硬盘

首先,创建一个挂载点,例如/mnt/newdisk

sudo mkdir /mnt/newdisk

然后,将新的文件系统挂载到这个目录:

sudo mount /dev/sdb1 /mnt/newdisk

5. 设置自动挂载

为了在系统重启后自动挂载新硬盘,需要编辑/etc/fstab文件。首先,获取新分区的UUID:

sudo blkid

找到/dev/sdb1的UUID,然后编辑/etc/fstab文件,添加一行:

UUID=分区UUID /mnt/newdisk ext4 defaults 0 2

替换分区UUID为实际的UUID值。

6. 迁移 /var/lib/rancher 数据

迁移 /var/lib/rancher 数据的原因主要是为了解决 Kubernetes 集群节点上出现的 DiskPressure 问题,即磁盘空间不足的问题。在 Kubernetes 集群中,/var/lib/rancher 目录是非常关键的,因为它通常包含了 K3s 或 Rancher 部署的数据和状态信息,这可能包括集群数据、容器镜像、Pod 的日志文件等。随着时间的推移和集群的使用,这些数据可以积累起来,占用大量的磁盘空间。

当节点的磁盘空间不足时,Kubernetes 的 kubelet 会触发 DiskPressure 状态,这会导致新的 Pods 无法调度到该节点上,同时开始驱逐现有的 Pods 以释放空间。这种情况下,集群的稳定性和应用的可用性都会受到影响。

通过将 /var/lib/rancher 目录迁移到一块新加的、空间更大的硬盘上,可以有效地解决根分区磁盘空间不足的问题。这样做有几个好处:

  1. 缓解磁盘压力:迁移后,根分区的磁盘使用率会显著下降,从而解除 DiskPressure 状态,保证集群的稳定运行。
  2. 提高性能:如果原磁盘的 I/O 性能成为瓶颈,迁移到性能更好的新硬盘上也可能带来性能提升。
  3. 扩展存储容量:对于持续增长的数据,使用更大的硬盘可以提供更多的存储空间,避免未来出现相同的磁盘空间不足问题。
  4. 增加冗余:将关键数据迁移到独立的硬盘上,可以在根分区发生故障时,降低数据丢失的风险。
# 停止 K3s 服务
sudo systemctl stop k3s.service

# 复制数据到新硬盘上
sudo rsync -avzh /var/lib/rancher/ /mnt/newdisk/rancher/

# 重命名原目录(为了安全起见,暂时保留)
sudo mv /var/lib/rancher /var/lib/rancher_backup

# 创建一个新的符号链接指向新位置
sudo ln -s /mnt/newdisk/rancher /var/lib/rancher

# 重新启动 K3s 服务
sudo systemctl start k3s.service

7. 监控和验证

在迁移完成并重新启动 K3s 服务后,仔细监控集群的状态和应用的运行情况,确保一切正常。可以使用 k3s kubectl 命令来查看集群状态和 Pods 的状态。

8. 清理

一旦确认新的配置运行稳定,且 /var/lib/rancher 的数据已经成功迁移到新硬盘上,并且没有任何问题,可以删除原来的备份目录来释放空间:

sudo rm -rf /var/lib/rancher_backup

注意事项

  • 在操作过程中,确保有对 /var/lib/rancher 目录的完整备份,以防万一出现问题。
  • 根据具体环境和配置,步骤中的命令可能需要适当调整。
  • 在编辑 /etc/fstab 文件时要特别小心,因为错误的配置可能导致系统无法启动。

通过以上步骤,应该能够有效地利用新增的磁盘空间来缓解 K3s 集群的磁盘空间压力。