掘金 后端 ( ) • 2024-04-23 11:02

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

问题定位

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

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 集群的磁盘空间压力。