0715 跨集群etcd主备数据同步实施方案
为了提高集团云上协同业务和数据的可靠性和容灾能力,需要针对现有生产环境进行设计异地主备容灾方案。
云上协同生产环境公共组件(etcd 等)数据目前使用本地存储方式存放于集群节点上,为提高数据可用性,规划基于 drbd 技术进行跨集群数据实时同步, 将生产环境(主集群)公共组件业务数据实时同步到备集群(浪潮公有云),并在主集群故障时能够快速将负载切换到备集群,同时确保数据无丢失。
本方案以 etcd 公共组件为例,提供 etcd 生产数据切换 drbd 的具体实施步骤,以及主备切换的演练方案,为其他中间件提供统一参考。
将生产环境上基于 hostpath-provisioner 本地存储的 etcd 数据切换至 drbd 管理的同步盘上,并确保切换前后数据一致无丢失, 切换过程尽可能简单、易操作、便捷快速,降低实施风险。
生产环境首次切换中间件本地存储到 DRBD 数据盘,需要重新调度现有中间件 Pod 负载,使其落到规划有 DRBD 资源的节点上,此过程必然影响业务,导致不可用, 整个切换过程至少需要保留总计 2 个小时的操作、数据验证以及排障预留时间窗口。
生产数据切换过程中,需要拷贝已有数据到 DRBD 同步盘中,此过程要求运维操作人员严格安装方案手册执行,操作前进行数据备份,操作过程中确保数据、文件以及递归子目录权限等保持完整一致,杜绝产生任何生产数据的人为变更。
- 主备集群运行期间 DRBD 资源数据实时同步,在网络可靠条件下,DRBD 数据主备保持实时一致性;
- 主集群故障时,当需要进行备集群切换提升为临时主集群,需要人工操作介入,正常可控制到分钟级(<10min)完成切换以及中间件服务可用;
以下内容均以 10.110.21.51(主集群) 和 10.110.21.45(备集群) 上两套测试环境为例进行演示说明。
总体规划图参考此前 DRBD 数据同步验证方案。
- etcd 在主集群 common 命名空间下,以 statefulset 方式运行三副本 etcd 高可用服务;
- etcd 使用 hostpath-provisioner 本地存储插件将数据持久化在 pv 中,pv 数据落在所调度节点的
/data/vmdata/hpvolumes/pvc-xxxx目录下; /data/vmdata/hpvolumes/即 etcd 使用的 sc 中配置的本地数据目录,该目录在集群节点上挂载了一块独立数据盘/dev/sdb1;- 创建集群时,为 etcd 中间件规划的三块 20G 独占磁盘,分别位于 worker01、worker02、worker03 上的
/dev/sdc, 并且未经格式化; - etcd 三个节点落在三个 worker 节点上,但是仅通过
control-plane标签选择所有 worker 节点,未落在规划了 etcd 磁盘的节点; - 规划 etcd 磁盘的三个节点未打 etcd 相关标签;
- 未部署 drbd 组件;
- etcd 磁盘规划与主集群一致(worker01、02、03 个 20G, 盘符
/dev/sdc); - hostpath-provisioner sc 配置一致;
- hostpath-provisoner 数据盘挂载点一致;
- 节点未添加 etcd 相关标签;
- 未部署 etcd 中间件;
- 未部署 drbd 组件;
根据环境信息,需要为 etcd 三个副本规划三对 drbd 主备同步资源(盘),每一对 DRBD 资源同步其中一个 etcd 副本 Pod 的数据。
主集群 DRBD 资源规划表格如下:
| DRBD 资源名称 | 端口号 | 节点 | IP | DRBD 设备盘符 | 底层数据盘符 | 对端地址 |
|---|---|---|---|---|---|---|
| etcd0 | 7790 | worker01 | 172.16.1.1 | /dev/drbd0 | /dev/sdc | 172.16.2.1 |
| etcd1 | 7790 | worker02 | 172.16.1.2 | /dev/drbd0 | /dev/sdc | 172.16.2.2 |
| etcd2 | 7790 | worker03 | 172.16.1.3 | /dev/drbd0 | /dev/sdc | 172.16.2.3 |
备集群 DRBD 资源规划:
| DRBD 资源名称 | 端口号 | 节点 | IP | DRBD 设备盘符 | 底层数据盘符 | 对端地址 |
|---|---|---|---|---|---|---|
| etcd0 | 7790 | worker01 | 172.16.2.1 | /dev/drbd0 | /dev/sdc | 172.16.1.1 |
| etcd1 | 7790 | worker02 | 172.16.2.2 | /dev/drbd0 | /dev/sdc | 172.16.1.2 |
| etcd2 | 7790 | worker03 | 172.16.2.3 | /dev/drbd0 | /dev/sdc | 172.16.1.3 |
特别说明
- DRBD 两端默认使用节点 IP 以及节点端口号进行互联,要求主备集群两节点可通过网络直连;若无法直连,需要重新设计代理方案(不建议);
- 由于 etcd 使用的 hostpath 存储插件生产的数据目录带有 uuid 信息,无法多个节点统一配置挂载点,而现版本 drbd 组件不支持各节点差异化配置,本方案所有 drbd 资源均为手动配置,不使用组件化配置;
确认 K8S 集群控制面正常,Pod 健康无异常;
kubectl get po -A -owide | grep -vE '(.)\/\1|Comp'确认业务运行正常,数据可正常读写;
确认主备集群 DRBD 同步节点两端可互相 ping 通;
ping 172.16.2.1确认主备节点之间网络带宽满足业务吞吐量要求;
netperf -H 172.16.2.1 -l 30
为了尽可能减少因数据切换产生的业务中断时间,在主集群配置之前,首先配置备集群 DRBD 资源。
DRBD 基于 CKE 组件化部署,直接在 CKE 环境中通过 apply 对应的组件定义 (component/com) 和组件部署定义(comdeploy/cd)即可:
DRBD com yaml:
apiVersion: cie.inspur.com/v1alpha1
kind: Component
metadata:
name: drbd-9.1.7-1
namespace: kube-system
spec:
depends:
- docker
- cke-certs
deployImage: library/cke/components/drbd:9.1.7-1-20220706_145827
images:
drbd_kernel: library/cke/piraeusdatastore/drbd9-bionic:v9.1.7
drbd_utils: library/cke/piraeusdatastore/drbd-utils:v9.21.2
drbd_top: library/cke/piraeusdatastore/drbdtop:v0.2.3
version: 9.1.7-1
DRBD cd yaml:
apiVersion: cie.inspur.com/v1alpha1
kind: Comdeploy
metadata:
name: drbd-deploy
namespace: kube-system
spec:
comDependenceName: cke-dependence
component:
name: drbd
version: 9.1.7-1
nodeSelector:
- node-role.kubernetes.io/node=true
parameters:
# 脑裂处理脚本放置路径,默认执行预装通知脚本 '/usr/lib/drbd/notify-split-brain.sh root' 即向 root 用户发送邮件
split_brain_handler_path: ""
# 脑裂处理脚本内容,自定义脚本内容时必须指定路径,若路径为空则使用内置脚本而忽略此配置;
split_brain_handler_script: ""
# drbd 资源配置采用 yaml 格式,此例中留空,后续采取手动方式配置资源;
resources: ""
注意 apply 有先后顺序,先创建组件(com)定义,在创建组件部署(cd)定义:
kubectl apply -f drbd-com.yaml
kubectl apply -f drbd-cd.yaml
查看组件部署状态,变为 Running 后即部署完成:
root@master01:~# kubectl get cd -n kube-system drbd-deploy
NAME COMPONENT VERSION STATUS REASON AGE NODES
drbd-deploy drbd 9.1.7-1 Running 3d15h ["master01","master02","master03","worker01","worker02","worker03","worker04","worker05","worker06","worker07","worker08","worker09","worker10","worker11","worker12","worker13","worker14","worker15","worker16","worker17","worker18","worker19","worker20","worker21"]
每个 drbd 资源对应一个资源配置文件,通常存放于 /etc/drbd.d/ 目录下,以 .res 作为文件后缀。
- 在 CKE 组件化部署的 drbd 中,会部署开机自启逻辑,实现 drbd 资源开机自动加载,官方原生的 drbd 资源不具备开机自动加载能力。
当手动配置 drbd 资源时,需要将 drbd 资源配置文件命名为
/etc/drbd.d/cke_<资源名>.res格式即可。 - 官方原生的 drbd 也不会记录资源的主备角色,即重启后,并不会自动变为主角色,需要手动介入。CKE 组件同样设计了自动提升主角色的能力,在本方案场景中,主集群在通常情况下需要保持主角色,即使单个节点重启后,应当自动加载资源,并恢复主角色,持续提供服务,只有在确认主集群故障需要切换备集群时,才需要处理原主集群中 drbd 资源主角色的自动提升配置。
- 当手动配置 DRBD 资源时,要使用 CKE 重启保持主角色的能力 ,需要创建(touch)一个
/etc/drbd.d/cke_<资源名>.primary的空文件,以标记当前节点上该资源为持久化的主角色。
以备节点 worker01 上的 drbd 配置文件为例,以 3.2 中规划的资源配置参数填充。
此配置文件仅包含必要的参数,如果需要配置其他参数请参考 《DRBD 9 用户手册》。
# cat /etc/drbd.d/cke_etcd0.res
# resource 后面跟资源名称,即 drbdadm 命令行操作使用的名称
resource etcd0 {
net {
# 同步复制协议
protocol C;
# 不允许双主
allow-two-primaries no;
}
options {
# 不允许自动提升为主角色
auto-promote no;
}
# 节点名称,与 hostname 一致
on worker01 {
# drbd 生成的设备盘符
device /dev/drbd0;
# 底层物理盘符
disk /dev/sdc;
# 本地 ip + 端口号
address 172.16.2.1:7790;
# 节点 id, 自己分配控制,每个节点唯一,取值范围 1~32,一旦分配生效,不可随意更改
node-id 2;
}
# 对端节点名称,可自定义,无需与实际节点 hostname 一致
on remote_172.16.1.1 {
# 对端地址+端口号,必须直通,若走代理则配置代理地址和端口号
address 172.16.1.1:7790;
# 对端 drbd 设备盘符
device /dev/drbd0;
# 对端底层物理盘符
disk /dev/sdc;
# 对端节点 id
node-id 1;
}
}
特别说明
- drbd 资源配置文件 res 格式文件无严格的缩进验证,与 yaml 不同;
- 注释以 # 号开头;
- 每一行配置严格以英文分号结尾,不可缺省;
- 部分公共基础配置参数存放于
/etc/drbd.d/global_common.conf全局配置文件中;
将 DRBD 资源文件准备就绪,确保路径格式为 /etc/drbd.d/cke_<资源名>.res 。
创建元数据(首次纳管底层数据盘时需要执行):
drbdadm create-md etcd0挂载数据盘:
drbdadm attach etcd0检查状态
drbdadm status etcd0
此时备集群的 drbd 资源由于无法连接对端资源(主集群还未配置),status 返回状态通常会显示 StandAlone 。
备集群 drbd 资源默认保持备角色(secondary)。
按照以上步骤分别配置备集群 3 个节点上的 etcd 资源。
etcd 的 pod 需要落在指定配置了 drbd 资源的三个节点上,必须为三个节点配置 etcd 专属标签:
kubectl label ckenode -n kube-system worker01 worker02 worker03 cnp.inspurcloud.cn/etcd-tenant=true
特别说明
- 在 CKE 集群中,K8S 节点标签统一由 CKE 节点资源 CKENode 管理,尽量避免直接在 k8s node 上修改标签,需要修改 ckenode 标签,会自动同步至对应的 k8s node.
在 etcd chart 的 values.yaml 中,也需要确认 nodeSelector 中,包含上一步我们为 etcd 节点添加的标签:
nodeSelector:
cnp.inspurcloud.cn/control-plane: "true"
cnp.inspurcloud.cn/etcd-tenant: "true"
helm install common-etcd -n common ./etcd
等待并确认部署完成,etcd pod 运行正常,节点调度符合预期:
kubectl get pod -n common -owide | grep etcd
备集群作为备用节点,使用的数据来自于 drbd 从主集群同步来的数据,因此备集群无需保留数据,在备集群角色状态下,也无需运行工作负载, 同时为了便于后续数据切换,需要直接将 etcd 副本数缩容为 0。
kubectl scale sts -n common common-etcd-etcd --replicas=0
如本方案第三章节所属,进行主集群实施时,必须在合适的时间窗口进行,并保持敏捷稳健原则,确保快速平稳迁移。
主集群迁移实施计划内耗时预估为 10~30min (不含 drbd 部署配置操作)
特别说明
- 在主集群(生产环境)进行 drbd 组件部署和资源配置,对业务无影响,可在常规运维窗口提前进行部署配置,减少迁移时间。
主集群进行变更操作前,同样需要首先确认集群和网络状态,参考本方案第五章节。
主集群 drbd 部署配置参考本方案第六章节,按照第四章节规划的节点和参数进行配置。
特别说明
- 在组件部署这一步,同样需要提前完成同 6.4.1 步骤中一样的节点 label 配置,为中间件重新规划好对应的标签。
配置完主集群三个节点 drbd 资源后,将主节点 drbd 资源提升为主角色,并进行主备资源连接:
drbdadm primary etcd0
drbdadm connect etcd0
首次建立连接时,将进行数据初始化同步,可以通过 drbdadm status 或者 drbdtop 查看同步进度。
同步速率受磁盘大小以及网络带宽决定。
当同步完成后,status 应显示两端均为 UpToDate 状态:
# drbdadm status
etcd0 role:Primary
disk:UpToDate
remote_172.16.2.1 role:Secondary
peer-disk:UpToDate
将主集群三个 etcd 节点均设置为主角色并完成数据同步。
完成同步后,如果数据盘为裸盘,需要在迁移数据之前,首先进行格式化:
mkfs.ext4 /dev/drbd0
进行 etcd 迁移之前,确保访问 etcd 的相关业务暂停或者具备离线条件。
在测试验证环境中(非生产),为了验证迁移数据可靠性,建议写入测试数据,在迁移后对比验证,确保无数据损失。
向 etcd 中测试数据 key 中写入当前时间戳数据:
kubectl exec -n common -it common-etcd-etcd-0 -- etcdctl put test-ts "$(date +%s.%N | cut -b 1-14)"
此步骤预计耗时 1min
将 etcd 副本数缩容为 0,确保业务数据在迁移期间无变更。
kubectl scale sts -n common common-etcd-etcd --replicas=0
此步骤预计耗时 6min
待 etcd 缩容完成后,进行数据备份。
首先查询获取 etcd 使用的本地卷 pv 的名称,后面需要根据 pv 名称查找对应的数据目录:
kubectl get pv | grep etcd登陆到 etcd 所在节点上,以 保留文件原始信息 的形式,将 etcd pv 数据目录拷贝到本地节点的备份目录:
cp -a /data/vmdata/hpvolumes/pvc-16e9053a-27e7-4479-80a5-0ea2381974e6/ /data/vmdata/backup/拷贝完成后再次确认备份数据与原始数据文件大小、hash、权限一致。
三个节点均以此方式进行数据备份。
此步骤预计耗时 5min
由于现有生产环境 etcd 所在节点不在规划的 drbd 同步节点,使用的 pv 已经固定在其他节点,迁移 etcd 节点必须迁移 pv, 最简便快捷的方式就是重建 etcd 。
首先删除现有 etcd chart:
helm uninstall -n common common-etcd删除旧 etcd 的 pvc:
kubectl delete pvc -n common data-common-etcd-etcd-0 data-common-etcd-etcd-1 data-common-etcd-etcd-2确认 pvc 和 pv 都删除后,确认节点上组件 label 以及 chart 中节点选择器都已配置好,能够按预期调度到 drbd 同步节点,重建 etcd chart:
kubectl get node -l cnp.inspurcloud.cn/etcd-tenant=true helm install common-etcd -n common ./etcd等待 etcd pod 重建完成并 running, 再次缩容为 0, 准备数据回迁:
kubectl scale sts -n common common-etcd-etcd --replicas=0
此步骤预计耗时 6min
重建后的 etcd 完成缩容后,进行原生产数据的回迁操作,需要将原所在节点对应的三个副本的备份数据目录,通过 scp 等方式迁移到新节点上 drbd 的同步盘中。
首先通过 kubectl 查询新创的的 etcd pv 名称,以确认对应节点上的 pv 数据目录;
将 drbd 数据盘
/dev/drbd0挂载到 etcd 新建的 pv 目录下,掩蔽原始目录:
mount /dev/drbd0 /data/vmdata/hpvolumes/pvc-66129604-196d-4d2d-9a6b-d4b2eeca9553
- 三个 etcd 同步节点完成同样的挂载操作。
此步骤预计耗时 4min
通过 scp 方式,将原备份节点上对应 etcd 副本的数据目录下的文件内容,拷回新节点上,drbd 同步盘的挂载点即新 pv 目录下:
scp -rp -P 6233 -i /etc/kubernetes/ckemonitor/private_key /data/vmdata/backup/ 172.16.1.1:/data/vmdata/hpvolumes/pvc-66129604-196d-4d2d-9a6b-d4b2eeca9553/
特别说明
- 数据拷贝回迁时同样需要注意保留数据文件的原始信息和权限等,使用 scp 时可添加
-rp参数递归并保留原始信息; - 通过 scp 拷贝目录时需要注意目录层级要与原 pv 目录层级一致(避免出现类似 /data/vmdata/pvc-xxxx-xxx/pvc-xxxx-xxxx 目录嵌套问题);
此步骤预计耗时 5min
三个 etcd 节点数据迁移完成后,确认 drbd 同步状态正常后,扩容 etcd 服务,恢复至 3 副本:
kubectl scale sts -n common common-etcd-etcd --replicas=3待 etcd 运行正常后,查询业务数据,确保与迁移前一致,无数据丢失;*测试环境中可查询迁移前写入的测试数据,是否能查询到且一致:
kubectl exec -n common -it common-etcd-etcd-0 -- etcdctl get test-ts恢复业务;
写入 CKE drbd 资源主角色标记:
touch /etc/drbd.d/cke_etcd0.res.primary配置 etcd pv 目录开机自动挂载
TODO 由于各节点目录不一致,无法走 CKE DRBD 组件的逻辑进行自动目录挂载,需重新确认方案
测试环境演练可直接进行节点宕机;
生产环境演练时,可通过停止 etcd 服务来演练;
模拟故障前,参考 7.3.1 步骤向 etcd 写入测试数据。
此步骤预计耗时 2min
登陆备集群 etcd 同步节点,将 3 各节点上的 drbd 资源提升为主角色, 并通过 status 查看资源状态,主集群宕机失联不影响备集群 drbd 提升为主角色:
drbdadm primary etcd0
drbdadm status etcd0
此步骤预计耗时 2min
参考 7.5.1 步骤,挂载 drbd 同步盘到 pv 目录。
此步骤预计耗时 1min
直接将 etcd 副本数扩容为 3 副本:
kubectl scale sts -n common common-etcd --replicas=3
此步骤预计耗时 3min
参考 7.5.3 步骤在备集群查询故障前写入的测试数据,验证是否一致。
待补充