k8s之Attach 和 Mount

Attach 和 Mount

一、核心概念對比

操作Attach(掛載設備)Mount(掛載文件系統)
定義將存儲卷(如 EBS、NFS 等)連接到宿主機將已 Attach 的存儲設備映射為宿主機上的文件系統路徑
執行者云提供商驅動(AWS EBS CSI Driver)或存儲系統插件容器運行時(containerd、Docker)或 kubelet
操作對象存儲卷(Volume)文件系統(Filesystem)
Kubernetes 資源VolumeAttachment 對象Pod.spec.volumes 定義
操作結果宿主機可識別存儲設備(如 /dev/xvdf容器可訪問文件路徑(如 /data

二、工作流程與協作關系

1. Attach 流程

請添加圖片描述
圖源:https://www.lixueduan.com/posts/kubernetes/14-pv-dynamic-provision-process/#1-attach

1. 核心組件與職責

Kubernetes 的存儲 Attach 流程由兩個核心組件協作完成:

  • AD Controller (AttachDetach Controller)
    位于 kube-controller-manager 中,負責計算節點上需要 Attach/Detach 的卷,并創建 VolumeAttachment 資源。
  • external-attacher
    獨立運行的 CSI 插件,監聽 VolumeAttachment 資源變化,調用 CSI Driver 的接口執行實際 Attach 操作。
2. Attach 觸發條件

AD Controller 通過以下邏輯觸發 Attach 操作:

  1. 監聽 Pod 調度:當 Pod 被調度到特定節點時,AD Controller 獲取該節點上所有 Pod 的 Volume 列表。
  2. 計算待 Attach 卷:對比當前節點的 status.volumesAttached 與 Pod 需要的卷,找出未 Attach 的 PV。
  3. 多節點掛載檢查:對 ReadWriteOnce (RWO) 類型的卷,檢查是否已被其他節點掛載(若已掛載則報錯)。
3. VolumeAttachment 資源

AD Controller 創建的 VolumeAttachment 對象包含三個關鍵信息:

apiVersion: storage.k8s.io/v1
kind: VolumeAttachment
spec:attacher: nfs.csi.k8s.io  # CSI Driver 名稱nodeName: ee              # 目標節點source:persistentVolumeName: pvc-047acd58-...  # 待掛載的 PV
status:attached: false  # 掛載狀態(由 external-attacher 更新)
4. 詳細執行流程
ADControllerVolumeAttachmentExternalAttacherCSIDriverCloudProviderNode創建 VolumeAttachment 資源監聽資源變化調用 ControllerPublishVolume(PV, Node)調用云 API(如 AWS EBS Attach)返回設備 ID(如 /dev/xvdf)返回成功更新 status.attached=true更新 status.volumesAttachedADControllerVolumeAttachmentExternalAttacherCSIDriverCloudProviderNode

2. Mount 流程

2.1 核心組件與數據結構

Kubernetes 的 Mount 流程由 kubeletvolumeManager 組件管理,主要包含以下核心元素:

type volumeManager struct {desiredStateOfWorld cache.DesiredStateOfWorld // 期望狀態緩存actualStateOfWorld  cache.ActualStateOfWorld // 實際狀態緩存reconciler          reconciler.Reconciler     // 狀態協調器desiredStateOfWorldPopulator populator.DesiredStateOfWorldPopulator // 狀態填充器// ...其他組件
}
  • desiredStateOfWorld:保存當前節點上所有 Volume 期望的狀態
  • actualStateOfWorld:保存當前節點上所有 Volume 實際的狀態
  • reconciler:周期性比較兩個狀態,執行掛載/卸載操作
  • desiredStateOfWorldPopulator:處理節點上的 Pod,更新期望狀態
2.2 狀態同步機制

reconciler 通過周期性對比狀態執行掛載/卸載操作:

func (rc *reconciler) reconcile() {if rc.readyToUnmount() {rc.unmountVolumes() // 卸載不再需要的卷}rc.mountOrAttachVolumes() // 掛載新卷或處理已掛載卷if rc.readyToUnmount() {rc.unmountDetachDevices() // 卸載設備rc.cleanOrphanVolumes()   // 清理孤立卷}// 更新狀態同步時間if len(rc.volumesNeedUpdateFromNodeStatus) != 0 {rc.updateReconstructedFromNodeStatus()}if len(rc.volumesNeedUpdateFromNodeStatus) == 0 {rc.updateLastSyncTime()}
}
2.3 卸載流程

遍歷 actualStateOfWorld,卸載不再需要的卷:

func (rc *reconciler) unmountVolumes() {for _, mountedVolume := range rc.actualStateOfWorld.GetAllMountedVolumes() {// 檢查是否有未完成的操作if rc.operationExecutor.IsOperationPending(mountedVolume.VolumeName, mountedVolume.PodName, nestedpendingoperations.EmptyNodeName) {continue}// 如果卷不在期望狀態中,執行卸載if !rc.desiredStateOfWorld.PodExistsInVolume(mountedVolume.PodName, mountedVolume.VolumeName, mountedVolume.SELinuxMountContext) {err := rc.operationExecutor.UnmountVolume(mountedVolume.MountedVolume, rc.actualStateOfWorld, rc.kubeletPodsDir)if err != nil {klog.ErrorS(err, "UnmountVolume failed")}}}
}
2.4 掛載流程

遍歷 desiredStateOfWorld,掛載新卷或處理需要更新的卷:

func (rc *reconciler) mountOrAttachVolumes() {for _, volumeToMount := range rc.desiredStateOfWorld.GetVolumesToMount() {// 檢查是否有未完成的操作if rc.operationExecutor.IsOperationPending(volumeToMount.VolumeName, nestedpendingoperations.EmptyUniquePodName, nestedpendingoperations.EmptyNodeName) {continue}// 檢查卷狀態volMounted, devicePath, err := rc.actualStateOfWorld.PodExistsInVolume(volumeToMount.PodName, volumeToMount.VolumeName, volumeToMount.DesiredPersistentVolumeSize, volumeToMount.SELinuxLabel)volumeToMount.DevicePath = devicePath// 根據不同錯誤類型執行不同操作switch {case cache.IsSELinuxMountMismatchError(err):// SELinux 上下文不匹配,標記錯誤case cache.IsVolumeNotAttachedError(err):// 卷未掛載,等待 Attachrc.waitForVolumeAttach(volumeToMount)case !volMounted || cache.IsRemountRequiredError(err):// 卷未掛載或需要重新掛載rc.mountAttachedVolumes(volumeToMount, err)case cache.IsFSResizeRequiredError(err):// 文件系統需要擴容rc.expandVolume(volumeToMount, err.CurrentSize)}}
}
2.5 實際掛載操作

通過 operationGenerator 執行實際掛載,并更新狀態:

func (og *operationGenerator) GenerateMountVolumeFunc(...) volumetypes.GeneratedOperations {mountVolumeFunc := func() {// 獲取卷插件volumePlugin, err := og.volumePluginMgr.FindPluginBySpec(volumeToMount.VolumeSpec)if err != nil {return volumetypes.NewOperationContext(err, nil, migrated)}// 創建掛載器volumeMounter, err := volumePlugin.NewMounter(volumeToMount.VolumeSpec, volumeToMount.Pod)if err != nil {return volumetypes.NewOperationContext(err, nil, migrated)}// 等待設備掛載(如果需要)devicePath, err := volumeAttacher.WaitForAttach(volumeToMount.VolumeSpec, devicePath, volumeToMount.Pod, waitForAttachTimeout)if err != nil {return volumetypes.NewOperationContext(err, nil, migrated)}// 執行掛載mountErr := volumeMounter.SetUp(volume.MounterArgs{...})if mountErr != nil {return volumetypes.NewOperationContext(mountErr, nil, migrated)}// 擴容文件系統(如果需要)if resizeNeeded {err = og.expandVolumeDuringMount(volumeToMount, actualStateOfWorld, resizeOptions)if err != nil {return volumetypes.NewOperationContext(err, nil, migrated)}}// 更新實際狀態markVolMountedErr := actualStateOfWorld.MarkVolumeAsMounted(markOpts)if markVolMountedErr != nil {return volumetypes.NewOperationContext(markVolMountedErr, nil, migrated)}return volumetypes.NewOperationContext(nil, nil, migrated)}return volumetypes.GeneratedOperations{OperationFunc: mountVolumeFunc,// ...其他回調函數}
}
2.6 實際卸載操作

通過 operationGenerator 執行卸載,并更新狀態:

func (og *operationGenerator) GenerateUnmountVolumeFunc(...) {unmountVolumeFunc := func() {// 獲取卸載器volumeUnmounter, err := volumePlugin.NewUnmounter(volumeToUnmount.InnerVolumeSpecName, volumeToUnmount.PodUID)if err != nil {return volumetypes.NewOperationContext(err, nil, migrated)}// 清理子路徑掛載點if err := subpather.CleanSubPaths(podDir, volumeToUnmount.InnerVolumeSpecName); err != nil {return volumetypes.NewOperationContext(err, nil, migrated)}// 執行卸載unmountErr := volumeUnmounter.TearDown()if unmountErr != nil {// 標記卷狀態為不確定actualStateOfWorld.MarkVolumeMountAsUncertain(opts)return volumetypes.NewOperationContext(unmountErr, nil, migrated)}// 更新實際狀態actualStateOfWorld.MarkVolumeAsUnmounted(volumeToUnmount.PodName, volumeToUnmount.VolumeName)return volumetypes.NewOperationContext(nil, nil, migrated)}return volumetypes.GeneratedOperations{OperationFunc: unmountVolumeFunc,// ...其他回調函數}
}
2.7 期望狀態更新機制

desiredStateOfWorldPopulator 周期性處理 Pod,更新期望狀態:

func (dswp *desiredStateOfWorldPopulator) Run(ctx context.Context, sourcesReady config.SourcesReady) {// 周期性執行狀態填充wait.UntilWithContext(ctx, dswp.populatorLoop, dswp.loopSleepDuration)
}func (dswp *desiredStateOfWorldPopulator) processPodVolumes(ctx context.Context, pod *v1.Pod) {for _, podVolume := range pod.Spec.Volumes {// 將 Pod 的卷添加到期望狀態uniqueVolumeName, err := dswp.desiredStateOfWorld.AddPodToVolume(uniquePodName, pod, volumeSpec, podVolume.Name, volumeGIDValue, seLinuxContainerContexts[podVolume.Name])if err != nil {klog.ErrorS(err, "Failed to add pod to volume")}}
}
2.8 關鍵數據結構
  • volumesToMount:記錄需要掛載的卷
    type volumeToMount struct {volumeName                     v1.UniqueVolumeNamepodsToMount                    map[types.UniquePodName]podToMountpluginIsAttachable             boolpluginIsDeviceMountable        boolvolumeGIDValue                 stringdesiredSizeLimit               *resource.QuantityeffectiveSELinuxMountFileLabel string// ...其他屬性
    }
    

Mount 流程總結

  1. 狀態初始化desiredStateOfWorldPopulator 從 Pod 中收集卷信息,更新期望狀態
  2. 狀態對比reconciler 周期性比較期望狀態和實際狀態
  3. 卸載操作:對不再需要的卷執行卸載
  4. 掛載操作:對新增卷或需要更新的卷執行掛載
  5. 狀態更新:掛載/卸載成功后更新實際狀態
  6. 錯誤處理:處理掛載/卸載過程中的各種異常情況

通過這種雙緩存、周期性同步的機制,Kubernetes 確保了節點上卷的狀態始終與期望狀態一致。

3. 協作關系

存儲卷生命周期:
創建PV/PVC → Attach(設備掛載到宿主機) → Mount(文件系統掛載到容器) → 
Unmount(從容器卸載) → Detach(從宿主機卸載) → 刪除PV/PVC

三、常見存儲類型的 Attach/Mount 差異

存儲類型Attach 操作Mount 操作
EBS(塊存儲)將 EBS 卷掛載到 EC2 實例在實例上格式化并掛載文件系統(如 ext4)
NFS(網絡存儲)建立網絡連接(無需顯式 Attach)通過 NFS 客戶端掛載遠程文件系統
HostPath(宿主機路徑)無(已在宿主機上)直接將宿主機路徑掛載到容器
Ceph RBD將 RBD 設備映射到宿主機在宿主機上掛載 RBD 設備為文件系統

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/914946.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/914946.shtml
英文地址,請注明出處:http://en.pswp.cn/news/914946.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

API Gateway HTTP API 控制客戶端訪問 IP 源

前言 在 API Gateway REST API 中我們可以配置 Resource policy 來實現對特定客戶端 IP 地址的限制. 然而 HTTP API 并不提供這個功能, 不過我們可以用 Lambda 搓一個 Authorizer 實現等效的功能. 創建 Lambda authorizer import json import os import ipaddressdef lambda…

Linux搭建LAMP環境(CentOS 7 與 Ubuntu 雙系統教程)

Linux搭建LAMP環境 一、LAMP 環境核心概念 定義:由 Linux、Apache、MySQL、PHP 四大組件組成的開源 Web 應用平臺本質:四個獨立開源軟件的組合體,因長期協同使用形成高度兼容性,成為動態網站和服務器的主流解決方案 二、LAMP 四大…

c# 開機自動啟動程序

以下是兩種實現C#軟件開機自啟動的常用方法&#xff0c;根據需求選擇適合的方案&#xff1a; 方法1&#xff1a;通過注冊表實現&#xff08;需管理員權限&#xff09; using Microsoft.Win32; using System.Diagnostics;public static class AutoStartManager {/// <summa…

C語言---動態內存管理

為什么要有動態內存分配我們在學習動態內存管理之前&#xff0c;一直都是通過開辟變量&#xff0c;或者是開辟數組的方式來在內存的棧區開辟空間的&#xff0c;但是這樣的開辟方式有局限性&#xff0c;因為一旦開辟之后&#xff0c;它們的大小就無法改變&#xff0c;就缺少了很…

C++標準庫(std)詳解

C標準庫&#xff08;std&#xff09;詳解——目錄C標準庫&#xff08;std&#xff09;詳解一、命名空間&#xff08;namespace&#xff09;二、主要組件1. 輸入輸出流&#xff08;<iostream>&#xff09;2. 字符串處理&#xff08;<string>&#xff09;3. STL容器&…

ESP32的OTA升級詳解:3. 搭建node/python服務器升級(native ota原生API)

一、OTA兩種方式&#xff1a;app_update 與 esp_https_ota 區別 ESP32/ESP32-S2/ESP32-C3等可通過Wi-Fi或以太網下載新固件到OTA分區實現運行時升級。ESP-IDF提供兩種OTA升級方法&#xff1a; 使用app_update組件的原生API使用esp_https_ota組件的簡化API(支持HTTPS升級) 本次…

byte[]作為接口參數傳遞的方法

在C#中通過WebService或API傳遞byte參數&#xff08;如文件、圖像等二進制數據&#xff09;時&#xff0c;通常有以下幾種實現方式&#xff1a; ?1. 使用Base64編碼&#xff08;推薦REST API&#xff09;? 將byte數組轉換為Base64字符串傳輸&#xff0c;適用于JSON格式的API&…

元宇宙與Web3的深度融合:構建沉浸式數字體驗的愿景與挑戰

一、技術特征與融合基礎1. 元宇宙的技術架構&#xff08;2025年&#xff09;空間構建技術&#xff1a;3D建模與渲染&#xff1a;實時渲染引擎&#xff08;如Unity HDRP&#xff09;支持路徑追蹤光追&#xff0c;AI生成模型&#xff08;NVIDIA Get3D&#xff09;3秒生成3D場景。…

什么是腦裂

腦裂定義&#xff1a; 腦裂是分布式系統中由于網絡分區&#xff08;Network Partition&#xff09;導致集群節點被分割成多個獨立子集&#xff0c;每個子集認為自己是唯一合法的集群&#xff0c;從而導致數據不一致或系統行為異常的現象。詳細工作原理&#xff1a;發生原因&…

川翔云電腦:云端算力新標桿,創作自由無邊界

一、旗艦機型&#xff1a;4090Ultra 48G 顯存顛覆硬件限制 川翔云電腦最新上線的RTX 4090Ultra 48G 顯存機型&#xff0c;采用 NVIDIA Ada Lovelace 架構&#xff0c;單卡顯存容量達 48GB GDDR6X&#xff0c;較傳統 4090 翻倍&#xff0c;可直接加載 1200 萬面數的超復雜模型&a…

貪心算法(排序)

碼蹄集OJ-活動安排 #include<bits/stdc.h> using namespace std; struct MOOE {int s,e; }; bool compare(const MOOE&a,const MOOE&b) {return a.e<b.e; } int main( ) {int n;cin>>n;vector<MOOE>a(n);for(int i0;i<n;i){cin>>a[i].…

詳解序數回歸損失函數ordinal_regression_loss:原理與實現

在醫療 AI 領域&#xff0c;很多分類任務具有有序類別的特性&#xff0c;如疾病嚴重程度&#xff08;輕度→中度→重度&#xff09;、腫瘤分級&#xff08;G1→G2→G3&#xff09;等。這類任務被稱為序數回歸&#xff08;Ordinal Regression&#xff09;&#xff0c;需要特殊的…

SQL增查

建完庫與建完表后后:1.分別查詢student表和score表的所有記錄student表&#xff1a;score表:2.查詢student表的第2條到5條記錄SELECT * FROM student LIMIT 1,4;3.從student表中查詢計算機系和英語系的學生的信息SELECT * FROM student-> WHERE department IN (計算機系, 英…

二分答案之最大化最小值

參考資料來源靈神在力扣所發的題單&#xff0c;僅供分享學習筆記和記錄&#xff0c;無商業用途。 核心思路&#xff1a;本質上是求最大 應用場景&#xff1a;在滿足條件的最小值區間內使最大化 檢查函數&#xff1a;保證數據都要大于等于答案 補充&#xff1a;為什么需要滿…

OCR 賦能檔案數字化:讓沉睡的檔案 “活” 起來

添加圖片注釋&#xff0c;不超過 140 字&#xff08;可選&#xff09;企業產品檔案包含設計圖紙、檢測報告、生產記錄等&#xff0c;傳統數字化僅靠掃描存檔&#xff0c;后續檢索需人工逐份翻閱&#xff0c;效率極低。?OCR 產品檔案解決方案直擊痛點&#xff1a;通過智能識別技…

力扣118.楊輝三角

思路1.新建一個vector的vector2.先把空間開出來&#xff0c;然后再把里面的值給一個個修改開空間的手段&#xff1a;new、構造函數、reserve、resize因為我們之后要修改里面的數據&#xff0c;這就意味著我們需要去讀取這個數據并修改&#xff0c;如果用reserve的話&#xff0c…

Python 網絡爬蟲 —— 提交信息到網頁

一、模塊核心邏輯“提交信息到網頁” 是網絡交互關鍵環節&#xff0c;借助 requests 庫的 post() 函數&#xff0c;能模擬瀏覽器向網頁發數據&#xff08;如表單、文件 &#xff09;&#xff0c;實現信息上傳&#xff0c;讓我們能與網頁背后的服務器 “溝通”&#xff0c;像改密…

SpringMVC4

一、SpringMVC 注解與項目開發流程1.1注解的生命周期- Target、Retention 等元注解&#xff1a;- Target(ElementType.TYPE) &#xff1a;說明這個注解只能用在類、接口上。- Retention(RetentionPolicy.RUNTIME) &#xff1a;說明注解在運行時保留&#xff0c;能通過反射獲取…

數據結構排序算法總結(C語言實現)

以下是常見排序算法的總結及C語言實現&#xff0c;包含時間復雜度、空間復雜度和穩定性分析&#xff1a;1. 冒泡排序 (Bubble Sort)思想&#xff1a;重復比較相鄰元素&#xff0c;將較大元素向后移動。 時間復雜度&#xff1a;O(n)&#xff08;最好O(n)&#xff0c;最壞O(n)) 空…

嵌入式學習-PyTorch(2)-day19

很久沒有學了&#xff0c;期間打點滴打了一個多星期&#xff0c;太累了&#xff0c;再加上學了一下Python語法基礎&#xff0c;再終于開始重新學習pytorchtensorboard 的使用import torch from torch.utils.tensorboard import SummaryWriter writer SummaryWriter("logs…