T O P

[资源分享]     一个恢复CSI挂载信息的解决方法

  • By - 楼主

  • 2022-05-29 16:06:08
  • 一个恢复CSI挂载信息的解决方法

    问题描述

    之前有做过一个华为OBS 的CSI插件,其基本运作原理如下图所示。CSI插件Pod挂载了主机的/var/lib/kubelet/pods目录,当创建挂载Pvc的业务Pod时,CSI插件会启动一个s3fs进程,该进程用于远程连接s3服务,将bucket(也即Pvc)挂载到/var/lib/kubelet/pods中的对应Pod目录下(一般为/var/lib/kubelet/pods/ /volumes/ kubernetes.io~csi/ /mount ),然后由kubelet挂载到业务Pod中。

    image

    该插件有个问题,就是当CSI插件重启之后,会丢失调内部负责远程连接s3服务的s3fs进程,因此会导致业务Pod内部挂载目录失效,访问/var/lib/kubelet/pods/ /volumes/ kubernetes.io~csi/ /mount 目录会出现Transport endpoint is not connected的问题。此时为了让业务Pod能够正常访问,需要重启业务Pod,但这种方式很不优雅。

    解决思路

    为了解决Transport endpoint is not connected问题,首先需要恢复s3fs进程,但恢复进程依赖几个数据:Pvc的名称、Pod的uid、s3服务的地址以及访问使用的AK/SK等。有两种方式可以保存这类数据:

    1. 在CSI插件正常运行过程中,将元数据保存到s3服务,其实就是将s3服务作为一个元数据库使用。但这种方式可能存在元数据被误删以及元数据和系统不一致的情况
    2. 在CSI插件启动后使用client-go动态获取集群中的相关数据

    此次采用了第二种方式,执行思路为:

    1. 获取所有命名空间下的Pvc(allPvcs)
    2. allPvcs中找到Pvc的metadata.annotations.volume.beta.kubernetes.io/storage-provisioner 为目标storageclass的Pvc(targetPvcs)
    3. 获取挂载了上述targetPvcs的pod(targetPods)
    4. 找到targetPods的uid(targetUid)
    5. 拼接挂载路径/var/lib/kubelet/pods/<targetUid>/volumes/<targetUid>kubernetes.io~csi/<targetPvc-name>/mount
    6. 找到targetPvcsspec.storageClassName,进而找出负责该Pvc的storageclass(targetStorageclass)
    7. targetStorageclassparameters找到相关的信息,最主要的是保存访问s3服务的AK/SK的secret(targetSecret)
    8. targetSecret中找到AK/SK
    9. 执行挂载

    上述步骤的主要目的就是找出挂载路径以及s3服务的访问信息。

    实施过程

    在完成编码之后,经验证发现/var/lib/kubelet/pods/<targetUid>/volumes/<targetUid>kubernetes.io~csi/<targetPvc-name>/mount挂载成功,进入该目录之后可以看到bucket中的内容,但进入业务容器发现,目录并没有成功挂载。

    需要提出的一点是,由于CSI插件是被异常重启的,导致挂载失效,并没有执行标准的Unmounting 流程(即调用NodeUnpublishVolume方法),因此在重新挂载之前首先需要umount掉原来的挂载点。

    业务容器没有挂载成功的原因是整个恢复流程并没有触发kubelet执行umount/mount来将pvc重新挂载到业务容器。解决方式与CSI插件的/var/lib/kubelet/pods/<targetUid>/volumes/<targetUid>kubernetes.io~csi/<targetPvc-name>/mount一样,执行umountmount即可。但这么做首先要知道Pod映射到主机上的挂载路径,这样就比较麻烦了,因为pod映射到主机上的路径与使用的CRI相关,如果朝这一方向下去,难度比较大,在CSI Volume Plugins in Kubernetes Design Doc中也提过,正常情况下是由kubelet执行的:

    1. The volume manager component of kubelet, notices a mounted CSI volume, referenced by a pod that has been deleted or terminated, so it calls the in-tree CSI volume plugin’s UnmountDevice method which is a no-op and returns immediately.
    2. Next kubelet calls the in-tree CSI volume plugin’s unmount (teardown) method, which causes the in-tree volume plugin to issue a NodeUnpublishVolume call via the registered unix domain socket to the local CSI driver. If this call fails from any reason, kubelet re-tries the call periodically.
    3. Upon successful completion of the NodeUnpublishVolume call the specified path is unmounted from the pod container.

    那么怎么才能让容器重新挂载成功呢?

    只要重新触发kubelet的挂载动作即可,可以采用livenessProbe来触发该动作,方式如下:

    apiVersion: v1
    kind: Pod
    metadata:
      name: csi-s3-test-nginx
      namespace: default
    spec:
      containers:
       - name: csi-s3-test-nginx
         image: nginx
         livenessProbe:
           failureThreshold: 3
           initialDelaySeconds: 20
           periodSeconds: 5
           timeoutSeconds: 5
           exec:
             command:
             - ls
             - /var/lib/www/html
         volumeMounts:
           - mountPath: /var/lib/www/html
             name: webroot
           - mountPath: /var/lib/www/html2
             name: webroot2
      volumes:
       - name: webroot
         persistentVolumeClaim:
           claimName: csi-s3-pvc
           readOnly: false
       - name: webroot2
         persistentVolumeClaim:
           claimName: csi-s3-pvc2
           readOnly: false
    

    如果使用这种方式的话,还需要执行之前恢复s3fs进程的操作吗?答案是需要的,重启只会触发kubelet的动作,但不会触发CSI重新挂载,因此恢复s3fs进程和livenessProbe都是同时需要的。

    本帖子中包含资源

    您需要 登录 才可以下载,没有帐号?立即注册


Image

15091620030 2

去看attacher日志,报找不到VolumeAttachment资源,但是这个资源也是存在的 I0901 03:34:46.389716 1 reflector.go:188] Listing and watching *v1beta1.VolumeAttachment from k8s.io/client-go/informers/factory.go:135 E0901 03:34:46.392959 1 reflector.go:156] k8s.io/client-go/informers/factory.go:135: Failed to list *v1beta1.VolumeAttachment: the server could not find the requested resource root@wangbin:~/csi-s3-1.2.0-rc.1/deploy/kubernetes/examples# kubectl logs csi-attacher-s3-0 -n kube-system root@wangbin:~/csi-s3-1.2.0-rc.1/deploy/kubernetes/examples# kubectl get VolumeAttachment NAME ATTACHER PV NODE ATTACHED AGE csi-e830a62d66bdf6640f14d72962c87b7eab237705c7a163f9aae366ab701f8185 ch.ctrox.csi.s3-driver pvc-4c1189a2-21c3-474e-8591-e610fc956458 wangbin false 50m

Image

15091620030 1

您好,咨询下。我是使用minio+csi-s3做pod的存储。pv,pvc都创建bound成功了。使用pod去挂载,一直挂不上。可能啥问题呢 root@wangbin:~/csi-s3-1.2.0-rc.1/deploy/kubernetes/examples# ls pod.yaml pvc.yaml secret.yaml storageclass.yaml root@wangbin:~/csi-s3-1.2.0-rc.1/deploy/kubernetes/examples# cat pod.yaml apiVersion: v1 kind: Pod metadata: name: csi-s3-test-nginx namespace: default spec: containers: - name: csi-s3-test-nginx image: nginx volumeMounts: - mountPath: /var/lib/www/html name: webroot volumes: - name: webroot persistentVolumeClaim: claimName: csi-s3-pvc readOnly: false root@wangbin:~/csi-s3-1.2.0-rc.1/deploy/kubernetes/examples# kubectl get pod NAME READY STATUS RESTARTS AGE csi-s3-test-nginx 0/1 ContainerCreating 0 45m minio-5999fdd548-glnm9 1/1 Running 1 (17h ago) 25h root@wangbin:~/csi-s3-1.2.0-rc.1/deploy/kubernetes/examples# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE csi-s3-pvc Bound pvc-4c1189a2-21c3-474e-8591-e610fc956458 1Gi RWO csi-s3 74m minio Bound minio-pv 500Gi RWO manual 25h root@wangbin:~/csi-s3-1.2.0-rc.1/deploy/kubernetes/examples#