K8S持久化存储之基于NFS-Subdir-External-Provisioner存储组件创建的StorageClass

前言:一般 StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件制备 PV。NFS-Subdir-External-Provisioner是对 nfs-client-provisioner 的扩展,如今nfs-client-provisioner 已经不提供更新,且 nfs-client-provisioner 的 Github 仓库已经迁移到 NFS-Subdir-External-Provisioner 的仓库。本文将介绍国内环境如何合理的以NFS-Subdir-External-Provisioner组件为基础创建StorageClass。
本文会涉及几个平台使用,也会分享我安装该组件时遇到的各个坑(带星号*部分)。最后成功实现由 StorageClass 根据 PVC 的需求动态创建 PV。

一、解决国内镜像问题
NFS存储类k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner在国内的网络环境下无法使用docker pull将镜像拉取下来,而且在主流的国内镜像站里也找不到这些镜像仓库,这时候我们就需要想其他的办法来解决了,下面介绍使用阿里云构建镜像的方法配合GitHub拉取组件镜像的方法解决该问题。
1.1.1、在自己的GitHub创建一个仓库:
在这里插入图片描述
1.1.2、创建一个路径为k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner/v4.0.2/Dockerfile文件,文件内容:

FROM k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2

在这里插入图片描述
拉取该Provisioner组件镜像的命令。

1.2.1、登录阿里云,进入容器镜像服务控制台,容器列表处创建个人实例,个人实例下创建命名空间:
在这里插入图片描述
1.2.2、创建好命名空间后,就可以用该命名空间创建镜像仓库,代码源则选择绑定的GitHub上刚创建的仓库,并且勾选海外机器构建。
在这里插入图片描述
在这里插入图片描述
1.2.3、进入该镜像仓库,点击构建。添加规则使我们拉取私人镜像时可以利用GitHub的代码拉取到nfs-subdir-external-provisioner组件的源镜像。此处为了标准,上下文目录和版本号需要和GitHub上的一致,可直接复制刚GitHub创建的代码分支路径。
在这里插入图片描述
创建规则完成后,需要对规则构建,如果步骤正确时构建日志处会出现构建成功。
在这里插入图片描述
1.2.4、尝试拉取镜像。在该镜像仓库的基本信息,可直接复制公网地址,到我们国内正常联网的机器上尝试拉取镜像
在这里插入图片描述
按照阿里云的操作指南使用docker login命令登录后登录使用docker pull命令尝试拉取私人镜像
在这里插入图片描述

docker login --username=xxx registry.cn-hangzhou.aliyuncs.com
docker pull registry.cn-hangzhou.aliyuncs.com/niuma_1/nfs-subdir-external-provisioner:v4.0.2

在这里插入图片描述
发现拉取成功,说明使用GitHub+阿里云镜像构建的方法可成功在国内环境拉取国外源的镜像。

二、部署NFS-Subdir-External-Provisioner组件
2.1.1、部署该组件依赖可用的NFS服务,*本文不赘述安装NFS服务的步骤,
下文根据自己的NFS服务信息修改NFS Provisioner deploy的yaml文件内容即可,本文示例的NFS信息如下:
NFS服务器IP:192.168.113.131
服务文件路径: /data/nfs/rw
*需要K8S的所有的节点可访问该服务。

showmount -e 192.168.113.131

在这里插入图片描述

2.2.1、创建并配置RBAC的控制权限使其可以与NFS provisioner组件绑定赋予权限。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: default 
---
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
  namespace: default
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
  namespace: default
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner #关联的命名最好检查一遍
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
kubectl apply -f nfs-rbac.yaml

可顺手检查创建的SA和ClusterRole等创建的情况。
在这里插入图片描述
2.2.2、创建一个secret存放拉取镜像时的认证信息,自己私人仓库账号密码,可参照上文使用docker login时用的账号密码,*该secret需要被下文步骤部署 NFS-Subdir-External-Provisioner组件时引用到imagePullSecret中,否则会出现ImagePullBackOff。

kubectl create secret docker-registry myregistrykey --docker-server=registry.cn-hangzhou.aliyuncs.com --docker-username=xxxxxxx --docker-password=xxxxxxx --docker-email=xxxx@xx.com

在这里插入图片描述

2.2.3、部署NFS-Subdir-External-Provisioner
*注意:yaml文件中1、NFS服务IP;2、NFS文件路径,3、imagePullSecret配置

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: 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
      imagePullSecrets:  #此处引用的是上文创建的secret,携带了拉取镜像时的认证信息
        - name: myregistrykey 
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-hangzhou.aliyuncs.com/niuma_1/nfs-subdir-external-provisioner:v4.0.2 #指定的镜像地址要跟刚才创建的aliyun上的镜像仓库地址要对的上
          #imagePullPolicy: Never
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME     ## Provisioner的名称,创建storageclass时引用的制备器要和该名称保持一致
              value: nfs-client
            - name: NFS_SERVER           ## NFS服务器地址,需和valumes参数中配置的保持一致
              value: 192.168.113.131
            - name: NFS_PATH             ## NFS服务器数据存储目录,需和valumes参数中配置的保持一致
              value: /data/nfs/rw
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.113.131     ## NFS服务器地址
            path: /data/nfs/rw           ## NFS服务器数据存储目录

kubectl apply -f nfs-provisioner-deploy.yaml

创建完成后查看nfs-provisioner制备器组件的deploy和pod是否正常,保证状态正常后再去尝试创建SC。
在这里插入图片描述

2.2.4、使用nfs-provisioner创建 NFS SotageClass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storage  #SC的名称,下文的PVC可根据名称直接引用
  annotations:
    storageclass.kubernetes.io/is-default-class: "false"  ## 是否设置为默认的storageclass
provisioner: nfs-client                                   ## 动态卷分配者名称,必须和上面创建的"provisioner"变量中设置的Name一致
parameters:
  archiveOnDelete: "true"                                 ## 设置为"false"时删除PVC不会保留数据,"true"则保留数据
mountOptions:
  - hard                                                  ## 指定为硬挂载方式
  - nfsvers=4                                             ## 指定NFS版本,这个需要根据NFS Server版本号设置
kubectl apply -f nfs-storage.yaml

到该步骤成功安装SC
在这里插入图片描述

三、创建PVC和Pod用于验证SC是否正常
3.1.1、创建PVC,观察是否自动创建PV。

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nfs-sc-test-pvc
spec:
  storageClassName: nfs-storage #需要与上面创建的storageclass的名称一致
  accessModes:
    - ReadWriteOnce  #指定者可读写
  resources:
    requests:
      storage: 2Mi #容量规格
 kubectl apply -f nfs-sc-test-pvc.yaml

查看创建出来的pvc信息,观察其绑定的SC,PV的信息是否正确。
在这里插入图片描述
观察nfs服务器的共享文件夹发现,基于SC创建的PV都会在NFS服务器创建对应的文件夹,文件夹名可以跟PV名称对上。
在这里插入图片描述

3.1.2、创建一个POD绑定刚创建的PVC

apiVersion: v1
kind: Pod
metadata:
  name: test-nginx-pod
spec:
  containers:
  - image: nginx
    name: nginx-volume
    volumeMounts:
    - mountPath: /usr/share/nginx/html # 挂载到容器的目录
      name: test-pvc-volume # 挂载哪个 volume
  volumes:
  - name: test-pvc-volume
    persistentVolumeClaim:  # 关联PVC
      claimName: nfs-sc-test-pvc # 要关联到的pvc

查看Pod的描述发现已经绑定了指定的PVC在这里插入图片描述

3.2.1、查看pod的服务是否正常
尝试能否请求到刚创建的pod内的nginx服务:
在这里插入图片描述
*发现了403报错,这个是正常现象,因为挂载的目录正好覆盖了nginx服务的主页文件。

3.2.2、查看pod内的服务和nfs交互文件内容是否正常进入pod的nginx容器内部,进入 /usr/share/nginx/html,发现果然没有文件,手工尝试创建一个index.html文件:

kubectl exec -it test-nginx-pod -- sh
cd /usr/share/nginx/html
ls -l
touch index.html

在这里插入图片描述
创建完之后在nfs服务器上看共享目录内对应的pv文件夹,发现该文件被创建了:
在这里插入图片描述
最后,我们尝试在nfs服务器配置,创建写入一些内容到上文的index.html文件中,
然后再尝试请求看能否请求到相关内容:

 cd /data/nfs/rw/default-nfs-sc-test-pvc-pvc-2a2999c0-2718-4549-a287-20f863081e71
 echo  '------------I am The King of niuma--------------'  > index.html

尝试去请求pod的nginx服务,发现可以请求到刚写入的内容了:
在这里插入图片描述
文章到此结束。

参考文章:
[1]陌上荼靡(2022).无法下载外网Docker镜像的解决方案.cnblogs.检索于2024-5-2,https://www.cnblogs.com/mstmdev/p/16047954.html
[2]zuozewei(2022).Kubernetes 集群部署 NFS-Subdir-External-Provisioner 存储插件.aliyun.检索于2024-5-2,https://developer.aliyun.com/article/856853

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐