当创建pvc后,kubernetes组件如何协作
本文分享自华为云社区《当创建一个pvc后,kubernetes会发生什么?》,作者:可以交个朋友。
一、背景
外部存储接入 Kubernetes 的方式主要有两种:In-Tree 和 Out-of-Tree:
- In-Tree 是指存储驱动的源码都在 Kubernetes 代码库中,与 Kubernetes 一起发布、迭代、管理,这种方式灵活性较差,且门槛较高。
- Out-of-Tree 是指存储插件由第三方编写、发布、管理,作为一种扩展与 Kubernetes 配合使用。Out-of-Tree 主要有 FlexVolume 和 CSI 两种实现方式,其中,FlexVolume 因为其命令式的特点,不易维护和管理,从 Kubernetes v1.23 版本开始已被弃用。因此 CSI 已经成为 Kubernetes 存储扩展( Out-of-Tree )的唯一方式。
外部存储最终的效果是将存储(磁盘、obs、nas盘等)挂载到容器中被业务使用,所以一般包括存在两个过程:
- attach 是将存储介质在指定虚拟机上绑盘,部分存储介质才需要attach操作,比如容器中使用块存储,大致流程是1)需要先调用openstack接口,将某块evs绑到某个虚拟机上,成为虚拟机设备;2)在将存储设备挂载到容器目录上
- mount 将某个存储挂载到对应文件系统上,是操作系统层面的行为,所有的存储介质挂载到容器中都需要mount阶段,比如容器中使用nas或者obs,本质上就是执行nfs命令将网络存储挂载到容器目录上
二、CSI 架构解读
kubernetes CSI存储插件的关键组件与推荐的容器化部署架构

三、动态创建 Volume 执行过程
以块类型存储为例,从声明pvc到pod挂载卷成功时序图:

1、涉及组件解读
PV Controller:负责处理集群中的pvc/pv对象,对pvc/pv对象进行状态转换,并根据需求进行数据卷的 Provision/Delete 操作(注:Static pv不会触发provisioner、Dynamic pv才会触发provisioner)
AD Controller:负责VolumeAttachement的生命周期管理,并通过external-attacher将设备挂载到目标节点或从目标节点卸载。VolumeAttachement是控制块存储设备的 Attach/Detach 操作的逻辑对象。(注:可通过kubelet配置文件开关控制节点是否由AD Controller管理)。
kubelet主要包含与存储相关的两个插件::1)Volume Manager:管理存储卷的 Mount/Unmount 操作、卷设备的格式化等操作(注:如果当前节点并没有交给AD Controller管理,那么就是volumeManager负责管理VolumeAttachement的生命周期);2)Volume Plugin:K8S平台为存储提供商提供存储接入的插件接口,其中包含in-tree的多种存储插件和out-tree的两种存储插件。通过该插件机制进而为容器应用提供各种类型的存储。社区推荐的是CSI架构的扩展插件
2、涉及资源解读
PV:PersistentVolume,集群级别的资源,由集群管理员 or External Provisioner创建。PV 的生命周期独立于使用 PV 的 Pod,PV 的 .Spec 中保存了存储设备的详细信息。
kind: PersistentVolume
apiVersion: v1
metadata:
name: pv-test
labels:
failure-domain.beta.kubernetes.io/region: cn-north-4
failure-domain.beta.kubernetes.io/zone: cn-north-4a
annotations:
pv.kubernetes.io/provisioned-by: xxxx-provisioner #存储提供者
spec:
capacity:
storage: 10Gi
csi:
driver: disk.csi.everest.io
volumeHandle: 698a99d8-xxx-xxxx-xxxx-ab80b1ecbf #使用的存储设备信息
volumeAttributes:
everest.io/disk-mode: SCSI
everest.io/disk-volume-type: ESSD
storage.kubernetes.io/csiProvisionerIdentity: xxxx-provisioner
accessModes:
- ReadWriteOnce
# 引用对象, 该pv由哪个pvc创建
claimRef:
kind: PersistentVolumeClaim
namespace: test
name: pvc-test
uid: xxxx-xxxx-xxxx-22bf9101f0ce
apiVersion: v1
persistentVolumeReclaimPolicy: Delete
storageClassName: csi-disk
volumeMode: Filesystem
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: failure-domain.beta.kubernetes.io/zone
operator: In
values:
- cn-north-4a
status:
phase: Bound
# available : 表示当前的pv没有被绑定
# bound: 已经被pvc挂载
# released: pvc没有在使用pv, 需要管理员手工释放pv
# failed: 资源回收失败
PVC:PersistentVolumeClaim,命名空间(namespace)级别的资源,由用户 or StatefulSet 控制器(根据VolumeClaimTemplate)创建。PVC 类似于 Pod,Pod 消耗 Node 资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存),而 PVC 可以请求特定存储卷的大小及访问模式(Access Mode)。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc-evs-test
namespace: test
uid: xxxx-xxxx-xxxx-22bf9101f0ce
labels:
failure-domain.beta.kubernetes.io/region: cn-north-4
failure-domain.beta.kubernetes.io/zone: cn-north-4a
annotations:
volume.kubernetes.io/selected-node: xxx.xxx.xxx.186
everest.io/disk-volume-type: ESSD
volume.kubernetes.io/storage-provisioner: xxxx-provisioner
spec:
# ReadWriteOnce:被单个节点mount为读写rw模式
# ReadOnlyMany 被多个节点mount为只读ro模式
# ReadWriteMany 被多个节点mount为读写rw模式
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
volumeName: pv-test #绑定的pv name
# 使用的sc类型
storageClassName: csi-disk
# 存储模式,包含Filesystem(文件系统)和Block(块设备)
volumeMode: Filesystem
status:
# Pending:pvc刚创建还未与pv绑定
# Bound: pvc与pv完成绑定
# Lost:对应的pv被删除
phase: Bound
accessModes:
- ReadWriteOnce
SC:StorageClass 是集群级别的资源,由集群管理员创建。SC 为管理员提供了一种动态提供存储卷的“类”模板,SC 中的 .Spec 中详细定义了存储卷 PV 的不同服务质量级别、备份策略等等。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-disk
parameters:
csi.storage.k8s.io/csi-driver-name: disk.csi.everest.io
csi.storage.k8s.io/fstype: ext4
everest.io/disk-volume-type: SATA
everest.io/passthrough: "true"
provisioner: xxxx-provisioner
# 回收策略, pvc和pv解绑,删除了pvc, pv里面的数据是否还保留
# Retain: 保留数据, 需要手工删除
# delete: pv删除
reclaimPolicy: Delete
# Immediate: pv创建好之后立马将pvc和pv进行绑定
# WaitForFirstConsumer: 延迟绑定,直到使用pvc的pod被调度到节点上
volumeBindingMode: Immediate
allowVolumeExpansion: true #是否允许扩容
3、涉及 CSI API 对象
CSINode
- 判断外部 CSI 插件是否注册成功。在 Node Driver Registrar 组件向 Kubelet 注册完毕后,Kubelet 会创建该资源,故不需要显式创建 CSINode 资源
- 将 Kubernetes 中 Node 资源名称与三方存储系统中节点名称(nodeID)一一对应。此处 Kubelet 会调用外部 CSI 插件 NodeServer 的 GetNodeInfo 函数获取 nodeID。
- 显示卷拓扑信息。CSINode 中 topologyKeys 用来表示存储节点的拓扑信息,卷拓扑信息会使得 Scheduler 在 Pod 调度时选择合适的存储节点。
apiVersion: storage.k8s.io/v1
kind: CSINode
metadata:
annotations:
everest.io/node.localvolume.capacity: "null"
name: xxx.xxx.xxx.186
ownerReferences:
- apiVersion: v1
kind: Node
name: xxx.xxx.xxx.186
uid: 091cc415-b8bb-4173-8312-5f6318d4383f
uid: fea2c180-99b8-4195-a966-3953b8bab16a
spec:
# 节点上有哪些driver
drivers:
- allocatable:
count: 58
name: disk.csi.everest.io
nodeID: 7d279bf8-c70f-4179-842e-5e501d591d17
topologyKeys:
- failure-domain.beta.kubernetes.io/zone
- name: proxy.csi.everest.io
nodeID: 7d279bf8-c70f-4179-842e-5e501d591d17
topologyKeys: null
- name: sfsturbo.csi.everest.io
nodeID: 7d279bf8-c70f-4179-842e-5e501d591d17
topologyKeys: null
- name: nas.csi.everest.io
nodeID: 7d279bf8-c70f-4179-842e-5e501d591d17
topologyKeys: null
...
apiVersion: storage.k8s.io/v1
kind: CSINode
metadata:
annotations:
everest.io/node.localvolume.capacity: "null"
name: xxx.xxx.xxx.186
ownerReferences:
- apiVersion: v1
kind: Node
name: xxx.xxx.xxx.186
uid: 091cc415-b8bb-4173-8312-5f6318d4383f
uid: fea2c180-99b8-4195-a966-3953b8bab16a
spec:
# 节点上有哪些driver
drivers:
- allocatable:
count: 58
name: disk.csi.everest.io
nodeID: 7d279bf8-c70f-4179-842e-5e501d591d17
topologyKeys:
- failure-domain.beta.kubernetes.io/zone
- name: proxy.csi.everest.io
nodeID: 7d279bf8-c70f-4179-842e-5e501d591d17
topologyKeys: null
- name: sfsturbo.csi.everest.io
nodeID: 7d279bf8-c70f-4179-842e-5e501d591d17
topologyKeys: null
- name: nas.csi.everest.io
nodeID: 7d279bf8-c70f-4179-842e-5e501d591d17
topologyKeys: null
...
CSIDriver
- 简化外部 CSI 插件的发现。由集群管理员创建,通过 kubectl get csidriver 即可得知环境上有哪些 CSI 插件。
- 自定义Kubernetes 行为,如一些外部 CSI 插件不需要执行卷挂接(VolumeAttach)操作,则可以设置 .spec.attachRequired 为 false。
apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
name: disk.csi.everest.io
uid: 5d33a29b-4bf1-4ab8-815f-e97b207b991e
spec:
# 是否需要attache和mount,只有evs需要attach
attachRequired: true
podInfoOnMount: true
requiresRepublish: false
storageCapacity: false
volumeLifecycleModes:
- Persistent #volume生命周期,持久模式
VolumeAttachment
AD Controller 创建一个 VolumeAttachment,而 External-attacher 则通过观察该 VolumeAttachment,根据其状态属性来进行存储的挂载和卸载操作。
apiVersion: storage.k8s.io/v1
kind: VolumeAttachment
metadata:
annotations:
csi.alpha.kubernetes.io/node-id: xxxx-xxxx-xxxx-5e501d591d17
finalizers:
- everest-csi-attacher/disk-csi-everest-io
name: csi-d10b9f7e4dde469fa2b7f3461fcfef7862260883196647d6b7ae7bb17bc0e226
uid: 665b740f-a544-4f3e-9953-00b8d186c548
spec:
attacher: disk.csi.everest.io
nodeName:xxx.xxx.xxx.186
source:
persistentVolumeName: pv-test
status:
# 标记是否attached到节点上,attache后才能mount
attached: true
attachmentMetadata: #attach的设备信息
bus: scsi
device: /dev/sdg
四、存储拓展-延迟绑定
kubernetes里面有两个绑定:
- kube-schedule将pod和node绑定
- Pvc controller将pvc和pv绑定。正常情况下,kube-schedule绑定pod和node时候,如果pod有pvc,会等待pvc和pv绑定完成后根据pv所在的az选择node过滤一部分不满足节点,然后再完成绑定pod和node。延迟绑定场景,kube-schedule 先不等待PVC和PV绑定,先预调度node,然后把预调度结果写到PVC注解中,pvc控制接获取到预调度az信息后,再完成pv创建和pv绑定。所以,延迟绑定时延迟了pvc和pv绑定阶段。
stroageclass延迟绑定作用字段:VolumeBindingMode
- Immediate :表示一旦创建了 PersistentVolumeClaim 也就完成了卷绑定和动态制备(不参与调度)。 对于由于拓扑限制而非集群所有节点可达的存储后端,PersistentVolume 会在不知道 Pod 调度要求的情况下绑定或者制备。
- WaitForFirstConsumer :该模式将延迟 PersistentVolume 的绑定和制备,直到使用该 PersistentVolumeClaim 的 Pod 被创建。 PersistentVolume 会根据 Pod 调度约束指定的拓扑来选择或制备。 这些包括但不限于资源需求、 节点筛选器、 Pod 亲和性和互斥性、 以及污点和容忍度。
当创建pvc后,kubernetes组件如何协作的更多相关文章
- kubernetes组件
kubernetes组件 @(马克飞象)[k8s] 组件 kubernetes除了必备的dns和网络组件外,官方推出大量的cluster-monitoring,dashboard,fluentd-el ...
- centos7下kubernetes(4.kubernetes组件)
Kubenetes cluster 由master和node组成 Master是kubenetes的大脑.运行着以下进程:kube-apiserver.kube-scheduler.kube-cont ...
- Kubernetes组件与架构
转载请标明出处: 文章首发于>https://www.fangzhipeng.com/kubernetes/2018/09/30/k8s-basic1/ 本文出自方志朋的博客 Kubernete ...
- 使用 C# 开发 Kubernetes 组件,获取集群资源信息
写什么呢 前段时间使用 C# 写了个项目,使用 Kubernetes API Server,获取信息以及监控 Kubernetes 资源,然后结合 Neting 做 API 网关. 体验地址 http ...
- C#创建和使用ActiveX组件
开发基于.Net平台上的程序员是很难从本质上把Visual C#和ActiveX组件联起来,虽然在使用Visual C#开发应用程序时,有时为了快速开发或者由于.Net FrameWork SDK的不 ...
- 多对多三种创建方式、forms组件、cookies与session
多对多三种创建方式.forms组件.cookies与session 一.多对多三种创建方式 1.全自动 # 优势:不需要你手动创建第三张表 # 不足:由于第三张表不是你手动创建的,也就意味着第三张表字 ...
- Vue环境搭建-项目的创建-启动生命周期-组件的封装及应用
vue项目环境的搭建 """ node >>> python:node是用c++编写用来运行js代码的 npm(cnpm) >>> p ...
- Kubernetes【K8S】(一):Kubernetes组件
什么是Kubernetes Kubernetes 是一个可移植的.可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化.Kubernetes拥有一个庞大且快速增长的生态系统. ...
- 构建Docker平台【第三篇】安装 kubernetes 组件
第一步:准备 1. 安装包: kubeadm-1.6.0-0.alpha.0.2074.a092d8e0f95f52.x86_64.rpm kubernetes-cni-0.3.0.1-0.07a8a ...
- 宝塔控制面板创建ftp后链接不上的解决方法
很多的新手在安装宝塔面板并且创建完ftp管理后链接ftp居然链接不上?有许多朋友都不知道本站q302博客也是基于宝塔控制面板管理的,本站在安装网站完成后也和你们一样ftp链接不上,后面经过多次测试之后 ...
随机推荐
- Python 列表操作指南1
Python 列表 mylist = ["apple", "banana", "cherry"] 列表用于在单个变量中存储多个项目.列表是 ...
- Django框架项目——redis操作、Celery
1-redis操作 redis介绍 redis安装 """ 1.官网下载:安装包或是绿色面安装 2.安装并配置环境变量 """ redis ...
- 彻底搞懂Docker容器与Kraft模式kafka集群关于消息大小相关参数设置
Docker部署的设置 部署背景: 在DockerHub拉取的bitnami/kafka:3.4.1 镜像,如果要部署在Docker-Swarm集群或者单Docker部署,对于消息大小设置需要添加参数 ...
- 实验2_C语言分枝与循环基础应用编程
试验任务1 task 1.c #include <stdio.h> #include <stdlib.h> #include <time.h> #define N ...
- CF671D Roads in Yusland 题解
题目链接 题目要求我们求出选出若干条路径并最小化花费,如果这是在链上,我们可以考虑直接枚举每条路径的右端点 dp,那树呢?把路径剖分整个覆盖的集合就不一定连续了,没法 dp,况且题目里给了很强的条件: ...
- 文心一言 VS 讯飞星火 VS chatgpt (125)-- 算法导论10.6 6题
六.用go语言,任意有根树的左孩子右兄弟表示法中每个结点用到三个指针: leftchild.rightsibling 和parent.对于任何结点,都可以在常数时间到达其父结点,并在与其孩子数呈线性关 ...
- 数据结构-线性表-单循环链表(使用尾指针)(c++)
目录 单循环链表 说明 注意 (一)无参构造函数 (二)有参构造函数 (三)析构函数 (四)获取长度 (五)打印数组 (六)获取第i个元素的地址 (七)插入 (八)删除 (九)获取值为x的元素的位置 ...
- .Net Core3中微信退款证书本地调试正常读取证书,在服务器IIS中加载不到证书文件
如图,在开发微信退款功能时,需要用到微信提供的证书文件.本地开发调试时是正常的,但放到服务器(WinServer 2012 R2)中,则报错提示找不到文件. 网上找了一堆骚操作都没什么卵用,最后在其中 ...
- 鸿蒙开发学习(一)之ArkTS
目录 TypeScript语法 基础 module ArkTS 基本UI描述 基本概念 状态管理 页面级变量的状态管理 @State @Prop @Link 应用级变量的状态管理 开发入门 应用模型 ...
- Navicat远程连接Centos8.4服务器MySQL8.0数据库
一.首先登陆服务器后台管理,使服务器开放3306策略 二.开启远程连接 1.登陆服务器的MySQL数据库 mysql -uroot -p 2.登录成功后,切换数据库 use mysql; 3.查看当前 ...