环境:
背景: 采用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
- root@k8s-master1:~ # mkdir /root/pvc
- root@k8s-master1:~ # cd /root/pvc
创建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 deployment's 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的数据已全部复现