K8S单机部署-06.动态持久化StorageClass(基于NFS)

转载请注明出处

相关链接



一、StorageClass是什么

Kubernetes提供了一套可以自动创建PV的机制,即:Dynamic Provisioning.而这个机制的核心在于:StorageClass这个API对象.

StorageClass对象会定义下面两部分内容:

  • PV的属性.比如,存储类型,Volume的大小等.
  • 创建这种PV需要用到的存储插件

有了这两个信息之后,Kubernetes就能够根据用户提交的PVC,找到一个对应的StorageClass,之后Kubernetes就会调用该StorageClass声明的存储插件,进而创建出需要的PV.
但是其实使用起来是一件很简单的事情,你只需要根据自己的需求,编写YAML文件即可,然后使用kubectl create命令执行即可

二、StorageClass出现的原因

在一个大规模的Kubernetes集群里,可能有成千上万个PVC,这就意味着运维人员必须实现创建出这个多个PV,此外,随着项目的需要,会有新的PVC不断被提交,那么运维人员就需要不断的添加新的,满足要求的PV,否则新的Pod就会因为PVC绑定不到PV而导致创建失败.而且通过 PVC 请求到一定的存储空间也很有可能不足以满足应用对于存储设备的各种需求

而且不同的应用程序对于存储性能的要求可能也不尽相同,比如读写速度、并发性能等,为了解决这一问题,Kubernetes 又为我们引入了一个新的资源对象:StorageClass,通过 StorageClass 的定义,管理员可以将存储资源定义为某种类型的资源,比如快速存储、慢速存储等,用户根据 StorageClass 的描述就可以非常直观的知道各种存储资源的具体特性了,这样就可以根据应用的特性去申请合适的存储资源了

三、StorageClass运行原理

在动态资源供应模式下,通过StorageClass和PVC完成资源动态绑定(系统自动生成PV),并供Pod使用的存储管理机制。
在这里插入图片描述

volumeClaimTemplates实现了pvc的自动化,StorageClass实现了pv的自动化

每个 StorageClass 都包含 provisionerparametersreclaimPolicy 字段, 这些字段会在 StorageClass 需要动态分配 PersistentVolume 时会使用到。

StorageClass 对象的命名很重要,用户使用这个命名来请求生成一个特定的类。 当创建 StorageClass 对象时,管理员设置 StorageClass 对象的命名和其他参数,一旦创建了对象就不能再对其更新。

管理员可以为没有申请绑定到特定 StorageClass 的 PVC 指定一个默认的存储类

要使用 StorageClass,我们就得安装对应的自动配置程序,比如我们这里存储后端使用的是 nfs,那么我们就需要使用到一个 nfs-client 的自动配置程序,我们也叫它 Provisioner(制备器),这个程序使用我们已经配置好的 nfs 服务器,来自动创建持久卷,也就是自动帮我们创建 PV。

    1. 自动创建的 PV 以${namespace}-${pvcName}-${pvName}这样的命名格式创建在 NFS 服务器上的共享数据目录中
    1. 而当这个 PV 被回收后会以archieved-${namespace}-${pvcName}-${pvName}这样的命名格式存在 NFS 服务器上。
      在这里插入图片描述

搭建StorageClass+NFS,大致有以下几个步骤:

  • 1.创建一个可用的NFS Serve(实际存储文件)
  • 2.创建Service Account 这是用来管控NFS provisioner在k8s中运行的权限
  • 3.创建StorageClass 负责建立PVC并调用NFS provisioner进行预定的工作,并让PV与PVC建立管理
  • 4.创建NFS provisioner(制备器)
    • 每个 StorageClass 都有一个制备器(Provisioner)用来决定使用哪个卷插件制备 PV。 该字段必须指定。
    • 主要有两个功能
      • 一个是在NFS共享目录下创建挂载点(volume)
      • 另一个则是建了PV并将PV与NFS的挂载点建立关联

常见的存储制备器
在这里插入图片描述

可以运行和指定外部制备器,这些独立的程序遵循由 Kubernetes 定义的 规范。 外部供应商的作者完全可以自由决定他们的代码保存于何处、打包方式、运行方式、使用的插件(包括 Flex)等。


代码仓库 kubernetes-sigs/sig-storage-lib-external-provisioner 包含一个用于为外部制备器编写功能实现的类库。你可以访问代码仓库 kubernetes-sigs/sig-storage-lib-external-provisioner 了解外部驱动列表。


如,NFS 没有内部制备器,可以使用外部制备器。

四、创建StorageClass

1.创建NFS服务器

可参考
K8S单机部署-04.NFS服务器搭建

2.创建Service Account

wget raw.githubusercontent.com/Simontage/k8s/main/StorageClass-demo/rbac.yaml

# 如果网络慢可以直接复制下面的内容
kubectl apply -f rbac.yaml

rbac.yaml (唯一需要修改的地方只有namespace,根据实际情况定义)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  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
    # replace with namespace where provisioner is deployed
    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
  # replace with namespace where provisioner is deployed
  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
  # replace with namespace where provisioner is deployed
  namespace: default
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

查看结果

[root@master deploy-demo]# kubectl get sa
NAME                     SECRETS   AGE
default                  1         6h30m
nfs-client-provisioner   1         7s

3.创建NFS资源的StorageClass

kubectl apply -f nfs-StorageClass.yaml

nfs-StorageClass.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
  namespace: default  # 与RBAC文件中的namespace保持一致
provisioner: k8s-nfs-storage # 这里的名称要和provisioner配置文件中的环境变量PROVISIONER_NAME保持一致
# 回收策略
reclaimPolicy: Retain
parameters:
  archiveOnDelete: "ture"  
 
  # archiveOnDelete: "false"

provisioner的名称要和provisioner配置文件中的环境变量PROVISIONER_NAME保持一致

查看结果

[root@master deploy-demo]# kubectl get StorageClass
NAME                  PROVISIONER       RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
managed-nfs-storage   k8s-nfs-storage   Delete          Immediate           false                  19s

4.创建NFS provisioner

kubectl apply -f nfs-provisioner.yaml

nfs-provisioner.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default  # 与RBAC文件中的namespace保持一致
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-client-provisioner
  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: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: k8s-nfs-storage  # provisioner名称,请确保该名称与 nfs-StorageClass.yaml文件中的provisioner名称保持一致
            - name: NFS_SERVER
              value: 192.168.21.223   # NFS Server IP地址
            - name: NFS_PATH  
              value: /middle/nfsdata   # NFS挂载卷
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.21.223  # NFS Server IP地址
            path: /middle/nfsdata     # NFS 挂载卷

查看结果

[root@master deploy-demo]# kubectl get deployments.apps,pods
NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nfs-client-provisioner   1/1     1            1           3m6s

NAME                                          READY   STATUS    RESTARTS   AGE
pod/nfs-client-provisioner-867b699cb5-nvhmx   1/1     Running   0          3m6s

五、创建Deployment测试

创建

创建pod,申明PVC进行测试

kubectl apply -f demo_nginx_deployment-sc.yaml

demo_nginx_deployment-sc.yaml

# ConfigMap存储nginx配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: demo-nginx-configmap
  labels:
    app: demo-nginx-configmap
data:
  nginx.conf: |
        user  nginx;
        worker_processes  auto;

        error_log  /var/log/nginx/error.log notice;
        pid        /var/run/nginx.pid;

        events {
              worker_connections  1024;
        }

        http {
            include       /etc/nginx/mime.types;
            default_type  application/octet-stream;
            underscores_in_headers on;

            log_format logsjson '{"@timestamp":"$time_iso8601",'
                                  '"server_addr":"$server_addr",'
                                  '"client_ip":"$remote_addr",'
                                  '"http_user_agent":"$http_user_agent",'
                                  '"server_protocol":"$server_protocol",'
                                  '"request_method":"$request_method",'
                                  '"http_host":"$host",'
                                  '"request_uri":"$request_uri",'
                                  '"upstream_addr":"$upstream_addr",'
                                  '"upstream_status":"$upstream_status",'
                                  '"upstream_response_time":"$upstream_response_time",'
                                  '"http_x_forwarded_for":"$http_x_forwarded_for",'
                                  '"http_referer":"$http_referer",'
                                  '"request_time":"$request_time",'
                                  '"request_length":"$request_length",'
                                  '"body_bytes_sent":"$body_bytes_sent",'
                                  '"status":"$status"}';

            access_log  /var/log/nginx/access.log  logsjson;

            sendfile        on;
            #tcp_nopush     on;
            keepalive_timeout  65;
            #gzip  on;

            server {
                client_max_body_size 500M;
                listen       80;

                location /demo {
                    add_header X-Server-IP $server_addr;
                    proxy_set_header Host $host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    return 200 "health check";
                }
            }
        }


---
# 申明一个PVC,指定StorageClass
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: demo-nginx-pvc
spec:
  # 指定刚才创建的 storageClassName
  storageClassName: "managed-nfs-storage"
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
      
      
---
# nginx 服务
apiVersion: v1
kind: Service
metadata:
  name: demo-nginx
  labels:
    app: demo-nginx
spec:
  type: NodePort
  ports:
  # node port 要求端口大于30000
  - nodePort: 30013
    port: 80
    targetPort: 80
    protocol: TCP
  selector:
    app: demo-nginx


---
# nginx 部署 deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-nginx
  labels:
    app: demo-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo-nginx
  template:
    metadata:
      labels:
        app: demo-nginx
    spec:
      containers:
      - name: demo-nginx
        image: docker.io/nginx:1.22.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "1Gi"
            cpu: "200m"
        volumeMounts:
            # 日志挂载
          - name: nginx-data
            mountPath: /var/log/nginx
            # 配置挂载
          - name: nginx-config
            mountPath: /etc/nginx/nginx.conf
            subPath: nginx.conf
      volumes:
      # configmap 挂载配置
      - name: nginx-config
        configMap:
          name: demo-nginx-configmap
          items:
          - key: nginx.conf
            path: nginx.conf
      # pvc 挂载日志
      - name: nginx-data
        persistentVolumeClaim: # 数据卷挂载的是pvc
          claimName: demo-nginx-pvc # 与PVC名称保持一致

当执行 kubectl apply -f demo_nginx_deployment-sc.yaml 命令之后, 发现pod一直起不来, 问题原因以及解决方案在后文 问题一

持久化验证

查看共享NFS目录(/middle/nfsdata)是否有生成文件

[root@master ~]# ll /middle/nfsdata
total 4
drwxrwxrwx 2 nfsnobody nfsnobody 4096 Jan 13 23:38 default-demo-nginx-pvc-pvc-eea7dd76-f07d-4895-b1f7-b8bac1cc10e0

# 文件规则是按照${namespace}-${pvcName}-${pvName}创建的
# 目录下正常输出了nginx的日志
[root@master ~]# ll /middle/nfsdata/default-demo-nginx-pvc-pvc-eea7dd76-f07d-4895-b1f7-b8bac1cc10e0/
total 8
-rw-r--r-- 1 nfsnobody nfsnobody  91 Jan 13 23:49 access.log
-rw-r--r-- 1 nfsnobody nfsnobody 632 Jan 13 23:39 error.log

至此Deployment动态使用动态PVC验证结束。

六、 创建Statefulset以及测试

创建

kubectl apply -f demo_nginx_deployment_sc_sts.yaml

demo_nginx_deployment_sc_sts.yaml

# nginx 服务
apiVersion: v1
kind: Service
metadata:
  name: demo-nginx-sts
  labels:
    app: demo-nginx-sts
spec:
  type: NodePort
  ports:
  # node port 要求端口大于30000
  - nodePort: 30030
    port: 80
    targetPort: 80
    protocol: TCP
  selector:
    app: demo-nginx-sts


---
# nginx 无头服务
apiVersion: v1
kind: Service
metadata:
  name: demo-nginx-headless
  labels:
    app: demo-nginx-sts
spec:
  clusterIP: None   #注意此处的值,None表示无头服务
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    app: demo-nginx-sts


---
# nginx 部署 deployment
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: demo-nginx-sts
  labels:
    app: demo-nginx-sts
spec:
  serviceName: "demo-nginx-sts"
  replicas: 2 # 两个副本
  selector:
    matchLabels:
      app: demo-nginx-sts
  template:
    metadata:
      labels:
        app: demo-nginx-sts
    spec:
      containers:
      - name: demo-nginx-sts
        image: docker.io/nginx:1.22.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "1Gi"
            cpu: "200m"
        volumeMounts:
          - mountPath: /var/log/nginx
            name: nginx-data-sts
  volumeClaimTemplates:
  - metadata:
      name: nginx-data-sts
      #annotations:
        # 低版本采用annotations这种方式指定
        #volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"   #managed-nfs-storage为我们创建的storage-class名称
    spec:
      storageClassName: managed-nfs-storage    # 指定刚才创建的 storageclass
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

查看状态

[root@master deploy-demo]# kubectl get pvc,pv,sts,svc,pod
 
NAME                                                    STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
persistentvolumeclaim/demo-nginx-pvc                    Bound    pvc-eea7dd76-f07d-4895-b1f7-b8bac1cc10e0   1Gi        RWX            managed-nfs-storage   69m
persistentvolumeclaim/k8s-nfs-pv                        Bound    k8s-nfs-pv                                 50G        RWX                                  4h31m
persistentvolumeclaim/nginx-data-sts-demo-nginx-sts-0   Bound    pvc-f343932c-12fc-4f81-90f0-35bc033ac0c2   1Gi        RWO            managed-nfs-storage   4m42s
persistentvolumeclaim/nginx-data-sts-demo-nginx-sts-1   Bound    pvc-10e6f241-e746-49db-b56a-0b53c2407635   1Gi        RWO            managed-nfs-storage   4m41s

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                     STORAGECLASS          REASON   AGE
persistentvolume/k8s-nfs-pv                                 50G        RWX            Retain           Bound    default/k8s-nfs-pv                                                       4h32m
persistentvolume/pvc-10e6f241-e746-49db-b56a-0b53c2407635   1Gi        RWO            Delete           Bound    default/nginx-data-sts-demo-nginx-sts-1   managed-nfs-storage            4m41s
persistentvolume/pvc-eea7dd76-f07d-4895-b1f7-b8bac1cc10e0   1Gi        RWX            Delete           Bound    default/demo-nginx-pvc                    managed-nfs-storage            69m
persistentvolume/pvc-f343932c-12fc-4f81-90f0-35bc033ac0c2   1Gi        RWO            Delete           Bound    default/nginx-data-sts-demo-nginx-sts-0   managed-nfs-storage            4m42s

NAME                              READY   AGE
statefulset.apps/demo-nginx-sts   2/2     2m40s

NAME                          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/demo-nginx            NodePort    10.107.196.123   <none>        80:30013/TCP   8h
service/demo-nginx-headless   ClusterIP   None             <none>        80/TCP         2m40s
service/kubernetes            ClusterIP   10.96.0.1        <none>        443/TCP        8h

NAME                                          READY   STATUS    RESTARTS      AGE
pod/demo-nginx-6b4f6f75bc-6xwml               1/1     Running   0             47m
pod/demo-nginx-6b4f6f75bc-sbkv5               1/1     Running   0             69m
pod/demo-nginx-sts-0                          1/1     Running   0             2m40s
pod/demo-nginx-sts-1                          1/1     Running   0             2m39s
pod/nfs-client-provisioner-867b699cb5-nvhmx   1/1     Running   3 (70m ago)   103m

持久化验证

查看共享NFS目录(/middle/nfsdata)是否有生成文件

# 分别生成了 sts-0 、 sts-1
# 文件规则是按照${namespace}-${pvcName}-${pvName}创建的
[root@master deploy-demo]# ll /middle/nfsdata/
total 12

drwxrwxrwx 2 nfsnobody nfsnobody 4096 Jan 14 00:43 default-nginx-data-sts-demo-nginx-sts-0-pvc-f343932c-12fc-4f81-90f0-35bc033ac0c2
drwxrwxrwx 2 nfsnobody nfsnobody 4096 Jan 14 00:43 default-nginx-data-sts-demo-nginx-sts-1-pvc-10e6f241-e746-49db-b56a-0b53c2407635


# 分别 sts-0 、 sts-1 有各自pod的日志记录
# 文件规则是按照${namespace}-${pvcName}-${pvName}创建的
[root@master deploy-demo]# ll /middle/nfsdata/*sts*
 
/middle/nfsdata/default-nginx-data-sts-demo-nginx-sts-0-pvc-f343932c-12fc-4f81-90f0-35bc033ac0c2:
total 4
-rw-r--r-- 1 nfsnobody nfsnobody    0 Jan 14 00:43 access.log
-rw-r--r-- 1 nfsnobody nfsnobody 2522 Jan 14 00:46 error.log

/middle/nfsdata/default-nginx-data-sts-demo-nginx-sts-1-pvc-10e6f241-e746-49db-b56a-0b53c2407635:
total 4
-rw-r--r-- 1 nfsnobody nfsnobody    0 Jan 14 00:43 access.log
-rw-r--r-- 1 nfsnobody nfsnobody 2319 Jan 14 00:46 error.log

七、关于StorageClass回收策略对数据的影响

1.第一种配置

archiveOnDelete: "false"  
reclaimPolicy: Delete   #默认没有配置,默认值为Delete

测试结果:
1.pod删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
2.sc删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
3.删除PVC后,PV被删除且NFS Server对应数据被删除

2.第二种配置

archiveOnDelete: "false"  
reclaimPolicy: Retain  

测试结果:
1.pod删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
2.sc删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
3.删除PVC后,PV不会别删除,且状态由Bound变为Released,NFS Server对应数据被保留
4.重建sc后,新建PVC会绑定新的pv,旧数据可以通过拷贝到新的PV中

3.第三种配置

archiveOnDelete: "ture"  
reclaimPolicy: Retain  

测试结果:
1.pod删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
2.sc删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
3.删除PVC后,PV不会别删除,且状态由Bound变为Released,NFS Server对应数据被保留
4.重建sc后,新建PVC会绑定新的pv,旧数据可以通过拷贝到新的PV中

4.第四种配置

archiveOnDelete: "ture"  
reclaimPolicy: Delete  

测试结果:
1.pod删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
2.sc删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
3.删除PVC后,PV不会别删除,且状态由Bound变为Released,NFS Server对应数据被保留
4.重建sc后,新建PVC会绑定新的pv,旧数据可以通过拷贝到新的PV中

总结:除以第一种配置外,其他三种配置在PV/PVC被删除后数据依然保留

问题一

在StorageClass使用nfs持久化存储时, 无法动态创建pvc

问题现象

当执行 kubectl apply -f demo_nginx_deployment-sc.yaml 命令之后, 发现 pod 一直起不来, 发现是因为 pod 使用的 demo-nginx-pvc 一直处于Pending, 然后进一步查看状态

[root@master deploy-demo]# kubectl get pvc
NAME             STATUS    VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS          AGE
demo-nginx-pvc   Pending                                          managed-nfs-storage   26s
k8s-nfs-pv       Bound     k8s-nfs-pv   50G        RWX                                  3h16m

查看详情描述

[root@master deploy-demo]# kubectl describe pvc demo-nginx-pvc
Name:          demo-nginx-pvc
Namespace:     default
StorageClass:  managed-nfs-storage
Status:        Pending
Volume:
Labels:        <none>
Annotations:   volume.beta.kubernetes.io/storage-provisioner: k8s-nfs-storage
               volume.kubernetes.io/storage-provisioner: k8s-nfs-storage
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:
Access Modes:
VolumeMode:    Filesystem
Used By:       demo-nginx-6b4f6f75bc-np7cz
Events:
  Type    Reason                Age               From                         Message
  ----    ------                ----              ----                         -------
  Normal  ExternalProvisioning  5s (x3 over 23s)  persistentvolume-controller  waiting for a volume to be created, either by external provisioner "k8s-nfs-storage" or manually created by system administrator

问题关键

通过kubectl describe pvc [pvc名称]描述,发现如下错误:waiting for a volume to be created, either by external provisioner "k8s-nfs-storage" or manually created by system administrator. If volume creation is delayed, please verify that the provisioner is running and correctly registered.

问题原因

在查找资料后发现,在 k8s 1.20 之后,出于对性能和统一 apiserver 调用方式的初衷,k8s 移除了对 SelfLink 的支持,而默认上面指定的 provisioner 版本需要 SelfLink 功能,因此 PVC 无法进行自动制备

解决方案一(已验证)

修改kube-apiserver,配置追加 feature-gates=RemoveSelfLink=false

# 修改kube-apiserver的配置
[root@k8sm storage]# cd /etc/kubernetes/manifests
[root@k8sm storage]# vi kube-apiserver.yaml
apiVersion: v1
···
...
    - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
    - --feature-gates=RemoveSelfLink=false # 添加这个配置

# 重启kube-apiserver.yaml
[root@k8sm manifests]# kubectl apply -f kube-apiserver.yaml

# 查看状态
# 现在pvc可以正常创建不再Pending, pod 也可以正常运行
[root@master deploy-demo]# kubectl get pods,pvc
NAME                                          READY   STATUS    RESTARTS        AGE
pod/demo-nginx-6b4f6f75bc-sbkv5               1/1     Running   0               5m28s
pod/nfs-client-provisioner-867b699cb5-nvhmx   1/1     Running   3 (6m32s ago)   38m

NAME                                   STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
persistentvolumeclaim/demo-nginx-pvc   Bound    pvc-eea7dd76-f07d-4895-b1f7-b8bac1cc10e0   1Gi        RWX            managed-nfs-storage   5m28s
persistentvolumeclaim/k8s-nfs-pv       Bound    k8s-nfs-pv   

selfLink 是什么?


selfLink:通过API访问资源自身的URL,例如一个Pod的link可能是/api/v1/namespaces/ns36aa8455/pods/sc-cluster-test-1-6bc58d44d6-r8hld

解决方案二(待验证)

使用其他 nfs-provisioner(存储制备器),不基于 SelfLink 功能的 provisioner 镜像,重新创建 provisioner 容器。
若你能科学上网,可使用这个镜像:

gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.0

国内可使用这个镜像:

registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0

转载请注明出处来源

  • 29
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,以下是使用kubeadm部署Kubernetes 1.27.4的步骤: 1. 确认k8s版本和环境:首先,确认您要部署Kubernetes版本为1.27.4,并确保您的环境满足部署要求,例如操作系统版本、CPU和内存等。 2. 创建配置文件:根据您的需求,创建Kubernetes集群的配置文件,包括证书、网络插件、镜像源等。您可以根据实际情况进行配置。 3. 安装kubeadm:在两台Ubuntu 16.04 64位双核CPU虚拟机上安装kubeadm。您可以使用以下命令安装kubeadm: ```shell sudo apt-get update sudo apt-get install -y kubeadm ``` 4. 初始化Master节点:在其中一台虚拟机上执行以下命令初始化Master节点: ```shell sudo kubeadm init --kubernetes-version=1.27.4 ``` 该命令将会初始化Kubernetes Master节点,并生成一个加入集群的命令。 5. 部署网络插件:根据您的配置文件选择网络插件,这里以flannel为例。在Master节点上执行以下命令部署flannel网络插件: ```shell kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml ``` 6. 加入Worker节点:在另一台虚拟机上执行Master节点生成的加入集群的命令,将其加入到Kubernetes集群中: ```shell sudo kubeadm join <Master节点IP>:<Master节点端口> --token <Token值> --discovery-token-ca-cert-hash <证书哈希值> ``` 请将`<Master节点IP>`、`<Master节点端口>`、`<Token值>`和`<证书哈希值>`替换为实际的值。 至此,您已成功使用kubeadm部署Kubernetes 1.27.4集群。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值