集群节点批量分区及 docker 镜像存储空间变更

集群环境初始化

Posted by sincosmos on August 30, 2019

我们新建的 K8S 集群中,有时候部署 deployment 会发生 node 拉取镜像失败的问题,排查后发现是由于 docker 镜像的存储的磁盘空间很小,因此需要改变 docker 镜像的默认存储位置到另外一块儿磁盘上,但另外一块磁盘还没有划分分区。 为了解决该问题,我们进行以下步骤的操作。

  1. 配置 master 节点到 node 节点的免密操作
  2. 编写脚本,该脚本对 node 节点上未分区的磁盘进行分区、初始化文件系统、mount 磁盘分区到指定目录。从 master 上批量在所有 node 节点上执行该脚本,完成磁盘分区及挂载
  3. 编写脚本,该脚本更改 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 存储空间更改。