迁移 Zeabur 集群

我之前的 Zeabur 集群是独立跑在一台物理机上的,物理机相比云服务器的劣势之一就是底层存储的数据安全性 —— 云服务器的硬盘通常是由云服务商保证了安全性不同,物理硬盘坏了就是坏了

而不幸的是,不久前我就遇到了…… 所有数据差点消失,幸亏坏的盘并没有完全坏,以只读方式还能读(只是不能写)算是挽留了我的数据

但那以后我就一直在思考怎么保证数据安全,经过数个不同的方案研究,我最终的选择是 —— 将整机移动到 PVE 中 然后在 PVE 的底层使用 RAID 1 硬盘

方案敲定,行动开始 —— 我整个的迁移不太具有可复制性,因此写一篇完整的「迁移指南」确实不太有意义,但中间确确实实遇到了一些小问题,我觉得记录下来还是比较有价值的

💡 我两台机器(原 Zeabur 物理机和新的在 PVE 里面装的虚拟机):

  1. 在同一个机房
  2. 都是用的 RHEL 系的系统
  3. 内部文件系统都是 LVM + xfs

将 PVE 的硬盘改成 RAID1

我的 PVE 并不是在安装时就直接做好 RAID1 的,因此保证安全性的第一点是将 PVE 的硬盘改成 RAID1

⚠️ 需要注意的是,RAID 只是冗余,不是备份也无法替代备份

这次我的迁移也顺便把备份加上了,但备份又是一个较大的话题,因此本文不会写备份相关的内容,如果未来有机会我会单独写一篇文章,不过可以顺便说一嘴的是,我选用的备份方案是 Velero

我没有阵列卡,那么硬盘改 RAID 就只能是通过软 RAID 来组,在 Linux 下组软 RAID 有两种办法,一是利用 mdadm 组 RAID,另一种则是用 lvm 组 RAID;二者各有优劣,我为了灵活性选择了 lvm 的方案 —— 我现在是 2 块 1TB 的硬盘,使用 lvm 的话后面扩容可以很方便的通过加 1 块 2TB 的硬盘来得到完整的 2TB 可用 RAID1 空间,而如果不用 lvm 虽然也能实现但相对来说更加麻烦,且有难以避免的 degrade 时段

哦对,还有,做冗余不能只将数据做冗余,也要考虑引导,都是老步骤,复制下 ELF 分区、重做下 grub 引导,没什么值得说的,有什么问题问问 ChatGPT 它应该能相当完美的回答。

假设我们现在的环境是:原有的数据卷 /dev/sda3、原有的 VG pve、原有的 LV pve/root /pve/swap pve/data、新的数据卷 /dev/sdb3

首先将新的数据卷转换为 PV pvcreate /dev/sdb3 然后将它加入至 VG vgextend pve /dev/sdb3

pve/root 转换为 RAID1 十分简单:一行命令 lvconvert --type raid1 -m1 pve/root /dev/sda3 /dev/sdb3 搞定

pve/swap 是个 swap 分区,没有做 RAID1 的必要,我们跳过

难点来到了 pve/data 这个逻辑卷 —— 它不是一个普通的 LV 而是一个 Thin Pool,如果我们直接执行 lvconvert --type raid1 -m1 pve/data /dev/sda3 /dev/sdb3 LVM 会报错 Operation not permitted on LV pve/data type thinpool.

可以认为 Thin Pool 是一个「逻辑逻辑卷」,它事实上分成了 meta 和 data 两部分(通过 lvs -a 命令可以看到,它是用 pve/data_tmetapve/data_tdata 组合而成的),所以我们说是对它做 RAID1 但事实上想做的是对它底层依赖的 meta 和 data 做 RAID1 —— 这样,Thin Pool 本身和从这个 Thin Pool 所分配出去的子 LV 也都是 RAID1 了。

所以我们要做的是,将它的底层数据卷转换为 RAID1 即可:

1
2
lvconvert --type raid1 -m1 pve/data_tmeta /dev/sda3 /dev/sdb3
lvconvert --type raid1 -m1 pve/data_tdata /dev/sda3 /dev/sdb3

然后等待 lvs -a 的输出中 Cpy%Sync 列变为 100% 即为 RAID 转换完成。

哦对,还有一件事情,虽然示例中我用的另一块盘也是 SATA 盘做例子,但事实上我的另一块盘是 NVME 的,因此我上面说的「pve/swap 不用做 RAID1」之外,我其实还将 pve/swap 给移动到了新的盘上

将 LV 从一个 PV 移动到另一个 PV 的命令:pvmove -n pve/swap /dev/sda3 /dev/nvme0n1p3

迁移方案的选择

物理机迁移到 PVE 最直接的方法就是直接做整盘磁盘镜像然后导入,这种方案没什么可说的,也是最简单的

但是基于下面几个原因

  1. 我想换个系统,原来的系统是 CentOS Stream,嗯…… 不太适合一个稳定的环境使用
  2. 原来的系统在装 Zeabur 之前还装了一些别的东西,现在已经不需要了
  3. 我所有有价值的数据全都在 k3s 里面了,其实只要迁移 k3s 数据就行,而且我也想试试到底怎么迁移下集群,都要迁移哪些数据
  4. 我讨厌 Live CD 带的 Bash 的体验,特别是我可能还得用 IPMI 的 Remote Console 而不是自己的本地终端 SSH 过去
  5. 我原来其实也不是一块硬盘,而是两块硬盘组的 LVM 卷,两块盘都有数据,整盘迁移还得在 live cd 版系统里面折腾下加载 LVM
  6. 我原来物理机的启动用的 UEFI,但新的跑在虚拟机里面的引导用的 BIOS
  7. 整机迁移我也得迁移完去 PVE 里面改各种网卡、硬盘的映射什么的,也不容易
  8. 嗯…… 我没有一块多余的足够大的盘让我存这么大的磁盘镜像了 = =

我最后放弃了整盘迁移的方案,而是选择 rsync 拷贝 k3s 相关的数据:

  1. 在 Zeabur 中添加一个新的 Dedicated Server 让它为我们安装 k3s 的相关内容
  2. 安装好以后,执行 /usr/local/bin/k3s-killall.sh 停止整个集群、删除给 zeabur 用的 ssh key、在 zeabur 中删除这个服务器
  3. 利用 rsync 拷贝所有集群需要的数据
  4. 启动 k3s 服务,耐心等待它把原来所有的镜像下好
  5. 登录 zeabur 面板,执行一次 Reinstall Zeabur Service

将 ufw 换成 firewalld

我之前使用的防火墙时 ufw,它简单易用,但有一个非常重要的缺陷:只要 k8s 暴露的端口,它没办法阻止

因此,趁着这次,换回 firewalld 了;根据 Zeabur 的说明和 k3s 文档,需要执行下面的内容放行相关流量

1
2
3
4
5
6
7
8
9
10
11
12
13
firewall-cmd --permanent --zone=public --add-service=ssh    # 22
firewall-cmd --permanent --zone=public --add-service=http # 80
firewall-cmd --permanent --zone=public --add-service=https # 443

firewall-cmd --permanent --zone=public --add-port=4222/tcp
firewall-cmd --permanent --zone=public --add-port=6443/tcp
firewall-cmd --permanent --zone=public --add-port=30000-32767/tcp
firewall-cmd --permanent --zone=public --add-port=30000-32767/udp

firewall-cmd --permanent --zone=trusted --add-source=10.42.0.0/16
firewall-cmd --permanent --zone=trusted --add-source=10.43.0.0/16

firewall-cmd --reload

注:我个人不建议放开 30000-32767 —— 我询问过 Zeabur 支持人员,不放开这些端口不会影响 Zeabur 本身的能力,只是非 http 类型的端口映射无法被访问。Zeabur 会默认将所有端口都暴露到公网,部分端口所对应的服务可能有安全问题,所以我的建议是不要添加 30000-32767 两台规则,而仅在确实需要访问映射的端口时再添加

注 2:如果你是基于你自己需要的目的去访问内部服务(如数据库、Redis),我非常不建议你将这些服务暴露到公网,而是应当使用 zproxy 通过代理访问这些内部服务(当然,你需要将 zproxy 本身使用的端口放开)

不停机更换 IP

zeabur 和 k3s 本身对于「本机 IP 」有一定的偏好,如果要改的话比较麻烦,所以简单起见,我的选择是:

假设原机器 IP 1.1.1.1,现在新的机器 IP 2.2.2.2,我将两个机器的 IP 对调下就好了

云主机换个 IP 轻轻松松,物理机换个 IP 就很麻烦,特别是远程物理机换 IP(好吧,其实可以直接登录 IPMI 在 Remote console 里面改 IP 的,但我们当这个不存在)

不过挺好的一点是,我可以通过引入一个新的临时 IP 让这两台机器都不离线的情况下对调下 IP

💡 我这两台机器在同一个内网、网关相同、DNS 相同,都是手动指定的 IP 没有使用 DHCP

假设两台机器的网卡都是 eno1、临时 IP 是 3.3.3.3

流程是:

  1. 虽然和换 IP 的流程没关系,但是建议先执行 /usr/local/bin/k3s-killall.sh 把整个机器的 k3s 停掉
  2. 在原机器(1.1.1.1)执行 nmcli con mod eno1 +ipv4.addresses "3.3.3.3/24" && nmcli dev reapply eno1 让这个机器有 1.1.1.1 和 3.3.3.3 两个 IP
  3. 通过 3.3.3.3 登录原机器(1.1.1.1 + 3.3.3.3),执行 nmcli con mod eno1 -ipv4.addresses "1.1.1.1/24" && nmcli dev reapply eno1 让这台机器只剩下 3.3.3.3 一个 IP
  4. 登录新机器(2.2.2.2)执行 nmcli con mod eno1 +ipv4.addresses "1.1.1.1/24" && nmcli dev reapply eno1 让这个机器有 1.1.1.1 和 2.2.2.2 两个 IP
  5. 通过 1.1.1.1 登录新机器(2.2.2.2 + 1.1.1.1)执行 nmcli con mod eno1 -ipv4.addresses "2.2.2.2/24" && nmcli dev reapply eno1 让这台机器只剩下 1.1.1.1 一个 IP
  6. 通过 3.3.3.3 登录原机器,执行 nmcli con mod eno1 +ipv4.addresses "2.2.2.2/24" && nmcli dev reapply eno1 让这个机器有 2.2.2.2 和 3.3.3.3 两个 IP
  7. 通过 2.2.2.2 登录原机器(2.2.2.2 + 3.3.3.3)执行 nmcli con mod eno1 -ipv4.addresses "3.3.3.3/24" && nmcli dev reapply eno1 让这台机器只剩下 2.2.2.2 一个 IP
  8. 好了,现在原机器 IP 变成了 2.2.2.2、新机器 IP 则变成了 1.1.1.1 —— 对调完成

🤷 显得繁琐了点,但其实不难

利用 rsync 迁移数据

主要有两部分的信息我们需要迁移

  • Zeabur 连接集群所用的 SSH 凭据
  • 集群本身的各种配置、数据

我们需要用 rsync 同步下面的文件/目录到新的集群:

  • /etc/rancher/k3s k3s 配置及连接集群的凭证
  • /var/lib/rancher/k3s/server/db/ k3s 数据库
  • /var/lib/rancher/k3s/server/token k3s 内部授权 token
  • /var/lib/rancher/k3s/storage 使用的 local volume 的存储路径

同步时使用的命令为(在原机器上执行)

1
2
3
4
5
6
7
8
9
10
11
P=/etc/rancher/k3s # 依次使用上面所需要同步的路径
NEW=2.2.2.2 # 新机器的 IP 地址

# 同步数据
rsync -aHAX --numeric-ids --info=progress2 \
--delete --delete-delay \
$P \
root@$NEW:$P

# 恢复 SELinux 属性(如果需要的话)
ssh root@$NEW "restorecon -RF $P || true"

在启动前,删掉下面的目录(k3s 启动时会自动重新创建)

  • /var/lib/rancher/k3s/server/cred
  • /var/lib/rancher/k3s/server/tls

合并卷容量

我为虚拟机分配了 512GB 的硬盘,但我没想到的是我使用的 Automatic Disk Partition 竟然将绝大多数空间给了 /home 导致我迁移数据一半告诉我没空间了 = =

幸好,虽然这个奇怪的硬盘分区有点烦人,但 RHEL 系一律使用 LVM —— 它也只是个 LV 而已!简简单单,删掉这个 LV 把空间匀给 root 就好了

对了,删除 /home 挂载点要记得改 /etc/fstab,不然下次系统可能启动不起来

更新 node

因为 Zeabur 不允许同一个 IP 有两个 Dedicated Server 出现,所以安装的过程中是使用了一个新的 IP 装的

在迁移完,如果想用回原来的 IP,需要修改 /etc/systemd/system/k3s.service.env 文件里面的 K3S_NODE_NAME

然后启动起来看看 kubectl get nodes,如果还有原来的 IP 的 Node,删了就好

Pod 扩容

我数据迁移完一启动各种飙红,仔细一看原来是 Pod 数量超限(默认 110),需要修改 kubelet 配置

/var/lib/rancher/k3s/agent/etc/kubelet.conf.d 目录下,创建一个 01-max-pods.conf ,里面写

1
2
3
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
maxPods: 1000

然后执行 systemctl restart k3s 就好

哦对,这个其实我之前就改过,但是迁移的时候漏了,你可以看看原来机器的 /var/lib/rancher/k3s/agent/etc/kubelet.conf.d 目录下有没有除了 00-k3s-defaults.conf 以外的文件,有的话最好前面 rsync 的时候直接一起迁移了,省事