k8s集群升级(v1.19.x——>v1.20.x)后,nfs-client-provisioner工作异常:

pod状态:0/6 nodes are available: 3 pod has unbound immediate PersistentVolumeClaims.

动态PVC:一直生于pending状态

查看nfs-client-provisioner日志:

Could not construct reference to: '&v1.Endpoints{TypeMeta:v1.TypeMeta{Kind:"", APIVersion:""}, ObjectMeta:v1.ObjectMeta{Name:"", GenerateName:"", Namespace:"", SelfLink:"", UID:"", ResourceVersion:"", Generation:0, CreationTimestamp:v1.Time{Time:time.Time{wall:0x0, ext:0, loc:(*time.Location)(nil)}}, DeletionTimestamp:(*v1.Time)(nil), DeletionGracePeriodSeconds:(*int64)(nil), Labels:map[string]string(nil), Annotations:map[string]string(nil), OwnerReferences:[]v1.OwnerReference(nil), Initializers:(*v1.Initializers)(nil), Finalizers:[]string(nil), ClusterName:""}, Subsets:[]v1.EndpointSubset(nil)}' due to: 'selfLink was empty, can't make reference'. Will not report event: 'Normal' 'LeaderElection' 'nfs-client-provisioner-657d5d96c4-5g5h5_688b72ec-2dc3-11ed-a04a-06ad70053f24 stopped leading'


查资料发现,官方在k8s 1.20版本中基于对性能和统一API调用方式的初衷,移除了对SelfLink 的支持,而 nfs-provisioner 需要使用 SelfLink 特性。具体计划和原因可查看这个issue[2]KEP[3]


解决办法1:

修改apiserver配置文件,启动SelfLink功能。具体操作方法如下:

编辑文件</etc/kubernetes/manifests/kube-apiserver.yaml>,增加:- --feature-gates=RemoveSelfLink=false

apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 172.26.1.2:6443
  creationTimestamp: null
  labels:
    component: kube-apiserver
    tier: control-plane
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-apiserver
    - --feature-gates=RemoveSelfLink=false #增加
    - --advertise-address=172.26.1.2
    - --allow-privileged=true
    - --authorization-mode=Node,RBAC
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    - --enable-admission-plugins=NodeRestriction

配置重启完成后,重启apiserver.

kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml


解决办法2:

使用新的不基于SelfLink 功能的 provisioner 镜像,重新创建 nfs-provisioner.

操作参考:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/tree/master/deploy


注:NFS相关错误处理

使用NFSv4.0挂载时报错信息:mount.nfs: Operation not permitted或mount.nfs: an incorrect mount option was specified,但是使用NFSv3却可以挂载成功。


修改StorageClass,增加连接参数:nfsvers=3

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  creationTimestamp: "2020-12-04T11:40:13Z"
  name: managed-nfs-storage
  resourceVersion: "189571112"
  selfLink: /apis/storage.k8s.io/v1/storageclasses/managed-nfs-storage
  uid: 8c3960c2-70a0-4524-b701-9fce3a7268d8
mountOptions:
- nfsvers=3
- hard
- nolock
- noresvport
parameters:
  archiveOnDelete: "false"
provisioner: fuseim.pri/ifs
reclaimPolicy: Delete
volumeBindingMode: Immediate


报错信息:Output: mount.nfs: access denied by server while mounting

修改NFS Server配置,增加:insecure

[root@nfs-master ~]# cat /etc/exports
/data/k8s-nfs *(insecure,rw,async,no_root_squash)


NFS常见参数说明:
 ro:              默认选项,以只读的方式共享。
 rw:              以读写的方式共享。
 root_squash:     将客户端使用的是root用户时,则映射到NFS服务器的用户为NFS的匿名用户(nfsnobody)。
 no_root_squash:  将客户端使用的是root用户时,则映射到NFS服务器的用户依然为root用户。
 all_squash:      默认选项,将所有访问NFS服务器的客户端的用户都映射为匿名用户,不管客户端使用的是什么用户。
 anonuid:         设置映射到本地的匿名用户的UID
 anongid:         设置映射到本地的匿名用户的GID
 sync:            默认选项,保持数据同步,数据同步写入到内存和硬盘。
 sync:            异步,先将数据写入到内存,在将数据写入到硬盘。
 secure:          限制客户端只能从小于1024的tcp/ip端口连接nfs服务器(默认设置);
 insecure:        允许客户端从大于1024的tcp/ip端口连接服务器
 subtree_check:   如果共享/usr/bin之类的子目录时,强制NFS检查父目录的权限(默认) 
 no_subtree_check:和上面相对,不检查父目录权限
 wdelay:          如果多个用户要写入NFS目录,则归组写入(默认) 
 no_wdelay:       如果多个用户要写入NFS目录,则立即写入,当使用async时,无需此设置。 
 Hide:            在NFS共享目录中不共享其子目录 
 no_hide:         共享NFS目录的子目录