一起來讀 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
- 會產生 StorageClass ,可直接使用 PVC ,
去動態建立 Volume
- 使用 DaemonSet 自動安裝 Driver
(產生 csi.sock 供 kubelet 使用 gRPC 呼叫)
- 附帶 sidecar (Node、Driver)
- 附帶 sidecar (Controller)
使用 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 物件- (Status.Attached 狀態為 false)
- kubernetes/kubernetes
=> csi_attacher.go#L69
- external-attacher sidecar 監聽 VA 物件,
發現有 Attached 狀態為 false 的 VA物件,
會呼叫 CSI-Controller 的 ControllerPublishVolume 這個 gRPC- kubernetes-csi/external-attacher
=> attacher.go#L68
- kubernetes-csi/external-attacher
Pod 掛載 CSI Volume的過程
- CSI-Controller 被呼叫 ControllerPublishVolume,
執行對應的操作,確保這個 Volume 可以被 Mount
(例如 Dell CSI 會去呼叫 Storage 的 Restful API ,
進行Host & Lun 權限的 mapping)- dell/csi-unity
=> controller.go#L317
- dell/csi-unity
- ???會去呼叫 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
Kubernetes bug 紀實 (CSI篇)
By rockwyc992
Kubernetes bug 紀實 (CSI篇)
- 535