参考文档:

https://github.com/kubernetes-sigs/sig-storage-lib-external-provisioner

https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner

https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/blob/master/charts/nfs-subdir-external-provisioner/README.md

https://blog.csdn.net/weixin_71429850/article/details/125983940

https://cloud.tencent.com/developer/article/2295290

https://www.cnblogs.com/panwenbin-logs/p/17991584

https://blog.csdn.net/weixin_41020960/article/details/116134367

NFS 的安装

注意:可安装在任意服务器,需以root权限安装

 1# 安装nfs
 2yum install -y nfs-utils rpcbind 
 3
 4# 创建nfs共享目录
 5[zhangcong@master dev]$ mkdir /home/zhangcong/dev/nfs-data/k8s
 6
 7 # 授予权限
 8[zhangcong@master dev]$ chmod 777 /home/zhangcong/dev/nfs-data/k8s
 9
10# 编辑nfs配置文件(为下面k8s存储设置目录)
11cat > /etc/exports << EOF
12/home/zhangcong/dev/nfs-data/k8s *(rw,no_root_squash,sync)
13EOF
14
15# 使得配置生效
16exportfs -r
17
18# 查看生效
19exportfs
20
21# 启动rpcbind、nfs服务(手动加载NFS共享服务时,应该先启动rpcbind,在启动nfs;关闭的时候刚好顺序相反)
22systemctl restart rpcbind && systemctl enable rpcbind
23# systemctl start nfs && systemctl enable nfs
24# 上面的方式不能启动nfs,因为新版本的服务名改了;要以如下名称启动:
25systemctl start nfs-server && systemctl enable nfs-server
26
27
28# 查看rpc服务的注册情况
29rpcinfo -p localhost

关于nfs配置文件(/etc/exports)的说明:

客户机地址可以是主机名、IP地址、网段地址,允许使用“*”、“?”通配符。

rw 代表允许读写,ro 表示只读。

sync:表示同步写入到内存和硬盘中。

no_root_squash:表示当客户机以root身份访问时赋予本地root权限(默认是root_squash)

root_squash:表示客户机用root用户访问该共享目录时,将root用户映射成匿名用户。

all_squash:所有访问用户都映射为匿名用户或用户组。

async:将数据先保存在内存缓存区中,必要时才写入磁盘。

subtree_check(默认):若输出目录是一个子目录,则nfs服务器将检查其父目录的权限。

no_subtree_check:即使输出目录是一个子目录,nfs服务器也不检查其父目录的权限,这样可用提高效率。

安装nfs客户端

注意:k8s集群中的所有服务器都要安装!!!

 1[root@k8s-node3 ~]# yum install -y nfs-utils
 2
 3[root@k8s-node3 ~]# systemctl enable rpcbind.service && systemctl start rpcbind.service 
 4
 5### 测试:nfs服务是否可以正常使用
 6[root@k8s-node3 ~]# showmount -e 192.168.0.91
 7Export list for 192.168.0.91:
 8/home/zhangcong/dev/nfs-data/k8s *
 9
10### 测试:把nfs服务器的目录挂载到本地目录的/mnt
11[root@k8s-node3 ~]# mount -t nfs 192.168.0.91:/home/zhangcong/dev/nfs-data/k8s /mnt
12# 在本地挂载的目录/mnt中创建文件:
13[root@k8s-node3 ~]# echo '###这是NFS共享的目录' > /mnt/README.md
14# 在nfs服务器设置的目录下(192.168.0.91的/home/zhangcong/dev/nfs-data/k8s目录)发现已经同步了README.md文件

在k8s部署nfs动态存储

创建namespace(如果已经创建就直接跳过该步骤):

1kubectl create namespace storage

使用 helm 安装 nfs 存储:

1$ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
2$ helm install nfs nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
3    --set nfs.server=192.168.0.91 \
4    --set nfs.path=/home/zhangcong/dev/nfs-data/k8s \
5    --set storageClass.name=sc-nfs \
6    --set storageClass.defaultClass=true \
7  -n storage

说明:

参数只有nfs.server和nfs.path是必填的

1helm install nfs  \                                                      # 自定义名字
2nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \        # 源地址名字
3  --set storageClass.name=sc-nfs \                                       # storageclass名字
4  --set nfs.server=10.0.0.160 \                                          # nfs服务器地址
5  --set nfs.path=/mnt/jenkins \                                          # nfs共享目录
6  --set storageClass.defaultClass=true \                                 # 设置为默认存储
7  --set image.repository=dyrnq/nfs-subdir-external-provisioner:v4.0.2 \  # 设置为镜像
8  --set storageClass.reclaimPolicy=Delete \                              # 设置回收策略(Delete 或 Retain)
9-n storage                                                               # 指定名称空间

要注意的是,如果还要通过helm安装多个nfs动态存储,storageClass.name、storageClass.provisionerName需要重新定义。详情请查看文档。

查看安装进度:

 1[zhangcong@master nfs-data]$ kubectl get all -n my
 2NAME                                                                  READY   STATUS         RESTARTS       AGE
 3pod/demo-deployment-7b6b6b5b9-fvwzp                                   1/1     Running        3 (30h ago)    18d
 4pod/discuz-deployment-5b6d59fd75-tkdcl                                2/2     Running        24 (30h ago)   40d
 5pod/nfs-nfs-subdir-external-provisioner-848d6bc6c4qt4qz               0/1     ErrImagePull   0              59m
 6
 7NAME                              TYPE           CLUSTER-IP      EXTERNAL-IP                             PORT(S)        AGE
 8service/demo-service              NodePort       10.99.140.89    <none>                                  80:31001/TCP   18d
 9service/discuz-service            NodePort       10.108.118.95   <none>                                  80:31011/TCP   40d
10service/whoami-external-service   ExternalName   <none>          whoami-service.test.svc.cluster.local   80/TCP         49d
11
12NAME                                                              READY   UP-TO-DATE   AVAILABLE   AGE
13deployment.apps/demo-deployment                                   1/1     1            1           18d
14deployment.apps/discuz-deployment                                 1/1     1            1           40d
15deployment.apps/nfs-nfs-subdir-external-provisioner               0/1     1            0           59m
16
17NAME                                                                         DESIRED   CURRENT   READY   AGE
18replicaset.apps/demo-deployment-7b6b6b5b9                                    1         1         1       18d
19replicaset.apps/discuz-deployment-5b6d59fd75                                 1         1         1       40d
20replicaset.apps/nfs-nfs-subdir-external-provisioner-848d6bc6c4               1         1         0       59m

上面显示pod创建失败:还是无法拉取镜像的原因

修改deployment:

安装完成,查看storageclass:

1[zhangcong@master ~]$ kubectl get sc
2NAME               PROVISIONER                                         RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
3sc-nfs (default)   cluster.local/nfs-nfs-subdir-external-provisioner   Delete          Immediate           true                   16h

关于storageclass的回收策略(RECLAIMPOLICY)有两种模式:Delete模式(默认,且archiveOnDelete=true)和 Retain 模式。

  • Delete模式:需配合archiveOnDelete一起使用。

当archiveOnDelete为true时,删除PVC时,PV和NAS文件只会被重命名,不会被删除。

当archiveOnDelete为false时,删除PVC时,PV和NAS文件会被真正删除。

  • Retain模式:删除PVC时,PV和NAS文件系统不会被删除,需要您手动删除。

如果数据安全性要求高,推荐使用Retain,以免误删数据。

如果要删除上面的安装,在终端执行:

helm delete nfs -n storage

nfs 为之前install时的自定义名字

动态存储的测试

在任意namespace中创建pvc:

 1kind: PersistentVolumeClaim
 2apiVersion: v1
 3metadata:
 4  name: pvc-test
 5  namespace: default
 6spec:  
 7  storageClassName: sc-nfs # 前面创建的storageclass的名字;其实也可以不指定,因为之前已经指定了sc-nfs为默认存储
 8  accessModes:
 9    - ReadWriteOnce
10  resources:
11    requests:
12      storage: 200Mi

应用配置:

查看pvc,发现已经绑定了storageclass,并且自动创建了pv

1[zhangcong@master ~]$ kubectl get pvc -n default
2NAME       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
3pvc-test   Bound    pvc-138bc44c-6791-4c9b-915e-2da4f748aec7   200Mi      RWO            sc-nfs         11h
4
5[zhangcong@master ~]$ kubectl get pv
6NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                      STORAGECLASS   REASON   AGE
7pvc-138bc44c-6791-4c9b-915e-2da4f748aec7   200Mi      RWO            Delete           Bound    default/pvc-test           sc-nfs                  11h

创建pod并应用上面的pvc:

 1kind: Pod
 2apiVersion: v1
 3metadata:
 4  name: test-pod
 5  namespace: default
 6spec:
 7  containers:
 8  - name: test-pod
 9    image: busybox:1.28.4
10    command:
11      - "/bin/sh"
12    args:
13      - "-c"
14      - "touch /mnt/SUCCESS && exit 0 || exit 1" # 创建一个SUCCESS文件后退出
15    volumeMounts:
16      - name: nfs-pvc
17        mountPath: "/mnt"
18  restartPolicy: "Never"
19  volumes:
20    - name: nfs-pvc
21      persistentVolumeClaim:
22        claimName: pvc-test  #与上面的PVC名称保持一致

应用配置:

发现在nfs服务器的共享文件夹(/home/zhangcong/dev/nfs-data/k8s)内,已经创建SUCCESS文件

1[zhangcong@master ~]$ ll /home/zhangcong/dev/nfs-data/k8s
2总用量 0
3drwxrwxrwx 2 root root 21  4月  8 22:55 default-pvc-test-pvc-138bc44c-6791-4c9b-915e-2da4f748aec7
4
5[zhangcong@master ~]$ ll /home/zhangcong/dev/nfs-data/k8s/default-pvc-test-pvc-138bc44c-6791-4c9b-915e-2da4f748aec7/
6总用量 0
7-rw-r--r-- 1 root root 0  4月  8 22:55 SUCCESS

说明:

在nfs服务器的共享文件夹,又创建了一个子目录,作为pod的存储卷;这个子目录的命名规则是按照${namespace}-${pvcName}-${pvName}创建的。