环境:

背景: 采用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)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
服务自检命令
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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
二、配置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
- 1.
- 2.
创建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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
创建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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
创建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"
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
创建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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
#部署
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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
三、编写redis yaml 文件
root@k8s-master1:~ # mkdir /root/redis
root@k8s-master1:~ # cd /root/redis
- 1.
- 2.
编写 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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
编写 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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
编写 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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
四、测试,访问
使用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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.

查看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
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
(3)验证数据,可发现源redis的数据已全部复现
