一起來讀 Kubernetes

的 Source Code

印章

2021/12/29

一次 CSI Bug 排查紀實

Agenda

  • Dell CSI Operator 介紹

  • 問題緣由

  • Bug 定位

  • Kubernetes Source Code
     

  • Walkaround
    Fixed (#106557)

Who Am I ?

  • 印章 (seal.tw ),不是海豹

  • 本名 吳易璋

社群打雜:

  • Gitlab Taiwan

  • Cloud Native Taiwan User Group

TL ; DR

Problem Fixed!

下課!

問題要從一台詭異的
Dell EMC Storage
說起 .......

使用 Dell CSI Operator

  • 支援 NFS 、 iSCSI 、 Fiber Channel (FC) 等多種介面
     

  • 支援 NFS Quota、Multipath、Dynamic Provision (PVC)
     

  • CSI Spec 支援 Resize 、 Snapshot (可選)
     

  • 快速的 Release 週期 (擺脫 in-tree 的繁瑣程序,及 golang限制)
     

  • 原廠提供的專業 support
    (Nutanix、NetApp、VMWare、AWS GP2 也都有類似的機制)

使用 Dell CSI Operator

  • 支援 NFS 、 iSCSI 、 Fiber Channel (FC) 等多種介面
     

  • 支援 NFS Quota、Multipath、
     

  •  

https://dell.github.io/csm-docs/docs/csidriver/

使用 Dell CSI Operator

{
  "storageArrayList": [
    {
      "username": "user",
      "password": "password",
      "restGateway": "https://10.1.1.1",
      "arrayId": "APM00******1",
      "insecure": true,
      "isDefaultArray": true
    },
    {
      "username": "user",
      "password": "password",
      "restGateway": "https://10.1.1.2",
      "arrayId": "APM00******2",
      "insecure": true
    }
  ]
}
apiVersion: storage.dell.com/v1
kind: CSIUnity
metadata:
  name: test-unity
  namespace: test-unity
spec:
  driver:
    common:
      image: "dellemc/csi-unity:v1.5.0"
    sideCars:
      - name: provisioner
        args: 
        - "--volume-name-prefix=csiunity"
    storageClass:
    - name: virt2017****-iscsi
      reclaimPolicy: "Delete"
      allowVolumeExpansion: true
      parameters:
        storagePool: pool_1
        arrayId: "APM00******1"
        protocol: "iSCSI"
    - name: virt2017****-nfs
      parameters:
        storagePool: pool_1
        arrayId: "APM00******2"
        protocol: "NFS"

使用 Dell CSI Operator

使用 Dell CSI Operator

https://github.com/container-storage-interface/spec/blob/master/spec.md

external
provisioner

external
attacher

driver
registrar

使用 Dell CSI Operator

https://github.com/container-storage-interface/spec/blob/master/spec.md

CSI
Controller

CSI Node
(Driver)

Pod 掛載 CSI Volume的過程

  • 如果 kubelet 發現 pod 需要掛載某個 Volume,
    會呼叫 Controller-Manager 的 Attach 這個 gRPC(?) ,
    建立對應的 VolumeAttachment 物件
  • external-attacher sidecar 監聽 VA 物件,
    發現有 Attached 狀態為 false 的 VA物件,
    會呼叫 CSI-Controller 的 ControllerPublishVolume 這個 gRPC

Pod 掛載 CSI Volume的過程

  • CSI-Controller 被呼叫 ControllerPublishVolume,
    執行對應的操作,確保這個 Volume 可以被 Mount
    (例如 Dell CSI 會去呼叫 Storage 的 Restful API ,
    進行Host & Lun 權限的 mapping)
  • ???會去呼叫 Driver 的 NodePublishVolume 這個 grpc,然後 CSI Driver 就會將對應的 Volume Mount至這個目錄底下
    • /var/lib/kubelet/plugins/kubernetes.io/
      csi/pv/pvc-xxx/globalmount
    • /var/lib/kubelet/plugins/
      kubernetes.io~csi-unity.dellemc.com
      /pvc-xxx/globalmount

Pod 掛載 CSI Volume的過程

  • kubelet 確認 CSI Driver ,已經將 Volume Mount
    至 /var/lib/kubelet 底下之後,就會呼叫 CRI 元件,

    將 Volume 透過正常的 bind mount 掛載進去 pod 裡面
    (類似 hostPath)



  • 補充,其實 Block Device 透過 CSI,
    也可以做到有限度的 RWX,只要透過 PodAffinity ,
    讓他們分配到同一個 Node 即可

聽起來很正常

所以問題是啥?

問題簡述

  • 有兩座 K8s 使用同一座 Dell EMC Unity
    其中一座 K8s 會有以下狀況,另外一座 K8s 不會
     
  • 剛安裝好一切正常,使用一段時間後,才開始出現問題


     
  • StorageClass 建立的 PV 無法刪除
     
  • Pod 有機率無法 Mount Volume,
    卡在 ContainerCreating 的狀態
     
  • 成功 Mount 之後,在同一台 Node 重啟 Pod 仍然正常

逐步排查

  • UniqueName
    • 每個 CSI Volume 在 K8s 中的唯一名稱
    • 由 Driver Name 、 Volume Handle 兩部分組成
       
  • Volume Handle
    • 代表這個 CSI Volume 的 Volume ID
    • 在 CSI-Unity 中,由 PV Name、Protocol、Array ID、LUN ID 四個部分組成
       
  • PV Name
    • 是由 external-provisioner ,這個 sidecar 自動產生
  • 1. UniqueName: (2 + 3)
    • csi-unity.dellemc.com^csiunity-**********-iSCSI-APM00******1-sv_42
      
      
      
      
  • 2. Driver Name: (由 CSI 開發者自訂)
    • csi-unity.dellemc.com
      
      
      
      
  • 3. Volume Handle: (4 + 5 + 6 + 7)
    • csiunity-**********-iSCSI-APM00******1-sv_42

逐步排查

  • 4. PV Name: (由 external-provisioner 自動產生)
    • csiunity-**********
      
      
  • 5. Protocol:
    • iSCSI
      
      
  • 6. Array ID:
    • APM00******1
      
      
  • 7. LUN ID: (Dell EMC Unity 中的 Lun ID)
    • sv_42

逐步排查

突破點:

 

手動刪除 VolumeAttachment
可以恢復正常

round_trippers.go:420]      
    DELETE https://api-int.my-cluster.ocp:6443
    /apis/storage.k8s.io/v1/volumeattachments/
    csi-unity.dellemc.com%5Ecsiunity-**********-iSCSI-**************-sv_42
                            
round_trippers.go:446]      
    Response Status: 404 Not Found in 8 milliseconds

csi_attacher.go:411]        
    kubernetes.io/csi: VolumeAttachment object [csi-unity.dellemc.com^csiunity-**********-iSCSI-**************-sv_42] 
    for volume [csi-unity.dellemc.com^csiunity-**********-iSCSI-**************-sv_42] 
    not found, object deleted
                            
operation_generator.go:472] 
    DetachVolume.Detach succeeded for volume "csiunity-**********" 
    (UniqueName: "csi-unity.dellemc.com^csiunity-**********-iSCSI-**************-sv_42") 
    on node "worker01.my-cluster.ocp"

Controller-Manager 的 Log

// getAttachmentName returns 
// csi-<sha256(volName,csiDriverName,NodeName)>
func getAttachmentName(volName, csiDriverName, nodeName string) string {
	result := sha256.Sum256([]byte(fmt.Sprintf("%s%s%s", volName, csiDriverName, nodeName)))
	return fmt.Sprintf("csi-%x", result)
}

// isAttachmentName returns true 
// if the string given is of the form of an Attach ID
// and false otherwise
func isAttachmentName(unknownString string) bool {
	// 68 == "csi-" + len(sha256hash)
	return strings.HasPrefix(unknownString, "csi-") && len(unknownString) == 68
}

VolumeAttachment Name

發生原因

  • CSI Volume 的 UniqueName 長度剛好為 68
     
  • CSI Driver 開頭剛好為 `csi-`

     
  • 導致 Controller-Manager 在 Detach 時,
    誤把 CSI Volume 認為 VolumeAttachment 物件,
    而不是透過公式重新計算 VA物件的名稱
     
  • 目前 pull request #107025 已完全解決 (12/18)

Workaround

  • 修改 provisioner 的 prefix,讓 PV 保證會超過長度 68
kind: CSIUnity
metadata:
  namespace: unity
  name: openshift-unity
spec:
  driver:
    common:
      image: dellemc/csi-unity:v1.4.0.000R
    configVersion: v3
    sideCars:
    - args:
      - --volume-name-prefix=csiunity-openshift
      image: k8s.gcr.io/sig-storage/csi-provisioner:v2.0.2
      imagePullPolicy: IfNotPresent
      name: provisioner

Q&A

Thanks

for your attention!

其實直接 telegram 扔我CV比較快 (X

Made with Slides.com