開啟云盤并行掛載提升Pod啟動(dòng)速度
在高密度部署有狀態(tài)業(yè)務(wù)(例如數(shù)據(jù)庫)或大量短生命周期的容器(例如持續(xù)集成、批處理)等場景中,每個(gè)Pod都需要大量的云盤來存儲(chǔ)數(shù)據(jù),Pod的數(shù)量非常多,如果這些Pod同時(shí)被調(diào)度到同一個(gè)節(jié)點(diǎn)上,默認(rèn)使用的串行掛載會(huì)導(dǎo)致Pod啟動(dòng)時(shí)間顯著增加,您可以開啟云盤并行掛載功能來解決此類問題。
前提條件
已創(chuàng)建ACK托管集群,集群為1.26及以上版本,且csi-plugin和csi-provisioner組件版本為1.30.4及以上,請(qǐng)參見csi-plugin、csi-provisioner。
已安裝配置阿里云CLI,請(qǐng)參見安裝阿里云CLI。
注意事項(xiàng)
僅支持擁有磁盤序列號(hào)的云盤開啟并行掛載功能。關(guān)于如何查看磁盤序列號(hào),請(qǐng)?jiān)斠?a href="http://bestwisewords.com/zh/ecs/user-guide/query-the-serial-number-of-a-disk" id="08e770965dvdv" title="" class="xref">查看磁盤序列號(hào)。
2020年06月10日之前創(chuàng)建的云盤沒有可識(shí)別的序列號(hào)信息,無法開啟,因?yàn)樵擃愒票P會(huì)導(dǎo)致無法正常掛載。
多個(gè)云盤從同一個(gè)節(jié)點(diǎn)上卸載時(shí)仍然是串行的。
開啟并行掛載后,ECS DescribeDisks等OpenAPI返回的
Device
字段,以及控制臺(tái)上顯示的掛載點(diǎn)可能會(huì)不可靠,請(qǐng)避免在業(yè)務(wù)中使用該掛載路徑,您可以通過云盤的序列號(hào)確認(rèn)實(shí)際路徑。
開啟步驟
您可以通過自動(dòng)化腳本或手工配置開啟云盤并行掛載功能。
自動(dòng)化腳本配置
將以下腳本保存為enable_parallel_attach.sh文件。
#!/bin/bash set -e set -o pipefail readonly REQUIRED_VERSION="v1.30.4" CLUSTER_ID=$1 if [ -z "$CLUSTER_ID" ]; then echo "Usage: enable_parallel_attach.sh <cluster-id>" exit 1 fi check_version() { local ADDONS VERSION ADDONS=$(aliyun cs GET "/clusters/${CLUSTER_ID}/addon_instances") VERSION=$(echo "$ADDONS" | jq -r '.addons[] | select(.name=="csi-plugin") | .version') if ! printf "%s\n" "$REQUIRED_VERSION" "$VERSION" | sort -V -C; then echo "csi-plugin version $VERSION is not supported, please upgrade to $REQUIRED_VERSION or later" exit 1 fi PROVISIONER=managed-csiprovisioner VERSION=$(echo "$ADDONS" | jq -r '.addons[] | select(.name=="managed-csiprovisioner") | .version') if [ -z "$VERSION" ]; then PROVISIONER=csi-provisioner VERSION=$(echo "$ADDONS" | jq -r '.addons[] | select(.name=="csi-provisioner") | .version') fi if ! printf "%s\n" "$REQUIRED_VERSION" "$VERSION" | sort -V -C; then echo "$PROVISIONER version $VERSION is not supported, please upgrade to $REQUIRED_VERSION or later" exit 1 fi } update_node_pool() { local NODE_POOL_DOC NODE_POOL_DOC=$(aliyun cs GET "/clusters/${CLUSTER_ID}/nodepools/$1") if [ -n "$(echo "$NODE_POOL_DOC" | jq -r '(.scaling_group.tags // [])[] | select(.key=="supportConcurrencyAttach")')" ]; then echo "node pool already has supportConcurrencyAttach tag" return fi aliyun cs PUT "/clusters/${CLUSTER_ID}/nodepools/$1" --header "Content-Type=application/json" \ --body "$(echo "$NODE_POOL_DOC" | jq -c '{ "scaling_group": { "tags": ((.scaling_group.tags // []) + [{ "key": "supportConcurrencyAttach", "value": "true" }]) } }')" } # 存量節(jié)點(diǎn)配置 update_nodes() { local PAGE=1 local IDX TOTAL NODES_DOC ARGS while :; do echo "tagging nodes, page $PAGE" NODES_DOC=$(aliyun cs GET "/clusters/${CLUSTER_ID}/nodes" --pageSize 50 --pageNumber $PAGE) TOTAL=$(echo "$NODES_DOC" | jq -r '.page.total_count') ARGS=() IDX=0 for node in $(echo "$NODES_DOC" | jq -r '.nodes[] | select(.is_aliyun_node) | .instance_id'); do IDX=$((IDX+1)) ARGS+=("--ResourceId.$IDX" "$node") done if [ "$IDX" != "0" ]; then aliyun ecs TagResources --region "$ALIBABA_CLOUD_REGION_ID" --ResourceType Instance "${ARGS[@]}" \ --Tag.1.Key supportConcurrencyAttach --Tag.1.Value true echo "finished nodes $(( (PAGE-1)*50+IDX ))/$TOTAL" fi if [[ $(( PAGE*50 )) -ge $TOTAL ]]; then break fi PAGE=$((PAGE+1)) done } update_addon() { local ADDON=$1 shift local CONFIG STATE CONFIG=$(aliyun cs GET "/clusters/${CLUSTER_ID}/addon_instances/${ADDON}" | \ jq -c '.config | fromjson | (.FeatureGate // "" | split(",")) as $fg | .FeatureGate = ($fg + $ARGS.positional | unique | join(",")) | {config: . | tojson}' --args "$@") aliyun cs POST "/clusters/${CLUSTER_ID}/components/${ADDON}/config" --header "Content-Type=application/json" --body "$CONFIG" echo "Waiting for $ADDON config to complete" while true; do STATE=$(aliyun --secure cs GET "/clusters/${CLUSTER_ID}/addon_instances/${ADDON}" | jq -r '.state') echo "state: $STATE" if [ "$STATE" != "updating" ]; then break fi sleep 5 done if [ "$STATE" != "active" ]; then echo "Failed to update $ADDON config" return 1 fi } check_version aliyun cs GET "/clusters/${CLUSTER_ID}/nodepools" | jq -r '.nodepools[]|.nodepool_info|"\(.nodepool_id)\t\(.name)"' | \ while read -r NODE_POOL_ID NODE_POOL_NAME; do echo "Updating tags for node pool $NODE_POOL_NAME ($NODE_POOL_ID)" update_node_pool "$NODE_POOL_ID" done ALIBABA_CLOUD_REGION_ID=$(aliyun cs GET "/clusters/${CLUSTER_ID}" | jq -r .region_id) update_nodes update_addon $PROVISIONER DiskADController=true DiskParallelAttach=true update_addon csi-plugin DiskADController=true echo "All done! Now the disks can be attached concurrently to the same node."
執(zhí)行腳本并行掛載云盤。
bash enable_parallel_attach.sh <集群ID>
手工配置
新增集群節(jié)點(diǎn)池配置中的ECS 標(biāo)簽,使其鍵為
supportConcurrencyAttach
,值為true
,確保新創(chuàng)建的ECS實(shí)例有該標(biāo)簽。登錄容器服務(wù)管理控制臺(tái),在左側(cè)導(dǎo)航欄選擇集群。
在集群列表頁面,單擊目標(biāo)集群名稱,然后在左側(cè)導(dǎo)航欄,選擇 。
在節(jié)點(diǎn)池列表頁面,單擊目標(biāo)節(jié)點(diǎn)池所在行操作列的編輯。
在編輯節(jié)點(diǎn)池頁面最下方的高級(jí)選項(xiàng)區(qū)域,增加ECS 標(biāo)簽,其鍵為
supportConcurrencyAttach
,值為true
。
為集群中所有存量節(jié)點(diǎn)的ECS實(shí)例添加標(biāo)簽,使其鍵為
supportConcurrencyAttach
,值為true
。具體操作,請(qǐng)參見創(chuàng)建并綁定自定義標(biāo)簽。在左側(cè)導(dǎo)航欄選擇運(yùn)維管理 > 組件管理,單擊存儲(chǔ)頁簽,定位csi-provisioner組件,單擊組件右下方的配置,將FeatureGate設(shè)置為
DiskADController=true,DiskParallelAttach=true
。說明DiskADController=true
設(shè)置后,云盤相關(guān)attach
和detach
的操作交由csi-provisioner;DiskParallelAttach=true
設(shè)置后,將開啟云盤并行掛載功能。待csi-provisioner配置完成后,將csi-plugin組件的FeatureGate設(shè)置為
DiskADController=true
。
驗(yàn)證云盤并行掛載性能
本示例將在同一節(jié)點(diǎn)上創(chuàng)建大量掛載云盤的Pod,以驗(yàn)證開啟并行掛載對(duì)Pod啟動(dòng)速度的提升。
本文中提供的測試數(shù)據(jù)僅為理論值(參考值),實(shí)際數(shù)據(jù)以您的操作環(huán)境為準(zhǔn)。
在ACK集群中,添加一個(gè)支持多個(gè)云盤掛載的節(jié)點(diǎn)。例如,ecs.g7se.16xlarge類型的實(shí)例最多可掛載56塊云盤。
使用以下內(nèi)容,創(chuàng)建測試應(yīng)用attach-stress.yaml文件,并將
<YOUR-HOSTNAME>
替換為實(shí)際的節(jié)點(diǎn)名稱。--- apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: alibabacloud-disk provisioner: diskplugin.csi.alibabacloud.com parameters: type: cloud_auto volumeBindingMode: WaitForFirstConsumer reclaimPolicy: Delete allowVolumeExpansion: true --- apiVersion: apps/v1 kind: StatefulSet metadata: name: attach-stress spec: selector: matchLabels: app: attach-stress serviceName: attach-stress replicas: 1 podManagementPolicy: Parallel persistentVolumeClaimRetentionPolicy: whenScaled: Retain whenDeleted: Delete template: metadata: labels: app: attach-stress spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - <YOUR-HOSTNAME> # 替換為實(shí)際節(jié)點(diǎn)的名稱。 hostNetwork: true containers: - name: attach-stress image: registry-cn-hangzhou.ack.aliyuncs.com/acs/busybox command: ["/bin/sh", "-c", "trap exit TERM; while true; do date > /mnt/0/data; sleep 1; done"] volumeMounts: - name: volume-0 mountPath: /mnt/0 - name: volume-1 mountPath: /mnt/1 volumeClaimTemplates: - metadata: name: volume-0 spec: accessModes: [ "ReadWriteOnce" ] storageClassName: alibabacloud-disk resources: requests: storage: 1Gi - metadata: name: volume-1 spec: accessModes: [ "ReadWriteOnce" ] storageClassName: alibabacloud-disk resources: requests: storage: 1Gi
執(zhí)行以下命令,確認(rèn)應(yīng)用正常啟動(dòng),然后將副本數(shù)量縮容到0,以準(zhǔn)備后續(xù)的批量掛載測試。
kubectl apply -f attach-stress.yaml kubectl rollout status sts attach-stress kubectl scale sts attach-stress --replicas 0
預(yù)期輸出:
storageclass.storage.k8s.io/alibabacloud-disk created statefulset.apps/attach-stress created partitioned roll out complete: 1 new pods have been updated... statefulset.apps/attach-stress scaled
執(zhí)行以下命令,開始批量掛載測試,并統(tǒng)計(jì)Pod啟動(dòng)所需的時(shí)間。
說明此時(shí)該集群尚未開啟并行掛載功能,請(qǐng)根據(jù)您的節(jié)點(diǎn)最大支持的云盤數(shù)量調(diào)整測試的副本數(shù)。
date && \ kubectl scale sts attach-stress --replicas 28 && \ kubectl rollout status sts attach-stress && \ date
預(yù)期輸出:
2024年10月15日 星期二 19時(shí)21分36秒 CST statefulset.apps/attach-stress scaled Waiting for 28 pods to be ready... Waiting for 27 pods to be ready... <省略……> Waiting for 3 pods to be ready... Waiting for 2 pods to be ready... Waiting for 1 pods to be ready... partitioned roll out complete: 28 new pods have been updated... 2024年10月15日 星期二 19時(shí)24分55秒 CST
輸出表明,在未開啟并行掛載時(shí),28個(gè)Pod全部啟動(dòng)耗時(shí)超過3分鐘。
參考上文開啟步驟開啟該集群的并行掛載功能。
執(zhí)行以下命令,清理之前創(chuàng)建的Pod,準(zhǔn)備下一輪測試。
說明清理時(shí),觀察集群中相關(guān)的
volumeattachments
資源,等待它們被刪除后即可完成云盤的卸載,過程大約需要幾分鐘。kubectl scale sts attach-stress --replicas 0
再次執(zhí)行以下測試命令,統(tǒng)計(jì)開啟并行掛載后Pod啟動(dòng)所需的時(shí)間,預(yù)期僅需要約40秒,較未開啟時(shí)的3分鐘,有明顯提升。
date && \ kubectl scale sts attach-stress --replicas 28 && \ kubectl rollout status sts attach-stress && \ date
預(yù)期輸出:
2024年10月15日 星期二 20時(shí)02分54秒 CST statefulset.apps/attach-stress scaled Waiting for 28 pods to be ready... Waiting for 27 pods to be ready... <省略……> Waiting for 3 pods to be ready... Waiting for 2 pods to be ready... Waiting for 1 pods to be ready... partitioned roll out complete: 28 new pods have been updated... 2024年10月15日 星期二 20時(shí)03分31秒 CST
執(zhí)行以下命令,清理集群中的測試應(yīng)用。
kubectl delete -f attach-stress.yaml