大早上10:30,我刚一进门研发小姐姐就跑上来说:杂工哥,我们有一些测试服务都访问不了了。机器能ping通,就是一些测试服务好像没啥反应。
问题定位
出问题的是我们的一台陈年老机,没准上面的硬件最大年龄都比实习生年纪要大一些。看了一眼资源占用,CPU、内存和硬盘IO还有网络都正常。通过小姐姐的描述,不能用的服务都来自一个k3s集群中主节点。这个节点平时基本上又当爹又当妈,除了他集群中所有的节点都是ARM的开发板而且稍微有点负载的服务都在这个节点上。
sh
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),这会触发以下行为:
- 阻止新的 Pods 调度到该节点上:具有磁盘压力污点的节点不会接受新的 Pods,除非这些 Pods 明确容忍(Tolerate)了这个污点。
- 开始驱逐现有的 Pods:为了释放磁盘空间,kubelet 会根据一定的策略开始驱逐一些 Pods。这些策略考虑了 Pod 的优先级、是否是关键系统组件等因素。被驱逐的 Pods 会被标记为 Evicted,集群的调度器(Scheduler)会尝试将这些 Pods 重新调度到其他健康的节点上。
再看看磁盘占用,好家伙df -h
100G磁盘使用率已经92%了。这上面除了k3s的服务之外还有一点点其他服务,比如kafka、rocketMQ等市面上常见的消息队列以及MySQL、redis等常见的数据库和一些测试服务。好家伙,一人占一点空间就分毛不剩了。
修复方案
怎么办?加硬盘呗!
于是我和小姐姐说,她平时造的测试数据(faker.py十几亿条吧,MySQL、PG中都有一份)太多了导致硬盘占用过高。给加块500G的硬盘就好了
增加硬盘
在加入一块新的硬盘后,需要执行一系列步骤来初始化这块硬盘,创建文件系统,并将其挂载到系统中以供使用。以下是需要执行的步骤概述:
1. 确认新硬盘
首先,需要确认新硬盘已经被系统识别。可以通过lsblk
命令来查看所有连接的存储设备。新硬盘应该会显示在列表中,但没有挂载点。
bash
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. 分区
使用fdisk
或parted
工具对新硬盘进行分区。这里以fdisk
为例,假设新硬盘被系统识别为/dev/sdb
(根据lsblk
的输出确认正确的设备名)。
bash
sudo fdisk /dev/sdb
在fdisk
命令行工具中,可以使用n
来创建新分区,p
来创建主分区,然后按提示操作。完成后,使用w
命令写入并退出fdisk
。
3. 创建文件系统
创建分区后,需要在新分区上创建文件系统。这里以创建一个ext4
文件系统为例:
bash
sudo mkfs.ext4 /dev/sdb1
确保使用的是新分区的正确设备名(在上一步创建的分区,例如/dev/sdb1
)。
4. 挂载新硬盘
首先,创建一个挂载点,例如/mnt/newdisk
:
bash
sudo mkdir /mnt/newdisk
然后,将新的文件系统挂载到这个目录:
bash
sudo mount /dev/sdb1 /mnt/newdisk
5. 设置自动挂载
为了在系统重启后自动挂载新硬盘,需要编辑/etc/fstab
文件。首先,获取新分区的UUID:
bash
sudo blkid
找到/dev/sdb1
的UUID,然后编辑/etc/fstab
文件,添加一行:
bash
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
目录迁移到一块新加的、空间更大的硬盘上,可以有效地解决根分区磁盘空间不足的问题。这样做有几个好处:
- 缓解磁盘压力 :迁移后,根分区的磁盘使用率会显著下降,从而解除
DiskPressure
状态,保证集群的稳定运行。 - 提高性能:如果原磁盘的 I/O 性能成为瓶颈,迁移到性能更好的新硬盘上也可能带来性能提升。
- 扩展存储容量:对于持续增长的数据,使用更大的硬盘可以提供更多的存储空间,避免未来出现相同的磁盘空间不足问题。
- 增加冗余:将关键数据迁移到独立的硬盘上,可以在根分区发生故障时,降低数据丢失的风险。
bash
# 停止 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
的数据已经成功迁移到新硬盘上,并且没有任何问题,可以删除原来的备份目录来释放空间:
bash
sudo rm -rf /var/lib/rancher_backup
注意事项
- 在操作过程中,确保有对
/var/lib/rancher
目录的完整备份,以防万一出现问题。 - 根据具体环境和配置,步骤中的命令可能需要适当调整。
- 在编辑
/etc/fstab
文件时要特别小心,因为错误的配置可能导致系统无法启动。
通过以上步骤,应该能够有效地利用新增的磁盘空间来缓解 K3s 集群的磁盘空间压力。