1:为什么要使用nfs-csi
在很早之前,我们讲过一个使用nfs-subdir-external-provisioner来做nfs存储的方法,但是那个方法其实是根据不太规范的Pod使用volume挂载nfs实现的,并且它并非使用了标准的k8s存储接口,我们都知道csi(container storage interface)才是k8s标准的存储接口,所以就衍生出来我们使用csi的方案,其实基于CSI的存储已经有很多了,我们可以去如下github查看
# 基于NFS的CSI:https://github.com/kubernetes-csi/csi-driver-nfs
# 基于SMB的CSI:https://github.com/kubernetes-csi/csi-driver-smb
# 基于local的CSI:https://github.com/kubernetes-csi/csi-driver-host-path
# 当然还有更多的云厂商和一些开源的存储工具它们也提供了存储的方案,大家可以去选一选,这个在CNCF都可以找到几个,在这里我们列出几个
# Ceph
# CubeFS
# Longhorn
# Curve
# Juicefs
# Rook
# 这些都是开源的一些存储,它们同样也都支持CSI的方式,所以,我们后期的存储肯定是按照规范来了,所以nfs-subdir-external-provisioner一定不是长久之计,所以就有了现在的这篇文章
2:如何部署NFS-CSI
1:下载nfs-csi源码
[root@k-m-1 ~]# git clone https://github.com/kubernetes-csi/csi-driver-nfs.git
2:进入项目
[root@k-m-1 nfs-csi]# cd csi-driver-nfs
3:安装nfs-csi
[root@k-m-1 csi-driver-nfs]# ./deploy/install-driver.sh
Installing NFS CSI driver, version: master ...
serviceaccount/csi-nfs-controller-sa unchanged
serviceaccount/csi-nfs-node-sa unchanged
clusterrole.rbac.authorization.k8s.io/nfs-external-provisioner-role unchanged
clusterrolebinding.rbac.authorization.k8s.io/nfs-csi-provisioner-binding unchanged
csidriver.storage.k8s.io/nfs.csi.k8s.io unchanged
deployment.apps/csi-nfs-controller unchanged
daemonset.apps/csi-nfs-node unchanged
NFS CSI driver installed successfully.
# 看到NFS CSI driver installed successfully证明安装好了,然后我们来看看这个程序
[root@k-m-1 ~]# kubectl get pod -n kube-system -l app=csi-nfs-node
NAME READY STATUS RESTARTS AGE
csi-nfs-node-644bb 3/3 Running 0 9s
[root@k-m-1 ~]# kubectl get pod -n kube-system -l app=csi-nfs-controller
NAME READY STATUS RESTARTS AGE
csi-nfs-controller-767f94977c-h7kb5 4/4 Running 0 12s
# 看到Pod之后我们基本就算是部署好了,但是我们不能直接使用CSI,而是利用StorageClass来调用它,然后我们来创建这个StorageClass
[root@k-m-1 nfs-csi]# cd csi-driver-nfs/deploy/example
# 在这个目录下有一个storageclass-nfs.yaml,这里我们只需要更改如下内容
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs
annotations:
# 此操作是1.25的以上的一个alpha的新功能,是将此storageclass设置为默认,这个在前面文章有讲过
storageclass.kubernetes.io/is-default-class: "true"
# 此处指定了csidrivers的名称
provisioner: nfs.csi.k8s.io
parameters:
# NFS的Server
server: 10.0.0.11
# NFS的存储路径
share: /data
# csi.storage.k8s.io/provisioner-secret is only needed for providing mountOptions in DeleteVolume
# csi.storage.k8s.io/provisioner-secret-name: "mount-options"
# csi.storage.k8s.io/provisioner-secret-namespace: "default"
reclaimPolicy: Delete
volumeBindingMode: Immediate
mountOptions:
# 这里不只可以配置nfs的版本
- nfsvers=4.1
下面是关于parameters的一些参数
参数名称 |
意义 |
示例 |
强制参数 |
默认值 |
server |
NFS的服务地址 |
10.0.0.11 |
YES |
|
share |
NFS共享的路径 |
/ |
YES |
|
subDir |
NFS 共享下的子目录 |
|
NO |
|
mountPermissions |
挂载的文件夹权限。默认值为,如果设置为非零,驱动程序将在挂载后执行0 chmod |
|
NO |
不存在则创建 |
onDelete |
删除卷时,如果目录是retain |
delete(默认值), retain |
NO |
delete |
基本上我们保持默认就OK了,涉及不到太多的功能,我们只需要将上面的YAML的parameters的server和share改成自己的nfs的地址和path就OK了
# 查看StorageClass,然后测试
[root@k-m-1 example]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs (default) nfs.csi.k8s.io Delete Immediate false 11h
# 部署如下YAML资源对象
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
command:
- "/bin/bash"
- "-c"
- set -euo pipefail; while true; do echo $(date) >> /mnt/nfs/outfile; sleep 1; done
volumeMounts:
- name: data
mountPath: /mnt/nfs
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
# 根据上面资源的说明会生成一个outfile,然后我们去持久化的PVC下看看
[root@k-m-1 ~]# kubectl get pod,pvc
NAME READY STATUS RESTARTS AGE
pod/nginx-0 1/1 Running 0 63s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/data-nginx-0 Bound pvc-1bdd032a-c7ee-4e03-8b81-fc04e4ea2038 1Gi RWO nfs 63s
[root@k-m-1 ~]# ls /data/pvc-1bdd032a-c7ee-4e03-8b81-fc04e4ea2038/
outfile
# 这就说明,我们的CSI和StorageClass配置完成了,那么这就是我们用NFS-CSI替换nfs-subdir-external-provisioner的方法了,另外这个NFS的CSI它还支持snapshot功能,这个功能其实也算是个新功能了,在这个NFS-CSI也是支持,也不在我们的正常使用范围内,不过我们既然用到了它,我们就讲一下吧
3:NFS-CSI快照功能
我们如果要使用此功能,那么我么你需要安装一下这个CRD和控制器,还有Controller
# 部署CRD和Controller
[root@k-m-1 nfs-csi]# cd csi-driver-nfs/deploy
[root@k-m-1 deploy]# kubectl apply -f crd-csi-snapshot.yaml -f rbac-snapshot-controller.yaml -f csi-snapshot-controller.yaml
customresourcedefinition.apiextensions.k8s.io/volumesnapshots.snapshot.storage.k8s.io created
customresourcedefinition.apiextensions.k8s.io/volumesnapshotclasses.snapshot.storage.k8s.io created
customresourcedefinition.apiextensions.k8s.io/volumesnapshotcontents.snapshot.storage.k8s.io created
serviceaccount/snapshot-controller created
clusterrole.rbac.authorization.k8s.io/snapshot-controller-runner created
clusterrolebinding.rbac.authorization.k8s.io/snapshot-controller-role created
role.rbac.authorization.k8s.io/snapshot-controller-leaderelection created
rolebinding.rbac.authorization.k8s.io/snapshot-controller-leaderelection created
deployment.apps/snapshot-controller created
[root@k-m-1 deploy]# kubectl get pod -A -l app=snapshot-controller
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system snapshot-controller-546868dfb4-r879h 1/1 Running 0 50s
kube-system snapshot-controller-546868dfb4-rvhqc 1/1 Running 0 50s
[root@k-m-1 deploy]# kubectl api-resources | grep snapshot
volumesnapshotclasses vsclass,vsclasses snapshot.storage.k8s.io/v1 false VolumeSnapshotClass
volumesnapshotcontents vsc,vscs snapshot.storage.k8s.io/v1 false VolumeSnapshotContent
volumesnapshots vs snapshot.storage.k8s.io/v1 true VolumeSnapshot
# OK这样就部署好了,我们可以根据官方去看看这个API如何使用
地址:https://kubernetes.io/docs/concepts/storage/volume-snapshots/
# 部署snapshotclass资源
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: csi-nfs-snapclass
driver: nfs.csi.k8s.io
deletionPolicy: Delete
[root@k-m-1 nfs-csi]# cd csi-driver-nfs/deploy/example
[root@k-m-1 example]# kubectl apply -f snapshotclass-nfs.yaml
volumesnapshotclass.snapshot.storage.k8s.io/csi-nfs-snapclass created
[root@k-m-1 example]# kubectl get vsclass
NAME DRIVER DELETIONPOLICY AGE
csi-nfs-snapclass nfs.csi.k8s.io Delete 60s
# 我们来快照一下上面NFS的PVC
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: nginx-pvc-snapshot
spec:
# 指定vsclass的名称
volumeSnapshotClassName: csi-nfs-snapclass
# 指定pvc资源名称
source:
persistentVolumeClaimName: data-nginx-0
[root@k-m-1 example]# kubectl apply -f snapshot-nfs-dynamic.yaml
volumesnapshot.snapshot.storage.k8s.io/nginx-pvc-snapshot created
[root@k-m-1 example]# kubectl get vs
NAME READYTOUSE SOURCEPVC SOURCESNAPSHOTCONTENT RESTORESIZE ......
nginx-pvc-snapshot true data-nginx-0 7577 ......
[root@k-m-1 example]# ls /data/snapshot-be2a23d0-4dc4-46fc-a619-56f340f09299/
pvc-1bdd032a-c7ee-4e03-8b81-fc04e4ea2038.tar.gz
[root@k-m-1 snapshot-be2a23d0-4dc4-46fc-a619-56f340f09299]# tar xf pvc-1bdd032a-c7ee-4e03-8b81-fc04e4ea2038.tar.gz
[root@k-m-1 snapshot-be2a23d0-4dc4-46fc-a619-56f340f09299]# ls
outfile pvc-1bdd032a-c7ee-4e03-8b81-fc04e4ea2038.tar.gz
# 我们备份好了之后我们可以去看看配置的csi的地址,里面会有一个snapshot的目录,然后里面是一个以PVC打包的tar.gz的文件,这个文件内就是快照下来的数据,这也就是我们要的一个快照功能,当然我们删除了这个资源之后,快照的文件也会跟着删除
[root@k-m-1 ~]# kubectl delete -f nfs-csi/csi-driver-nfs/deploy/example/snapshot-nfs-dynamic.yaml && ls /data
volumesnapshot.snapshot.storage.k8s.io "nginx-pvc-snapshot" deleted
pvc-1bdd032a-c7ee-4e03-8b81-fc04e4ea2038
# 然而这里面我们要知道的是,snapshot创建出来之后会随之创建一个声明周期管理的资源叫做VSC,这个资源主要包含如下信息
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotContent
metadata:
creationTimestamp: "2023-08-10T20:58:26Z"
finalizers:
- snapshot.storage.kubernetes.io/volumesnapshotcontent-bound-protection
generation: 1
name: snapcontent-dbc9d70e-7c1b-4d51-bc56-567b702cde9a
resourceVersion: "241853"
uid: 1d8dc380-cbf3-4084-83ee-339ff23ef833
spec:
deletionPolicy: Delete
driver: nfs.csi.k8s.io
source:
volumeHandle: 10.0.0.11#data#pvc-1bdd032a-c7ee-4e03-8b81-fc04e4ea2038##
volumeSnapshotClassName: csi-nfs-snapclass
volumeSnapshotRef:
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
name: nginx-pvc-snapshot
namespace: default
resourceVersion: "241843"
uid: dbc9d70e-7c1b-4d51-bc56-567b702cde9a
status:
creationTime: 1691701106274486295
readyToUse: true
restoreSize: 10643
snapshotHandle: 10.0.0.11#data#snapshot-dbc9d70e-7c1b-4d51-bc56-567b702cde9a#snapshot-dbc9d70e-7c1b-4d51-bc56-567b702cde9a#pvc-1bdd032a-c7ee-4e03-8b81-fc04e4ea2038
这个资源其实就是快照的一些详细信息,然后主要我们要知道的是,有了快照,怎么恢复呢?下面就是恢复数据的方法
4:使用NFS-CSI恢复备份的快照
# 找到要备份的名称
[root@k-m-1 ~]# kubectl get vs
NAME READYTOUSE SOURCEPVC SOURCESNAPSHOTCONTENT RESTORESIZE SNAPSHOTCLASS .....
nginx-pvc-snapshot true data-nginx-0 10643 csi-nfs-snapclass ......
# 创建新的PVC从快照恢复数据
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: restore-nginx-pvc
spec:
# 从这里指定快照
dataSource:
name: nginx-pvc-snapshot
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
# 创建新的PVC并检查数据
[root@k-m-1 ~]# kubectl apply -f restore-nginx-pvc.yaml
persistentvolumeclaim/restore-nginx-pvc created
# 检查新的PVC是否创建
[root@k-m-1 ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-nginx-0 Bound pvc-1bdd032a-c7ee-4e03-8b81-fc04e4ea2038 1Gi RWO nfs 86m
restore-nginx-pvc Bound pvc-e4fb65b5-5898-4cd1-a0ad-7200864fef54 10Gi RWO nfs 9s
# 查看新的PVC的数据
[root@k-m-1 ~]# ls /data/
pvc-1bdd032a-c7ee-4e03-8b81-fc04e4ea2038/ pvc-e4fb65b5-5898-4cd1-a0ad-7200864fef54/ snapshot-dbc9d70e-7c1b-4d51-bc56-567b702cde9a/
# 查看快照内容
[root@k-m-1 ~]# ls /data/pvc-e4fb65b5-5898-4cd1-a0ad-7200864fef54/
outfile
# OK那么这就是基本上快照备份和恢复的功能啦,当然,我们也可以用于迁移存储,比如从nfs迁移到其他存储,这些都是可以的,当然我们需要知道一个道理,PVC是支持克隆功能的,但是这个功能也是需要CSI支持的,也就是从一个存在的PVC将数据克隆到另一个PVC,但是这个克隆操作是不可以跨命名空间的,这一点我们需要明白,下面我们来看看
5:克隆PVC
# 查看PVC
[root@k-m-1 ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-nginx-0 Bound pvc-1bdd032a-c7ee-4e03-8b81-fc04e4ea2038 1Gi RWO nfs 95m
restore-nginx-pvc Bound pvc-e4fb65b5-5898-4cd1-a0ad-7200864fef54 10Gi RWO nfs 9m9s
# 我们的pvc在default的名称空间,我们将其克隆到其他命名空间
# 创建一个新的namespace
[root@k-m-1 ~]# kubectl create ns clone-namespace
namespace/clone-namespace created
# 创建PVC克隆Default的内的restore-nginx-pvc的数据
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: clone-of-default-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
# 此值一定要大于或者等于需要克隆的PVC,否则无法创建
storage: 10Gi
dataSource:
kind: PersistentVolumeClaim
name: restore-nginx-pvc
# 创建此PVC
[root@k-m-1 ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
clone-of-default-pvc Bound pvc-478731d8-f389-4d4f-a11a-5802d299ace8 10Gi RWO nfs 9s
data-nginx-0 Bound pvc-1bdd032a-c7ee-4e03-8b81-fc04e4ea2038 1Gi RWO nfs 107m
restore-nginx-pvc Bound pvc-e4fb65b5-5898-4cd1-a0ad-7200864fef54 10Gi RWO nfs 21m
# 查看克隆的数据
[root@k-m-1 ~]# ls /data/pvc-478731d8-f389-4d4f-a11a-5802d299ace8/
outfile
# 可以看到一模一样的,那么这就是克隆PVC的功能,这就是NFS-CSI的基本功能了,其他更高级的功能,我们还可以去参考最上面我给出的几个开源存储,它们会基于CSI开发更多的功能,这个大家可以自己去探索了