一文读懂容器存储接口 CSI
更新 PVC 的 .Status.Conditions,表明此时处于 Resizing 状态。
通过特定的 Unix Domain Socket 调用外部 CSI 插件的 ControllerExpandVolume 接口。
更新 PV 的 .Spec.Capacity。
若 CSI 支持文件系统在线扩容,ControllerExpandVolume 接口返回值中 NodeExpansionRequired 字段为 true,External-Resizer更新 PVC 的 .Status.Conditions 为 FileSystemResizePending 状态;若不支持则扩容成功,External-Resizer更新 PVC 的 .Status.Conditions 为空,且更新 PVC 的 .Status.Capacity。
Volume Manager(Kubelet 组件)观察到存储卷需在线扩容,于是通过特定的 Unix Domain Socket 调用外部 CSI 插件的NodeExpandVolume 接口实现文件系统扩容。
[](()5. livenessprobe
[](()1)功能
检查 CSI 插件是否正常。
[](()2)原理
通过对外暴露一个 / healthz HTTP 端口以服务 kubelet 的探针探测器,内部是通过特定的 Unix Domain Socket 调用外部 CSI 插件的 Probe 接口。
[](()CSI 接口介绍
=============================================================================
三方存储厂商需实现 CSI 插件的三大接口:IdentityServer、ControllerServer、NodeServer。
[](()1. IdentityServer
IdentityServer 主要用于认证 CSI 插件的身份信息。
// IdentityServer is the server API for Identity service.
type IdentityServer interface {
// 获取CSI插件的信息,比如名称、版本号
GetPluginInfo(context.Context, *GetPluginInfoRequest) (*GetPluginInfoResponse, error)
// 获取CSI插件提供的能力,比如是否提供ControllerService能力
GetPluginCapabilities(context.Context, *GetPluginCapabilitiesRequest) (*GetPluginCapabilitiesResponse, error)
// 获取CSI插件健康状况
Probe(context.Context, *ProbeRequest) (*ProbeResponse, error)
}
[](()2. ControllerServer
ControllerServer 主要负责存储卷及快照的创建/删除以及挂接/摘除操作。
// ControllerServer is the server API for Controller service.
type ControllerServer interface {
// 创建存储卷
CreateVolume(context.Context, *CreateVolumeRequest) (*CreateVolumeResponse, error)
// 删除存储卷
DeleteVolume(context.Context, *DeleteVolumeRequest) (*DeleteVolumeResponse, error)
// 挂接存储卷到特定节点
ControllerPublishVolume(context.Context, *ControllerPublishVolumeRequest) (*ControllerPublishVolumeResponse, error)
// 从特定节点摘除存储卷
ControllerUnpublishVolume(context.Context, *ControllerUnpublishVolumeRequest) (*ControllerUnpublishVolumeResponse, error)
// 验证存储卷能力是否满足要求,比如是否支持跨节点多读多写
ValidateVolumeCapabilities(context.Context, *ValidateVolumeCapabilitiesRequest) (*ValidateVolumeCapabilitiesResponse, error)
// 列举全部存储卷信息
ListVolumes(context.Context, *ListVolumesRequest) (*ListVolumesResponse, error)
// 获取存储资源池可用空间大小
GetCapacity(context.Context, *GetCapacityRequest) (*GetCapacityResponse, error)
// 获取ControllerServer支持功能点,比如是否支持快照能力
ControllerGetCapabilities(context.Context, *ControllerGetCapabilitiesRequest) (*ControllerGetCapabilitiesResponse, error)
// 创建快照
CreateSnapshot(context.Context, *CreateSnapshotRequest) (*CreateSnapshotResponse, error)
// 删除快照
DeleteSnapshot(context.Context, *DeleteSnapshotRequest) (*DeleteSnapshotResponse, error)
// 获取所有快照信息
ListSnapshots(context.Context, *ListSnapshotsRequest) (*ListSnapshotsResponse, error)
// 扩容存储卷
ControllerExpandVolume(context.Context, *ControllerExpandVolumeRequest) (*ControllerExpandVolumeResponse, error)
}
[](()3. NodeServer
NodeServer 主要负责存储卷挂载/卸载操作。
// NodeServer is the server API for Node service.
type NodeServer interface {
// 将存储卷格式化并挂载至临时全局目录
NodeStageVolume(context.Context, *NodeStageVolumeRequest) (*NodeStageVolumeResponse, error)
// 将存储卷从临时全局目录卸载
NodeUnstageVolume(context.Context, *NodeUnstageVolumeRequest) (*NodeUnstageVolumeResponse, error)
// 将存储卷从临时目录bind-mount到目标目录
NodePublishVolume(context.Context, *NodePublishVolumeRequest) (*NodePublishVolumeResponse, error)
// 将存储卷从目标目录卸载
NodeUnpublishVolume(context.Context, *NodeUnpublishVolumeRequest) (*NodeUnpublishVolumeResponse, error)
// 获取存储卷的容量信息
NodeGetVolumeStats(context.Context, *NodeGetVolumeStatsRequest) (*NodeGetVolumeStatsResponse, error)
// 存储卷扩容
NodeExpandVolume(context.Context, *NodeExpandVolumeRequest) (*NodeExpandVolumeResponse, error)
// 获取NodeServer支持功能点,比如是否支持获取存储卷容量信息
NodeGetCapabilities(context.Context, *NodeGetCapabilitiesRequest) (*NodeGetCapabilitiesResponse, error)
// 获取CSI节点信息,比如最大支持卷个数
NodeGetInfo(context.Context, *NodeGetInfoRequest) (*NodeGetInfoResponse, error)
}
[](()K8s CSI API 对象
===================================================================================
K8s 为支持 CSI 标准,包含如下 API 对象:
CSINode
CSIDriver
VolumeAttachment
[](()1. CSINode
apiVersion: storage.k8s.io/v1beta1
kind: CSINode
metadata:
name: node-10.212.101.210
spec:
drivers:
- name: yodaplugin.csi.alibabacloud.com
nodeID: node-10.212.101.210
topologyKeys:
kubernetes.io/hostname
name: pangu.csi.alibabacloud.com
nodeID: a5441fd9013042ee8104a674e4a9666a
topologyKeys:
- topology.pangu.csi.alibabacloud.com/zone
作用:
判断外部 CSI 插件是否注册成功。在 Node Driver Registrar 组件向 Kubelet 注册完毕后,Kubelet 会创建该资源,故不需要显式创建 CSINode 资源。
将 Kubernetes 中 Node 资源名称与三方存储系统中节点名称(nodeID)一一对应。此处Kubelet会调用外部 CSI 插件NodeServer 的 GetNodeInfo 函数获取 nodeID。
显示卷拓扑信息。CSINode 中 topologyKeys 用来表示存储节点的拓扑信息,卷拓扑信息会使得Scheduler在 Pod 调度时选择合适的存储节点。
[](()2. CSIDriver
apiVersion: storage.k8s.io/v1beta1
kind: CSIDriver
metadata:
name: pangu.csi.alibabacloud.com
spec:
插件是否支持卷挂接(VolumeAttach)
attachRequired: true
Mount阶段是否CSI插件需要Pod信息
podInfoOnMount: true
指定CSI支持的卷模式
volumeLifecycleModes:
- Persistent
作用:
简化外部 CSI 插件的发现。由集群管理员创建,通过 kubectl get csidriver 即可得知环境上有哪些 CSI 插件。
自定 义Kubernetes 行为,如一些外部 CSI 插件不需要执行卷挂接(VolumeAttach)操作,则可以设置 .spec.attachRequired 为 false。
[](()3. VolumeAttachment
apiVersion: storage.k8s.io/v1
kind: VolumeAttachment
metadata:
annotations:
csi.alpha.kubernetes.io/node-id: 21481ae252a2457f9abcb86a3d02ba05
finalizers:
- external-attacher/pangu-csi-alibabacloud-com
name: csi-0996e5e9459e1ccc1b3a7aba07df4ef7301c8e283d99eabc1b69626b119ce750
spec:
attacher: pangu.csi.alibabacloud.com
nodeName: node-10.212.101.241
source:
persistentVolumeName: pangu-39aa24e7-8877-11eb-b02f-021234350de1
status:
attached: true
作用:VolumeAttachment 记录了存储卷的挂接/摘除信息以及节点信息。
[](()支持特性
=========================================================================
[](()1. 拓扑支持
在 StorageClass 中有 AllowedTopologies 字段:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-pangu
provisioner: pangu.csi.alibabacloud.com
parameters:
type: cloud_ssd
volumeBindingMode: Immediate
allowedTopologies:
matchLabelExpressions:
key: topology.pangu.csi.alibabacloud.com/zone
values:
zone-1
zone-2
外部 CSI 插件部署后会为每个节点打标,打标内容NodeGetInfo 函数返回的 [AccessibleTopology] 值(详见 Node Driver Registrar 部分)。
External Provisioner在调用 CSI 插件的 CreateVolume 接口之前,会在请求参数设置 AccessibilityRequirements:
对于 WaitForFirstConsumer
当 PVC 的 anno 中包含 “volume.kubernetes.io/selected-node” 且不为空,则先获取对应节点 CSINode 的 TopologyKeys,然后根据该 TopologyKeys 键从 Node 资源的 Label 获取 Values 值,最后拿该 Values 值与 StorageClass 的 AllowedTopologies 比对,判断其是否包含于其中;若不包含则报错。
对于 Immediately
将 StorageClass 的 AllowedTopologies 的值填进来,若 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 StorageClass 没有设置 AllowedTopologies 则将所有包含 TopologyKeys 键的节点 Value 添进来。
[](()Scheduler 如何处理使用存储卷调度
基于社区 1.18 版本调度器
调度器的调度过程主要有如下三步:
预选(Filter):筛选满足 Pod 调度要求的节点列表。
优选(Score):通过内部的优选算法为节点打分,获得最高分数的节点即为选中的节点。
绑定(Bind):调度器将调度结果通知给 kube-apiserver,更新 Pod 的 .spec.nodeName 字段。
调度器预选阶段:处理 Pod 的 PVC/PV 绑定关系以及动态供应 PV(Dynamic Provisioning),同时使调度器调度时考虑 Pod 所使用 PV 的节点亲和性。详细调度过程如下:
Pod 不包含 PVC 直接跳过。
FindPodVolumes
获取 Pod 的 boundClaims、claimsToBind 以及 unboundClaimsImmediate。
boundClaims:已 Bound 的 PVC
claimsToBind:PVC 对应 StorageClass 的 VolumeBindingMode 为 VolumeBindingWaitForFirstConsumer
unboundClaimsImmediate:PVC 对应 StorageClass 的 VolumeBindingMode 为 VolumeBindingImmediate
若 len(unboundClaimsImmediate) 不为空,表示这种 PVC 需要立即绑定 PV(即存 PVC 创建后,立刻动态创建 PV 并将其绑定到 PVC,该过程不走调度),若 PVC 处于 unbound 阶段则报错。
若 len(boundClaims) 不为空,则检查 PVC 对应 PV 的节点亲和性与当前节点的 Label 是否冲突,若冲突则报错(可检查 Immediate 类型的 PV 拓扑)。
若 len(claimsToBind) 不为空
先检查环境中已有的 PV 能否与该 PVC 匹配(findMatchingVolumes),将能够匹配 PVC 的 PV 记录在调度器的 cache 中。
未匹配到 PV 的 PVC 走动态调度流程,动态调度主要通过 StorageClass 的 AllowedTopologies 字段判断当前调度节点是否满足拓扑要求(针对 WaitForFirstConsumer 类型的 PVC)。
调度器优选阶段不讨论。
调度器 Assume 阶段
调度器会先 Assume PV/PVC,再 Assume Pod。
将当前待调度的 Pod 进行深拷贝。
AssumePodVolumes(针对 WaitForFirstConsumer 类型的 PVC)
更改调度器 cache 中已经 Match 的 PV 信息:设置 annotation:pv.kubernetes.io/bound-by-controller=“yes”。
更改调度器 cache 中未匹配到 PV 的 PVC,设置 annotation:volume.kubernetes.io/selected-node=【所选节点】。
- Assume Pod 完毕
- 更改调度器 cache 中 Pod 的 .Spec.NodeName 为【所选节点】。
调度器 Bind 阶段
BindPodVolumes:
调用 Kubernetes 的 API 更新集群中 PV/PVC 资源,使其与调度器 Cache 中的 PV/PVC 一致。
检查 PV/PVC 状态:
检查所有 PVC 是否已处于 Bound 状态。
检查所有 PV 的 NodeAffinity 是否与节点 Label 冲突。
调度器执行 Bind 操作:调用 Kubernetes 的 API 更新 Pod 的 .Spec.NodeName 字段。
[](()2. 存储卷扩容
存储卷扩容部分在 External Resizer 部分已提到,故不再赘述。用户只需要编辑 PVC 的 .Spec.Resources.Requests.Storage 字段即可,注意只可扩容不可缩容。
若 PV 扩容失败,此时 PVC 无法重新编辑 spec 字段的 storage 为原来的值(只可扩容不可缩容)。参考 K8s 官网提供的 PVC 还原方法:
https://kubernetes.io/docs/concepts/storage/persistent-volumes/#recovering-from-failure-when-expanding-volumes
[](()3. 单节点卷数量限制
卷数量限制在 Node Driver Registrar 部分已提到,故不再赘述。
[](()4. 存储卷监控
存储商需实现 CSI 插件的 NodeGetVolumeStats 接口,Kubelet 会调用该函数,并反映在其 metrics上:
kubelet_volume_stats_capacity_bytes:存储卷容量
kubelet_volume_stats_used_bytes:存储卷已使用容量
kubelet_volume_stats_available_bytes:存储卷可使用容量
kubelet_volume_stats_inodes:存储卷 inode 总量
kubelet_volume_stats_inodes_used:存储卷 inode 使用量
kubelet_volume_stats_inodes_free:存储卷 inode 剩余量
[](()5. Secret
CSI 存储卷支持传入 Secret 来处理不同流程中所需要的私密数据,目前 StorageClass 支持如下 Parameter:
csi.storage.k8s.io/provisioner-secret-name
csi.storage.k8s.io/provisioner-secret-namespace
csi.storage.k8s.io/controller-publish-secret-name
csi.storage.k8s.io/controller-publish-secret-namespace
csi.storage.k8s.io/node-stage-secret-name
csi.storage.k8s.io/node-stage-secret-namespace
csi.storage.k8s.io/node-publish-secret-name
csi.storage.k8s.io/node-publish-secret-namespace
csi.storage.k8s.io/controller-expand-secret-name
csi.storage.k8s.io/controller-expand-secret-namespace
Secret 会包含在对应 CSI 接口的参数中,如对于 CreateVolume 接口而言则包含在 CreateVolumeRequest.Secrets 中。
[](()6. 块设备
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx-example
spec:
selector:
matchLabels:
app: nginx
serviceName: “nginx”
volumeClaimTemplates:
- metadata:
name: html
spec:
accessModes:
- ReadWriteOnce
volumeMode: Block
storageClassName: csi-pangu
resources:
requests:
storage: 40Gi
template:
metadata:
labels:
app: nginx
spec:
containers:
一文读懂容器存储接口 CSI相关推荐
- 容器存储接口 CSI学习
一 CSI 概述 K8s持久化存储经历了从 in-tree Volume 到CSI Plugin(out-of-tree)的迁移,一方面是为了将k8s的核心主干代码与Volume相关代码解耦,便于更好 ...
- 认识K8s容器存储接口CSI
容器存储接口(Container Storage Interface),简称 CSI,CSI试图建立一个行业标准接口的规范,借助CSI容器编排系统(CO)可以将任意存储系统暴露给自己的容器工作负载. ...
- 一文读懂浏览器存储与缓存机制
浏览器存储 Cookie Cookie 是 HTTP 协议的一种无状态协议.当请求服务器时,HTTP 请求都需要携带 Cookie,用来验证用户身份.Cookie 由服务端生成,存储在客户端,用来维持 ...
- 云原生的基石,一文读懂容器、Docker、Pod到底是什么!
作者 | Aholiab 责编 | Carol 出品 | CSDN(ID:CSDNnews) 封图|CSDN下载自视觉中国 云原生(Cloud Native),是2013年由Pivotal公司率先提出 ...
- 云原生的基石,一文读懂容器、Docker、Pod到底是什么
课程概要 云原生(Cloud Native),是2013年由Pivotal公司率先提出的概念.云原生以容器化.微服务.可持续交付性,帮助企业构建和运行可弹性扩展的应用.由于云原生应用构建简便快捷,部署 ...
- 一文读懂 K8s 持久化存储流程
作者 | 孙志恒(惠志) 阿里巴巴开发工程师 **导读:**众所周知,K8s 的持久化存储(Persistent Storage)保证了应用数据独立于应用生命周期而存在,但其内部实现却少有人提及.K ...
- Kubernetes 1.13 版本发布:Kubeadm简化群集管理、容器存储接口(CSI)和CoreDNS作为默认DNS现已普遍可用
Kubernetes 1.13 版本发布 Kubeadm简化群集管理.容器存储接口(CSI)和CoreDNS作为默认DNS现已普遍可用 我们很高兴地宣布推出Kubernetes 1.13,这是我们20 ...
- 一文读懂HDMI和VGA接口针脚定义
一文读懂HDMI和VGA接口针脚定义 摘自:http://www.elecfans.com/yuanqijian/jiekou/20180423666604.html HDMI概述 HDMI是高清 ...
- 一文读懂Java中File类、字节流、字符流、转换流
一文读懂Java中File类.字节流.字符流.转换流 第一章 递归:File类: 1.1:概述 java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建.查找和删除等操作. ...
最新文章
- netstat -ano 查看机器端口占用情况
- oracle em 按钮乱码解决办法
- fastd java下载_配置 FastDFS Java 客户端
- SpringCloud学习笔记(十)----服务熔断与限流 Sentinel
- python字典的常用方法_python操作字典类型的常用方法(推荐)
- Asp.Net MVC 身份验证-Forms
- MySQL安装配置+Navicat安装配置
- 会玩儿!网易云音乐推出“还郑州一个七夕”特别策划
- ipmitool 远程操作BMC控制服务器
- 每天吃多少才不会胖?食物和卡路里对照表
- Linux EXPORT_SYMBOL宏详解
- 不可不读的百句良言!!
- 27.FastAPI应用生产环境部署
- ctf编码,解密总结
- WireShark教程 – 黑客发现之旅(5) – (nmap)扫描探测
- 行人重识别模型搭建与训练
- From Microservices to Data Microservices-pivotal-专题视频课程
- 元宇宙的新鲜度,终归离不开一个“玩”字
- 兄弟hl4150cdn感叹号5_打印质量问题解决方法
- 中级网络工程师——第一章计算机组成与原理