我们新建的 K8S 集群中,有时候部署 deployment 会发生 node 拉取镜像失败的问题,排查后发现是由于 docker 镜像的存储的磁盘空间很小,因此需要改变 docker 镜像的默认存储位置到另外一块儿磁盘上,但另外一块磁盘还没有划分分区。 为了解决该问题,我们进行以下步骤的操作。
- 配置 master 节点到 node 节点的免密操作
- 编写脚本,该脚本对 node 节点上未分区的磁盘进行分区、初始化文件系统、mount 磁盘分区到指定目录。从 master 上批量在所有 node 节点上执行该脚本,完成磁盘分区及挂载
- 编写脚本,该脚本更改 node 节点上 docker 镜像的存储位置,同步以前的镜像到新的镜像存储空间,并重启 docker 服务是配置生效
经过以上操作,再加上我们的集群上已经运行了定时清除无用镜像的 DameonSet,解决了 docker 镜像存储空间的问题。下面介绍具体每一个步骤中进行的工作内容。
SSH 免密登录
可以通过将 master 主机的 ssh 公钥保存在集群各个节点上,实现 master 到集群节点的免密登录。我们集群中节点较多,为避免纷发公钥时依次登录到各个节点,可以在 master 主机上执行纷发脚本来实现。
对于未知 host,linux 将会询问是否要继续建立连接,为了避免纷发脚本执行过程中每个节点都需要交互,可以更改 master 主机的 /etc/ssh/ssh_config
文件,添加 StrictHostKeyChecking no
。执行 ssh-keygen -t rsa
根据提示生成 master 机器的公钥/密钥文件。执行下面
#!/bin/sh
cat nodes.txt | while read ip
do
echo $ip
sshpass -p node-password ssh-copy-id -i ~/.ssh/id_rsa.pub root@${ip}
done
磁盘分区
先登录到其中一个 node 节点上,划分好分区,作为批量划分分区的模版。
# 查看磁盘,发现有一块磁盘尚未挂载
$ fdisk -l
# Disk /dev/vdb: 2147.5 GB, 2147483648000 bytes, 4194304000 sectors
# Units = sectors of 1 * 512 = 512 bytes
# Sector size (logical/physical): 512 bytes / 512 bytes
# I/O size (minimum/optimal): 512 bytes / 512 bytes
# 开始对新磁盘进行分区,进入 fdisk 交互式环境,根据提示进行操作即可
# n 指令添加新分区
# 之后的 p 表示新分区为主分区(我们将整个磁盘都作为存储用,无需添加扩展分区)
# 1 表示新添加的分区编号
# 将全部磁盘空间分配给该分区并使用 w 指令保存
$ fdisk /dev/vdb
> n
> p
> 1
>
> w
# 再使用 fdisk 命令查看,发现已经有新分区了 /dev/vdb1
$ fdisk -l
# 添加新分区后,要格式化新分区,我们使用 ext4 文件系统
$ mkfs -t ext4 /dev/vdb1
# 之后再将新分区挂载到某个文件夹下,通过读写文件夹,就能使用新磁盘存储文件了
$ mount /dev/vdb1 /mnt/localdisk
# 查看可用空间
$ df -h
# /dev/vdb1 2.0T 71M 1.9T 1% /mnt/data
# 如果要卸载磁盘,可以使用如下命令之一(磁盘上的文件不会消失,但从操作系统上看不到了)
$ umount /mnt/localdisk
$ umount /dev/vdb1
# 接下来将分区信息导出到文件,以便批量应用到集群所有机器上
$ sfdisk -d /dev/vdb > vdb.layout
下面是需要在集群集群上批量执行的脚本文件的内容
#!/bin/sh
sfdisk /dev/vdb < vdb.layout
mkfs -t ext4 /dev/vdb1
mkdir /mnt/localdisk
mount /dev/vdb1 /mnt/localdisk
更改 Docker 存储位置
在集群节点上执行下面的命令
# 暂停 docker 服务
systemctl stop docker
# 修改 docker 配置文件,更改 docker 镜像的存储位置
# 主要是将 docker 的 graph 更改为新的路径
# 如果配置文件中原来没有这一行,则需要添加上这一行
mkdir /mnt/localdisk/docker
sed -E -i "s/^.*graph.*$/ \"graph\": \"\/mnt\/localdisk\/docker\",/" /etc/docker/daemon.json
# 同步以前的镜像到新的镜像存储位置
# 以前的镜像位置就是原来 graph 的值,可以在 /etc/docker/daemon.json 中找到
# 默认是 /var/lib/docker
$ rsync -avz /export/temp/docker-storage/overlay2 /mnt/localdisk/docker
# 重启 docker 服务
$ systemctl daemon-reload
$ systemctl start docker
# 清除原来 docker 镜像占用的空间,也可以在保证 docker 服务运行正常后执行
# rm -rf /export/temp/docker-storage/overlay2
最终执行
最终,在配置了可免密登录到 node 上的 master 节点上执行上面的内容。 总结起来,在 node 上执行的下面的脚本 disk-docker.sh
#!/bin/sh
sfdisk /dev/vdb < vdb.layout
mkfs -t ext4 /dev/vdb1
mkdir /mnt/localdisk
mount /dev/vdb1 /mnt/localdisk
systemctl stop docker
mkdir /mnt/localdisk/docker
sed -E -i "s/^.*graph.*$/ \"graph\": \"\/mnt\/localdisk\/docker\",/" /etc/docker/daemon.json
rsync -avz /export/temp/docker-storage/overlay2 /mnt/localdisk/docker
systemctl daemon-reload
systemctl start docker
# rm -rf /export/temp/docker-storage/overlay2
而在 master 节点上,需要将 disk-docker.sh 和 vdb.layout 纷发到各个节点上,并远程执行,我们也通过一个脚本 nodes-disk-docker.sh 来实现。
集群中节点的 IP 列表通过使用 kubectl get no -o wide | awk /none/'{print $6}' > nodes.txt
保存在 nodes.txt 文件中。
#!/bin/sh
chmod +x disk-docker.sh
# 注意 loop 的写法,避免 sh 将后续的 ip 当作脚本的入参,导致 loop 只执行一次
for ip in $(cat nodes.txt)
do
echo $ip
scp ./disk-docker.sh root@${ip}:/root/
scp ./vdb.layout root@${ip}:/root/
ssh root@${ip} /root/disk-docker.sh
done
接下来在 master 节点执行 nohup sh nodes-disk-docker.sh > nodes-disk-docker.log 2>&1 &
就可以了。
经过以上操作就完成了对免密登录、磁盘重新分区及挂载和 docker 存储空间更改。