glusterfs/heketi更换服务器主机

glusterfs存储池三台主机逐台替换,heketi部署在存储池第一台主机上。

实验:glusterfs/heketi 更换主机、手动修改 heketi 数据库

环境信息

实验环境 软件版本
CentOS7 - linux 3.10.0-1160.el7.x86_64|OS、ARCH 其实无所谓,就是软件包不一样而已
glusterfs 8.5
heketi 9.0|提这个需求的客户环境是 heketi 9.0|TODO heketi 10.4 也应该测下
实验环境 主机 IP 主机角色 说明
10.10.101.81 glusterfs01 装有 heketi;是存储者,保有一份完整的存储数据
10.10.101.82 glusterfs02 是存储者,保有一份完整的存储数据
10.10.101.83 glusterfs-arbiter 是仲裁者,仅保有存储数据的 inode ,不包含 data
10.10.101.88 glusterfs03 代替 glusterfs01,并安装 heketi
10.10.101.89 glusterfs04 代替 glusterfs02
10.10.101.90 glusterfs05 代替 glusterfs-arbiter

主机角色:一方面用作 hostname,代替预装系统默认的 localhost.localdomain;另一方面写入 /etc/hosts 配置静态解析。在 gluster peer 建联时使用主机角色而不是主机IP。

有人说遇到过 bug,需要用 domain name 代替 ip 来做 gluster peer probe,不然后面会有 bug。

我不觉得 glusterfs8.5 有这个 bug,在最新的部署包中我就是用 ip 直接做 peer probe 的。

预估本实验面向的都是我接手 gfs 之前部署的客户机器,所以方案里还是以主机角色为主。而且确实,主机角色比 ip 更容易指代、更好理解。

前期准备

网络要求:

  • heketi 主机对存储池内所有主机 22 端口 tcp 畅通(可修改,SSH端口)
  • heketi 主机 8080 tcp 端口对外畅通(可修改,heketi 服务端口)
  • glusterfs 主机 24007 tcp 端口彼此畅通(不建议修改,glusterd 服务端口)
  • glusterfs 主机 24007 tcp 端口对 gluster-volume 挂载点主机畅通(客户端挂载 vol 时会访问 24007)
  • glusterfs 主机 brick 服务端口对 gluster-volume 挂载点主机畅通(可修改 默认 49152~60999)
# 配置免密
for i in 81 82 83 88 89 90; do
ssh-keygen -R 10.10.101.$i
ssh-copy-id -i ~/.ssh/id_ecdsa root@10.10.101.$i
done
# 批量修改 hostname
declare -A roles
roles=(
[81]="glusterfs01"
[82]="glusterfs02"
[83]="glusterfs-arbiter"
[88]="glusterfs03"
[89]="glusterfs04"
[90]="glusterfs05"
)
for i in "${!roles[@]}"; do
ssh root@10.10.101.$i "date"
ssh root@10.10.101.$i "hostnamectl set-hostname ${roles[$i]}"
echo -n "10.10.101.$i "; ssh root@10.10.101.$i "hostname"
done

模拟客户环境:安装一组 glusterfs/heketi

# 81 82 83 安装 glusterfs
yum install -y glusterfs-8.5
# 81 82 83 配置 /etc/hosts
sed -i '/glusterfs/d' /etc/hosts
echo """
10.10.101.81 glusterfs01
10.10.101.82 glusterfs02
10.10.101.83 glusterfs-arbiter
""" >> /etc/hosts
# 81 对 82 83 建联
gluster peer probe glusterfs02
gluster peer probe glusterfs-arbiter
# 81 查看握手状态
gluster peer status
gluster pool list

# 81 安装 heketi
yum install -y heketi-9.0
# 81 配置 topology
vi /etc/heketi/topology.json
alias heketix='heketi-cli --user admin --secret admin@123'
heketix topology load --json=/etc/heketi/topology.json
# 81 检查拓扑
heketix topology info | grep Free

模拟客户环境:建一个 vol 并读写

# 81 建盘
heketix volume create --size=10 --gluster-volume-options='user.heketi.arbiter true'
# ... | grep Mount
# 挂载
mkdir mt
mount -t glusterfs 10.10.101.82:vol_36d82e3d41f5d3fc15217b590f7458c9 mt
# verify
df -h mt
# 写文件
for i in {0..9}; do dd if=/dev/urandom of="mt/file-$i" bs=1M count=100; done
for i in {0..9}; do md5sum "mt/file-$i" ; done | tee mt/md5.out

image-20231227164510702

开始实验

依次安装并替换 gfs 主机 03:01 04:02 05:arbiter

更换主机上的 glusterfs 部分

  • 新主机安装 glusterfs 软件包
  • 现有 heketi 主机配置到新主机的 heketi ssh 免密(并验证)
    • 密钥路径以 /etc/heketi/heketi.json:glusterfs.sshexec.keyfile 的值为准
    • 验证:切换为 heketi 用户后使用密钥登录新主机,无需再键入密码为成功
  • 通过 heketi 将新主机纳管
    • 修改 topology.json,复制粘贴旧主机的字段,修改对应部分为新主机
  • 通过 heketi 将旧主机的磁盘设备标记为停机,删除磁盘设备,删除旧主机
    • 注意device remove会执行较长的时间,期间可通过 ssh 旧主机,执行 vgs 观察 vg 中 lv 剩余数量来确认进度。
    • 注意device remove命令返回了,只说明数据迁移成功发起了,不代表数据迁移完全做完了。
    • 注意,在确认数据迁移完全做完前,不要再remove别的磁盘设备了。
  • 将旧主机移出拓扑文件
### ssh 登录到新主机
# 新主机安装 glusterfs 软件包
yum install -y glusterfs-8.5

### ssh 登录到当前 heketi 主机
# 配置到新主机的 heketi ssh 免密|需要新主机 root 密码
ssh-copy-id -i /etc/heketi/heketi_key root@<新主机IP>
# 验证 ssh 免密
su -s /bin/bash heketi
ssh -i /etc/heketi/heketi_key root@<新主机IP>

image-20240109142224140

### ssh 登录到当前 heketi 主机
# 通过 heketi 将新主机纳管
vi /etc/heketi/topology.json
heketi-cli --user admin --secret admin@123 topology load --json /etc/heketi/topology.json
# 通过 heketi 将旧主机的磁盘设备标记为停机,删除磁盘设备,删除旧主机
heketi-cli --user admin --secret admin@123 node list
heketi-cli --user admin --secret admin@123 node info <node id>
heketi-cli --user admin --secret admin@123 device disable <device id>
heketi-cli --user admin --secret admin@123 device remove <device id>
heketi-cli --user admin --secret admin@123 device delete <device id>
heketi-cli --user admin --secret admin@123 node delete <node id>
# 将旧主机移出拓扑文件
vi /etc/heketi/topology.json

image-20240109103209579

image-20240109103320292

image-20240109104537295

确认数据迁移是否完成

# ssh 至任意一台 gluster 主机即可
# 如果 Number of Peers: 0 说明登错了,换一台
gluster peer status
# 列出所有 volume,逐个检查数据迁移状况,并保存输出到文件
# 部分情况 info summary 会耗时3分钟以上,请耐心等待
gluster v list | while read x; do gluster v heal $x info summary; done; | tee heal-status
# 检查所有 volume 的数据迁移状况
# 仅 Total Number of entries: 0 代表数据迁移成功完成
grep "Total Number" heal-status

数据迁移一直不能完成怎么办

  1. 停机业务 pod,减少对 pvc 的挂载使用可以提高迁移完成速度
  2. tail -f /var/log/glusterfs/glustershd.log 监控数据迁移日志
  3. systemctl restart glusterd 重启服务可重启数据迁移服务

最终方案:删除旧 volume,创建新 volume。

# 假如,有 brick 的数据迁移始终无法成功
Brick 10.10.101.82:/var/lib/heketi/mounts/vg_48c90966e5fd907c093fe79fce0a33c2/brick_7262e4997bb7719501d584b6b2df7d54/brick
Status: Connected
Total Number of entries: 10
Number of entries in heal pending: 10
Number of entries in split-brain: 0
Number of entries possibly healing: 0

# 登录至 brick 所在主机,10.10.101.82
ssh root@10.10.101.82

# 查询 brick 对应的 volume name
ps aux | grep brick_7262e4997bb7719501d584b6b2df7d54 | grep -Eo vol_.{32}

# 查询 volume name 对应的 pv
ssh root@<kubernetes控制面>
kubectl get pv -A -oyaml | vi -
# 在 vi 中搜索 volume name,例如 vol_36d82e3d41f5d3fc15217b590f7458c9
# 在 pv 的 claimRef.namespace claimRef.name 得知 pv 对应的 pvc

Q: 如何重置 volume
A: 重建此 pvc 即可

Q: 重建此 pvc 是否会导致数据丢失
A: 会

Q: 如何保留 pvc 中的数据并恢复到新建的 pvc 中
A:
# 请通知业务方后,确认业务 pod 已停机,再执行以下步骤
mkdir mt backup
mount -t glusterfs 10.10.101.82:vol_36d82e3d41f5d3fc15217b590f7458c9 mt
cp -avf mt/ backup
umount mt
kubectl get pvc -n test test-pvc -o yaml > pvc.yaml
# 删除字段如下:
# pv.kubernetes.io/bind-completed: "yes"
# pv.kubernetes.io/bound-by-controller: "yes"
# volumeName: pvc-29eaa00e-c5fc-4b2b-8b46-260105f6a4fc
vi pvc.yaml
kubectl delete -f pvc.yaml
kubectl create -f pvc.yaml
# 获取新建出来的 volume name,假设是 vol_9c8547f095b71251cf3d5f14d3e28d63
kubectl get pvc -n test test-pvc -o yaml | grep vol
mount -t glusterfs 10.10.101.82:vol_9c8547f095b71251cf3d5f14d3e28d63 mt
cp -avf backup/ mt
umount mt

更换主机上的 heketi 部分

如果被更换的主机上安装了 heketi,则需要执行本小节。本小节应所有主机替换都完成以后再执行。

  • 老主机 heketi 停机

  • 新主机安装 heketi

  • 拷贝 heketi 数据

  • 新主机配置到拓扑内各主机的 ssh 免密(注意,包括自己)

  • 验证 heketi 是否正常

  • 更新 k8s 集群中 stoageclass 中的 resturl,注意需要删除重建

### 登录到老主机
systemctl disable heketi --now
### 登录到新主机
# 新主机安装 heketi
yum install -y heketi-9.0

# 拷贝 heketi 数据,假设老 heketi 主机是 10.10.101.81
systemctl stop heketi
scp root@10.10.101.81:/etc/heketi/heketi.json /etc/heketi
scp root@10.10.101.81:/etc/heketi/topology.json /etc/heketi
scp root@10.10.101.81:/var/lib/heketi/heketi.db /var/lib/heketi/heketi.db

# 新主机配置到拓扑内每个主机的 ssh 免密,包括到当前主机的免密
# 例如,ssh 登录到 10.10.101.88,各主机为 10.10.101.88,10.10.101.89,10.10.101.90
ssh-keygen -t ed25519 -f /etc/heketi/heketi_key -N ""
chown heketi:heketi /etc/heketi/heketi_key
for i in 88 89 90; do
ssh-copy-id -i /etc/heketi/heketi_key.pub root@10.10.101.$i
done
systemctl start heketi

# 验证 heketi 是否正常
heketi-cli --user admin --secret admin@123 topology load --json=/etc/heketi/topology.json
[root@glusterfs03 ~]$ heketi-cli --user admin --secret admin@123 topology load --json=/etc/heketi/topology.json
Found node 10.10.101.88 on cluster fbc3d4ba741e9e3de16a0424140de9b6
Found device /dev/sdb
Found node 10.10.101.89 on cluster fbc3d4ba741e9e3de16a0424140de9b6
Found device /dev/sdb
Found node 10.10.101.90 on cluster fbc3d4ba741e9e3de16a0424140de9b6
Found device /dev/sdb
### 登录到 kubernetes 控制面
# 更新 k8s 集群中 stoageclass 中的 resturl,注意需要删除重建
kubectl get sc default -o yaml | vi -
:wq sc.yaml

kubectl delete sc default
kubectl create -f sc.yaml

image-20240109152805812

Addon

优化配置免密的过程

### 可用 ansible 代替、或通过 expect 优化「配置免密」的过程
# INFO: 用 realpath ~/.ssh/id_rsa.pub 的值代替 $keypath 再 CV
cat > exssh-copy-id << 'EOF'
#!/usr/bin/expect -f
set user [ lindex $argv 0 ]
set host [ lindex $argv 1 ]
set port [ lindex $argv 2 ]
set passwd [ lindex $argv 3 ]
spawn ssh-copy-id -i $keypath -p $port $user@$host
expect {
"yes/no" { send "yes\r"; exp_continue}
"password:" { send "$passwd\r" }
}
# interact
EOF

chmod a+x exssh-copy-id
for i in 81 82 83 88 89 90; do
ssh-keygen -R 10.10.101.$i
./exssh-copy-id root 10.10.101.$i 22 ******
done

声明/遍历 关联数组

# 声明
declare -A roles
# 初始化并设置键值对
roles=(
[81]="glusterfs01"
[82]="glusterfs02"
[83]="glusterfs-arbiter"
[88]="glusterfs03"
[89]="glusterfs04"
[90]="glusterfs05"
)
# debug print
declare -p roles
# 添加、修改键值对
roles[xx]="gxx"
declare -p roles
# 删除键为 82 的键值对
unset "roles[xx]"
declare -p roles

# ZSH 获取所有键 并遍历
for key in "${(@k)roles}"; do
echo "Key: $key, Value: ${roles[$key]}"
done

# BASH 获取所有键 并遍历
for key in "${!roles[@]}"; do
echo "Key: $key, Value: $roles[$key]"
done