K8S部署Redis单节点Rdb数据持久化故障演练恢复
环境:

背景: 采用NFS存储卷的方式 持久化存储redis 需要保存的文件
一、部署NFS服务器
#服务器安装nfs服务,提供nfs存储功能 1、安装nfs-utils yum install nfs-utils (centos) 或者 apt-get install nfs-kernel-server (ubuntu) 2、启动服务 systemctl enable nfs-server systemctl start nfs-server 3、创建共享目录完成共享配置 mkdir /home/nfs #创建共享目录 4、编辑共享配置 vim /etc/exports #语法格式: 共享文件路径 客户机地址(权限) #这里的客户机地址可以是IP,网段,域名,也可以是任意* /home/nfs *(rw,async,no_root_squash) 服务自检命令 exportfs -arv 5、重启服务 systemctl restart nfs-server 6、本机查看nfs 共享目录 #showmount -e 服务器IP地址 (如果提示命令不存在,则需要yum install showmount) showmount -e 127.0.0.1 /home/nfs * 7、客户端模拟挂载[所有k8s的节点都需要安装客户端] [root@master-1 ~]# yum install nfs-utils (centos) 或者 apt-get install nfs-common (ubuntu) [root@master-1 ~]# mkdir /test [root@master-1 ~]# mount -t nfs 172.16.201.209:/home/nfs /test #取消挂载 [root@master-1 ~]# umount /test二、配置PV 动态供给(NFS StorageClass),创建pvc
#部署NFS实现自动创建PV插件: 一共设计到4个yaml 文件 ,官方的文档有详细的说明。
https://github.com/kubernetes-incubator/external-storage


创建rbac.yaml 文件
root@k8s-master1:pvc # cat rbac.yaml kind: ServiceAccount apiVersion: v1 metadata: name: nfs-client-provisioner --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner rules: - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner namespace: default roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner rules: - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io创建deployment.yaml 文件
#官方默认的镜像地址,国内可能无法下载,可以使用 image:
fxkjnj/nfs-client-provisioner:latest
#定义NFS 服务器的地址,共享目录名称
root@k8s-master1:pvc # cat deployment.yaml apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner --- kind: Deployment apiVersion: apps/v1 metadata: name: nfs-client-provisioner spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner image: fxkjnj/nfs-client-provisioner:latest volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: fuseim.pri/ifs - name: NFS_SERVER value: 172.16.201.209 - name: NFS_PATH value: /home/nfs volumes: - name: nfs-client-root nfs: server: 172.16.201.209 path: /home/nfs创建class.yaml
# archiveOnDelete: "true" 表示当PVC 删除后,后端数据不直接删除,而是归档
root@k8s-master1:pvc # cat class.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: managed-nfs-storage provisioner: fuseim.pri/ifs # or choose another name, must match deployments env PROVISIONER_NAME parameters: archiveOnDelete: "true"创建pvc.yaml
#指定storageClassName 存储卷的名字
# requests:
storage: 100Gi 指定需要多大的存储
#注意,这里pvc ,我们创建在redis 命名空间下了,如果没有redis 还需要先创建才行, kubectl create namespace redis
root@k8s-master1:pvc # cat pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-redis namespace: redis spec: storageClassName: "managed-nfs-storage" accessModes: - ReadWriteMany resources: requests: storage: 100Gi #部署 root@k8s-master1:pvc # kubectl apply -f . #查看存储卷 root@k8s-master1:pvc # kubectl get sc NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE managed-nfs-storage fuseim.pri/ifs Delete Immediate false 25h #查看pvc root@k8s-master1:pvc # kubectl get pvc -n redis NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nfs-redis Bound pvc-8eacbe25-3875-4f78-91ca-ba83b6967a8a 100Gi RWX managed-nfs-storage 21h三、编写redis yaml 文件
root@k8s-master1:~ # mkdir /root/redis root@k8s-master1:~ # cd /root/redis编写 redis.conf 配置文件,以configmap 的方式挂载到容器中
# require 配置redis 密码
#save 5 1 ,表示 每5秒有一个key 变动 就写入到 dump.rdb 文件中
# appendonly no ,表示下次可以使用dump.rdb 来恢复 redis 快照的数据
# 注意namespace 为redis
root@k8s-master1: redis# cat redis-configmap-rdb.yml kind: ConfigMap apiVersion: v1 metadata: name: redis-config namespace: redis labels: app: redis data: redis.conf: |- protected-mode no port 6379 tcp-backlog 511 timeout 0 tcp-keepalive 300 daemonize no supervised no pidfile /data/redis_6379.pid loglevel notice logfile "" databases 16 always-show-logo yes save 5 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename dump.rdb dir /data replica-serve-stale-data yes replica-read-only yes repl-diskless-sync no repl-diskless-sync-delay 5 repl-disable-tcp-nodelay no replica-priority 100 requirepass 123 lazyfree-lazy-eviction no lazyfree-lazy-expire no lazyfree-lazy-server-del no replica-lazy-flush no appendonly no appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-load-truncated yes aof-use-rdb-preamble yes lua-time-limit 5000 slowlog-log-slower-than 10000 slowlog-max-len 128 latency-monitor-threshold 0 notify-keyspace-events "" hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-size -2 list-compress-depth 0 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 stream-node-max-bytes 4096 stream-node-max-entries 100 activerehashing yes client-output-buffer-limit normal 0 0 0 client-output-buffer-limit replica 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz 10 dynamic-hz yes aof-rewrite-incremental-fsync yes rdb-save-incremental-fsync yes编写 redis-deployment.yml
#注意namespace 为redis
root@k8s-master1: redis# cat redis-deployment.yml apiVersion: apps/v1 kind: Deployment metadata: name: redis namespace: redis labels: app: redis spec: replicas: 3 selector: matchLabels: app: redis template: metadata: labels: app: redis spec: # 进行初始化操作,修改系统配置,解决 Redis 启动时提示的警告信息 initContainers: - name: system-init image: busybox:1.32 imagePullPolicy: IfNotPresent command: - "sh" - "-c" - "echo 2048 > /proc/sys/net/core/somaxconn && echo never > /sys/kernel/mm/transparent_hugepage/enabled" securityContext: privileged: true runAsUser: 0 volumeMounts: - name: sys mountPath: /sys containers: - name: redis image: redis:5.0.8 command: - "sh" - "-c" - "redis-server /usr/local/etc/redis/redis.conf" ports: - containerPort: 6379 resources: limits: cpu: 1000m memory: 1024Mi requests: cpu: 1000m memory: 1024Mi livenessProbe: tcpSocket: port: 6379 initialDelaySeconds: 300 timeoutSeconds: 1 periodSeconds: 10 successThreshold: 1 failureThreshold: 3 readinessProbe: tcpSocket: port: 6379 initialDelaySeconds: 5 timeoutSeconds: 1 periodSeconds: 10 successThreshold: 1 failureThreshold: 3 volumeMounts: - name: data mountPath: /data - name: config mountPath: /usr/local/etc/redis/redis.conf subPath: redis.conf volumes: - name: data persistentVolumeClaim: claimName: nfs-redis - name: config configMap: name: redis-config - name: sys hostPath: path: /sys编写 redis-service.yml
#注意namespace 为redis
#部署 root@k8s-master1:~/kubernetes/redis# kubectl get pod -n redis NAME READY STATUS RESTARTS AGE redis-65f75db6bc-5skgr 1/1 Running 0 21h redis-65f75db6bc-75m8m 1/1 Running 0 21h redis-65f75db6bc-cp6cx 1/1 Running 0 21h root@k8s-master1:~/kubernetes/redis# kubectl get svc -n redis NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE redis-front NodePort 10.0.0.169 <none> 6379:36379/TCP 22h四、测试,访问
使用redis 客户端工具,写入几个KEY 测试


删除pod,在自动新建pod后,查询键值是否存在
root@k8s-master1:~# kubectl get pods -n redis NAME READY STATUS RESTARTS AGE redis-65f75db6bc-5skgr 1/1 Running 0 5d20h redis-65f75db6bc-75m8m 1/1 Running 0 5d20h redis-65f75db6bc-cp6cx 1/1 Running 0 5d20h root@k8s-master1:~# kubectl delete -n redis pod redis-65f75db6bc-5skgr pod "redis-65f75db6bc-5skgr" deleted #删除pod后,根据副本数,又重新拉取新的pod生成 root@k8s-master1:~# kubectl get pods -n redis NAME READY STATUS RESTARTS AGE redis-65f75db6bc-tnnxp 1/1 Running 0 54s redis-65f75db6bc-75m8m 1/1 Running 0 5d20h redis-65f75db6bc-cp6cx 1/1 Running 0 5d20h
查看nfs共享目录下是否存在 dump.rdb

五、故障演练恢复
(1)数据备份
源redis配置有持久化,直接拷贝持久化目录下的dump.rdb
直接到持久化的目录下,拷贝走dump.rdb 文件
源redis不支持持久化,则进入容器生成dump.rdb并拷出
进入容器:kubectl exec -it redis-xxx /bin/bash -n redis
进入redis命令台:redis-cli
密码认证:auth 123
保存数据,生成dump.rdb文件:save
退出redis命令台:quit
退出容器:exit
从容器中取出数据到本地:kubectl cp -n redis Pod_Name:/data/dump.rdb ./
传输至远程主机:scp dump.rdb root@目标服务器:/目录
(2)数据恢复
停止redis,直接删除创建的deployment 拷贝dump.rdb至目标redis的持久化目录下(注:将覆盖目标redis的数据) 重启pod:kubectl apply -f redis-deployment.yml #拷贝持久化目录下的dump.rbd文件 到root 下 cp dump.rdb /root #停止redis,也就是删除deployment root@k8s-master1:~/kubernetes/redis# kubectl delete -f redis-deployment.yml deployment.apps "redis" deleted root@k8s-master1:~/kubernetes/redis# kubectl get pods -n redis No resources found in redis namespace. #拷贝dump.rdb至目标redis的持久化目录下 cp /root/dump.rdb /home/nfs/redis-nfs-redis-pvc-8eacbe25-3875-4f78-91ca-ba83b6967a8a #重启pod root@k8s-master1:~/kubernetes/redis# kubectl apply -f redis-deployment.yml deployment.apps/redis created root@k8s-master1:~/kubernetes/redis# kubectl get pods -n redis NAME READY STATUS RESTARTS AGE redis-65f75db6bc-5jx4m 0/1 Init:0/1 0 3s redis-65f75db6bc-68jf5 0/1 Init:0/1 0 3s redis-65f75db6bc-b9gvk 0/1 Init:0/1 0 3s root@k8s-master1:~/kubernetes/redis# kubectl get pods -n redis NAME READY STATUS RESTARTS AGE redis-65f75db6bc-5jx4m 1/1 Running 0 20s redis-65f75db6bc-68jf5 1/1 Running 0 20s redis-65f75db6bc-b9gvk 1/1 Running 0 20s(3)验证数据,可发现源redis的数据已全部复现

扫一扫,关注我们