Longhorn跨AZ实现存储高可用
longhorn基础组件功能及其作用这里就不做介绍了
方案一
- Longhorn跨AZ的高可用的就是一个PVC的replicas 均匀打散的不同的AZ区域之间,这样当某个AZ挂掉后,engine会立即使用另外一个数据副本,并重建这个副本,但是
目前的关键点是如何将replica均匀打散到不同的AZ区域
- 为保证最大程度上的跨AZ数据高可用,这里列出关于longhorn关键参数(仅供参考)
shell
# replica-soft-anti-affinity
是否允许replica跑在使用pv的节点上
# default-replica-count
设置pv数据副本个数
# default-data-locality
是否允许replica跑在使用pv的节点上
# auto-salvage
当所有副本挂掉,时候允许longhorn找出可用的副本
# auto-delete-pod-when-volume-detached-unexpectedly
如果启用,当Longhorn卷意外分离(例如Kubernetes升级、Docker重启或网络断开)时,Longhorn将自动删除由控制器管理的工作负载pod。通过删除pod,其控制器将重新启动pod, Kubernetes将处理卷的重新连接和重新挂载
# disable-scheduling-on-cordoned-node
禁止在cordon节点安排replica
# `replica-zone-soft-anti-affinity` 实现跨AZ高可用关键参数
允许将卷的新副本调度到与现有健康副本相同区域中的节点。不属于任何Zone的节点将被视为属于同一个Zone。注意Longhorn依赖于标签拓扑。topology.kubernetes.io/zone=<Zone name of the node>
方案二
-
使用longhorn的backup/restore功能,但是随着数据量的增加,RTO时间具体需要多久待测试,且由于backup是定时或某个时刻手动触发的,RPO大小取决于备份完成后到发生故障这段时间具体产生了多少数据。且用户是否能容忍丢失这个数据量?
-
验证略
方案一验证
- 验证跨区域高可用(
这里我们用topology.kubernetes.io/zone来模拟不同的zone
) - Longhorn需要开启:
replica-zone-soft-anti-affinity参数,实现replica跨AZ数据同步
- 这里仅验证replica在某个AZ down是否可用,某个AZ内replica down了,实测是会重构replica,这里不做验证了
shell
# 查看k8s节点
╰─ kubectl get nodes -o custom-columns=NAME:.metadata.name,LABELS:.metadata.labels
NAME LABELS
k8s-master-1 map[beta.kubernetes.io/arch:arm64 beta.kubernetes.io/os:linux kubernetes.io/arch:arm64 kubernetes.io/hostname:k8s-master-1 kubernetes.io/os:linux]
k8s-node-1 map[beta.kubernetes.io/arch:arm64 beta.kubernetes.io/os:linux kubernetes.io/arch:arm64 kubernetes.io/hostname:k8s-node-1 kubernetes.io/os:linux]
k8s-node-2 map[beta.kubernetes.io/arch:arm64 beta.kubernetes.io/os:linux kubernetes.io/arch:arm64 kubernetes.io/hostname:k8s-node-2 kubernetes.io/os:linux]
k8s-node-3 map[beta.kubernetes.io/arch:arm64 beta.kubernetes.io/os:linux kubernetes.io/arch:arm64 kubernetes.io/hostname:k8s-node-3 kubernetes.io/os:linux]
# 设置节点zone
kubectl label nodes k8s-master-1 k8s-node-1 topology.kubernetes.io/zone=one --overwrite
kubectl label nodes k8s-node-2 k8s-node-3 topology.kubernetes.io/zone=two --overwrite
# 测试YAML
╰─ cat mysql.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
namespace: devops
spec:
storageClassName: longhorn
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
namespace: devops
spec:
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: docker.io/library/mysql:8.2
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumes:
- name: data
persistentVolumeClaim:
claimName: mysql-pvc
---
通过上图我们可以发现:
- 我们事先打的zone标签,longhorn识别了
- 我们在创建mysql后,查看pv信息可以发现,
replica分布在二个不同的ZONE区域
shell
# 生成1000条数据
cat > 1.sql <<"EOF"
CREATE DATABASE `test_bai`;
USE `test_bai`;
CREATE TABLE `app_user`(
`id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` VARCHAR(50) DEFAULT '' COMMENT '用户名称',
`email` VARCHAR(50) NOT NULL COMMENT '邮箱',
`phone` VARCHAR(20) DEFAULT '' COMMENT '手机号',
`gender` TINYINT DEFAULT '0' COMMENT '性别(0-男 : 1-女)',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`age` TINYINT DEFAULT '0' COMMENT '年龄',
`create_time` DATETIME DEFAULT NOW(),
`update_time` DATETIME DEFAULT NOW(),
PRIMARY KEY (`id`)
)ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT='app用户表';
SET GLOBAL log_bin_trust_function_creators=TRUE;
DELIMITER $$
CREATE FUNCTION mock_data()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000;
DECLARE i INT DEFAULT 0;
WHILE i < num DO
INSERT INTO app_user(`name`,`email`,`phone`,`gender`,`password`,`age`)
VALUES(CONCAT('用户',i),'2548928007qq.com',CONCAT('18',FLOOR(RAND() * ((999999999 - 100000000) + 1000000000))),FLOOR(RAND() * 2),UUID(),FLOOR(RAND() * 100));
SET i = i + 1;
END WHILE;
RETURN i;
END;
SELECT mock_data();
EOF
# 导入数据
bash-4.4# mysql -uroot -ppassword < 1.sql
mysql: [Warning] Using a password on the command line interface can be insecure.
mock_data()
1000
将k8s-node-3/k8s-node-2节点关机(模拟zone-two down,mysql目前也跑在这个zone
)
shell
# 等待controller-manager驱逐mysql后,在zone-one启动mysql
╰─ kubectl get pods -n devops -o wide | grep mysql
mysql-7bc9bc8b55-g7jn8 1/1 Running 0 118s 172.16.1.85 k8s-node-1 <none> <none>
# mysql 调度到k8s-node-1后,查询数据量大小
bash-4.4# mysql -uroot -ppassword -e "use test_bai; select count(*) from app_user;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----------+
| count(*) |
+----------+
| 1000 |
+----------+
通过上述测试我们可以发现
- 当zone-two down后,pv的replica被标志为失败,且会在zone-one找一个节点去复制pv的replica来保证replica=2(
即使我们配置了replica不能在同一个zone
) - 数据量大小也一致(
未发生数据丢失
),这里仅做了小数据验证
注意:节点异常->apiserver感知->controller-manager驱逐mysql是存在一段间隔时间的(取决于controller-manager和kubelet上报节点状态信息间隔等参数),这段时间实际上是无法访问的