pv和pvc状态
原文地址:https://kubernetes.cn/topics/46
API Server 和 PVController
API Server: 这个组件提供对API的支持,响应REST操作,验证API模型和更新etcd中的相应对象
PVController: 是ontroller.volume.persistentvolume.PersistentVolumeController的简称,负责监听PV和PVC资源的改动Event,取得最新的PV和PVC并维护它们之间的绑定关系。
通常情况下API Server和PVController是运行在一个进程里的,但它们之间通过Rest API通讯,理论上支持分开部署。
K8s里的业务逻辑处理都是在不同的Controller组件里进行,例如大家耳熟能详的Replication Controller,NodeController等。
下图是对这个过程的简单描述:
PV 和 PVC状态图
在我们开始深入PVController细节之前有必要先了解一下PV和PVC的状态切换。可参考前一篇文章了解所有状态的集合。
PV的状态图:
PVC的状态图:
实例演示
为了让大家有更直观的感受,现在我们用一个真实的实例并结合etcd里数据的变化来更好的理解各种状态的切换过程。
结合上面的PV和PVC状态图,这个实例唯一没有覆盖的路径是PV状态图中的序号3(Released到Available),有兴趣的用户可以自行做实验,只要保证PV中的Storage是真实可用的能被Mount到节点上就行。
| 操作 | PV状态 | PVC状态 |
|---|---|---|
| 1. 添加PV | Available | - |
| 2. 添加PVC | Available | Pending |
| Bound | Bound | |
| 3. 删除PV | - | Lost |
| 4. 再次添加PV | Bound | Bound |
| 5. 删除PVC | Released | - |
| 6. Storage不可用 | Failed | - |
| 7. 手动修改PV,删除ClaimRef | Available | - |
下面我会把每步操作后etcd里PV和PVC的关键信息抽取出来,为了避免冗长,只显示和状态相关的信息。
1. 添加PV
刚添加的PV在未被绑定到PVC时是Available状态,为了待会模拟PV由Released变为Failed的状态,这里故意把nfs server ip设置为非法地址。
[root@dev pv]# kubectl get pv pv3 -o yaml
apiVersion: v1
kind: PersistentVolume
metadata:
creationTimestamp: 2017-02-16T08:33:43Z
name: pv3
...
spec:
accessModes:
- ReadWriteOnce
- ReadWriteMany
- ReadOnlyMany
capacity:
storage: 5Gi
nfs:
path: /var/nfsshare/v1
server: 172.16.51.58.1
persistentVolumeReclaimPolicy: Recycle
status:
phase: Available
2. 添加PVC
刚添加的PVC的状态是Pending,如果有合适的PV,这个Pending状态会立刻变为Bound,同时相应的PVC也会变为Bound。 你也可以先添加PVC,后添加PV,这样就能保证看到Pending状态。
[root@dev pv]# kubectl get pvc myclaim -o yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
creationTimestamp: 2017-02-16T08:45:53Z
name: myclaim
namespace: test
...
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
status:
phase: Pending
然后PV和PVC都变为Bound:
[root@dev pv]# kubectl get pvc myclaim -o yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
pv.kubernetes.io/bind-completed: "yes"
...
uid: 534338ef-f424-11e6-8ab8-000c29a5bb07
spec:
...
status:
...
phase: Bound
[root@dev pv]# kubectl get pv pv3 -o yaml
apiVersion: v1
kind: PersistentVolume
metadata:
annotations:
pv.kubernetes.io/bound-by-controller: "yes"
...
name: pv3
...
spec:
...
claimRef:
apiVersion: v1
kind: PersistentVolumeClaim
name: myclaim
namespace: test
uid: 534338ef-f424-11e6-8ab8-000c29a5bb07
persistentVolumeReclaimPolicy: Recycle
status:
phase: Bound
3. 删除PV
删除PV后,PVC状态变为Lost。请看PVC状态图,Lost状态是没办法变回Pending的,这是即使有其它可用的PV,也不能被PVC使用,因为PVC中还保留对PV的引用(volumeName:pv3)。
[root@dev pv]# kubectl delete pv pv3
persistentvolume "pv3" deleted
[root@dev pv]# kubectl get pvc myclaim -o yaml
...
spec:
volumeName: pv3
status:
phase: Lost
4. 再次添加PV
再次把刚才的PV添加回来后,PV会被自动绑定到PVC,PVC再次变为Bound。
[root@dev pv]# kubectl create -f 1.yaml
persistentvolume "pv3" created
[root@dev pv]# kubectl get pvc myclaim -o yaml
...
phase: Bound
5. 删除PVC
删除PVC后,PV状态变为Released,请注意这时PV中还保留对PVC的引用(spec.claimRef)。
[root@dev pv]# kubectl delete pvc myclaim
persistentvolumeclaim "myclaim" deleted
[root@dev pv]# kubectl get pv pv3 -o yaml
...
spec:
accessModes:
- ReadWriteOnce
- ReadWriteMany
- ReadOnlyMany
capacity:
storage: 5Gi
claimRef:
apiVersion: v1
kind: PersistentVolumeClaim
name: myclaim
...
persistentVolumeReclaimPolicy: Recycle
status:
phase: Released
6. Storage不可用
如果PV的ReclaimPolicy是Recycle,系统会试图mount真实的存储并做删除操作(rm -rm /volume/*),因为我们配置了错误的存储server,Recycle会失败。
[root@dev pv]# kubectl get pv pv3 -o yaml
...
claimRef:
apiVersion: v1
kind: PersistentVolumeClaim
name: myclaim
...
phase: Failed
7. 手动修改PV,删除ClaimRef
这时就需要手工干预了,真实生产环境下管理员会把数据备份或迁移出来,然后修改PV,删除claimRef对PVC的引用,k8s会接受到PV变化的Event,将PV状态修改为Available。
[root@dev pv]# kubectl edit pv pv3
persistentvolume "pv3" edited
[root@dev pv]# kubectl get pv pv3 -o yaml
...
status:
phase: Available
PVController 构建和启动
构建
构建过程会创建PVController运行所需要的所有子组件,为了便于理解,这里省去了参数的传递过程,在代码片段里也只是保留了主要的逻辑处理,有兴趣的用户可以自行下载代码研究。
func NewPersistentVolumeController(
kubeClient clientset.Interface,
syncPeriod time.Duration,
alphaProvisioner vol.ProvisionableVolumePlugin,
volumePlugins []vol.VolumePlugin,
cloud cloudprovider.Interface,
clusterName string,
volumeSource, claimSource, classSource cache.ListerWatcher,
eventRecorder record.EventRecorder,
enableDynamicProvisioning bool,
) *PersistentVolumeController {
// eventRecorder 用于记录异常和关键信息,以Event资源形式记录在API Server并和event的来源建立绑定关系,
// 用kubectl describe 可以看到某种Resource上的event。
if eventRecorder == nil {
broadcaster := record.NewBroadcaster()
broadcaster.StartRecordingToSink(&unversioned_core.EventSinkImpl{Interface: kubeClient.Core().Events("")})
eventRecorder = broadcaster.NewRecorder(api.EventSource{Component: "persistentvolume-controller"})
}
// 初始化一个新的PVController实例,volumes用于缓存最新的PV,claims用于缓存最新的PVC。
// kubeClient用于和API Server交互。
controller := &PersistentVolumeController{
volumes: newPersistentVolumeOrderedIndex(),
claims: cache.NewStore(framework.DeletionHandlingMetaNamespaceKeyFunc),
kubeClient: kubeClient,
eventRecorder: eventRecorder,
...
}
// volumeSource 主要有两个功能:1. 用于请求API Server 得到最新的PV列表。 2. 用于接收API Server发过来的PV变动的Event
//
if volumeSource == nil {
volumeSource = &cache.ListWatch{
ListFunc: func(options api.ListOptions) (runtime.Object, error) {
return kubeClient.Core().PersistentVolumes().List(options)
},
WatchFunc: func(options api.ListOptions) (watch.Interface, error) {
return kubeClient.Core().PersistentVolumes().Watch(options)
},
}
}
controller.volumeSource = volumeSource
//claimSource 主要有两个功能:1. 用于请求API Server 得到最新的PVC列表。 2. 用于接收API Server发过来的PVC变动的Event
//
if claimSource == nil {
claimSource = &cache.ListWatch{
ListFunc: func(options api.ListOptions) (runtime.Object, error) {
return kubeClient.Core().PersistentVolumeClaims(api.NamespaceAll).List(options)
},
WatchFunc: func(options api.ListOptions) (watch.Interface, error) {
return kubeClient.Core().PersistentVolumeClaims(api.NamespaceAll).Watch(options)
},
}
}
controller.claimSource = claimSource
...
// volumeController会被启动为一个GoRoutine(类似线程,但更轻量),接收并处理PV的add/delete/update Event
//
_, controller.volumeController = framework.NewIndexerInformer(
volumeSource,
&api.PersistentVolume{},
syncPeriod,
framework.ResourceEventHandlerFuncs{
AddFunc: controller.addVolume,
UpdateFunc: controller.updateVolume,
DeleteFunc: controller.deleteVolume,
},
cache.Indexers{"accessmodes": accessModesIndexFunc},
)
// claimController会被启动为一个GoRoutine,接收并处理PVC的add/delete/update Event
//
_,controller.claimController=framework.NewInformer(claimSource,&api.PersistentVolumeClaim{},syncPeriod,framework.ResourceEventHandlerFuncs{AddFunc:controller.addClaim,UpdateFunc:controller.updateClaim,DeleteFunc:controller.deleteClaim,},)...returncontroller}
启动
启动过程比较简单,只是把volumeController和claimController启动到新的Goroutine里,这两个子Controller开始接收PV和PVC更新的Event并会触发相应的处理。 从构建过程可以看出:这两个子Controller会处理六种Event通知,分别是PV的add/delete/update和PVC的add/delete/update.
// Run starts all of this controller's control loops
func (ctrl *PersistentVolumeController) Run(stopCh <-chan struct{}) {
glog.V(4).Infof("starting PersistentVolumeController")
ctrl.initializeCaches(ctrl.volumeSource, ctrl.claimSource)
go ctrl.volumeController.Run(stopCh)
go ctrl.claimController.Run(stopCh)
}
PVController 工作流程解析
这部分会介绍PVController的主要职责,处理上面提到的六种Event通知,重新计算PV和PVC的绑定关系并把绑定关系通过API Server持久化。
add/delete/update PV
这三个方法都是先把Event中的最新PV更新到缓存中,然后调用syncVolume处理。可见syncVolume是一个通用的方法,逻辑比较复杂,因为要考虑到所有可能的PV更新类型。
说明:
unbindPV 会删除PV中对PV的引用然后调用API Server持久化,API Server会再生成一个PV更新的Event并通知PVController,从而使syncVolume再次被调用,但是这次会走不同的分支并把PV设置为Released
Fun:storeObjectUpdate 会更新本地缓存和API Server
Fun: reclaimVolume 的详情如下图:
add/delete/update PVC
这三个方法都是先把Event中的最新PVC更新到缓存中,然后调用syncClaim处理。

pv和pvc状态的更多相关文章
- Kubernetes集群PV和PVC详解
Kubernetes集群高级存储资源PV及PVC 文章目录 Kubernetes集群高级存储资源PV及PVC 1.高级存储PV和PVC概念部分 2.PV和PVC资源的生命周期 3.PV资源介绍与案例配 ...
- kubernetes系列11—PV和PVC详解
本文收录在容器技术学习系列文章总目录 1.认识PV/PVC/StorageClass 1.1 介绍 管理存储是管理计算的一个明显问题.该PersistentVolume子系统为用户和管理员提供了一个A ...
- K8s存储卷、pv和pvc的使用
emptyDIR 临时目录 hostPath :使用主机的路径 网络存储: 传统的设备存储:NAS,SAN 分布式存储:glusterfs,rbd,cephfs 云存储:EBS,Azure,阿里云的 ...
- PV、PVC和Storeclass等官方内容翻译
k8s1.13版本 PV apiVersion: v1 kind: PersistentVolume metadata: name: filesystem-pvc spec: capacity: #未 ...
- K8S 使用NFS 创建PV和PVC的例子 学习From https://blog.csdn.net/xts_huangxin/article/details/51494472
1. 获取资料 网址: https://blog.csdn.net/xts_huangxin/article/details/51494472 感谢原作者 这里面 按照自己的机器情况进行了学习模仿 ...
- Kubernetes 中的pv和pvc
原文地址:http://www.cnblogs.com/leidaxia/p/6485646.html 持久卷 PersistentVolumes 本文描述了 Kubernetes 中的 Persis ...
- k8s的pv和pvc简述
pvc:资源需要指定:1.accessMode:访问模型:对象列表: ReadWriteOnce – the volume can be mounted as read-write by a s ...
- PV、PVC、StorageClass讲解
PV.PVC.StorageClass讲解 为了方便开发人员更加容易的使用存储才出现的概念.通常我们在一个POD中定义使用存储是这样的方式,我们以hostpath类型来说: apiVersion: v ...
- Kubernetes 系列(六):持久化存储 PV与PVC
在使用容器之后,我们需要考虑的另外一个问题就是持久化存储,怎么保证容器内的数据存储到我们的服务器硬盘上.这样容器在重建后,依然可以使用之前的数据.但是显然存储资源和 CPU 资源以及内存资源有很大不同 ...
随机推荐
- nginx中使用 md5
core/ngx_md5.h 头文件 /* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #ifndef _NGX_MD5_H_ ...
- QLoo graphql engine了解
参考架构图 处理流程 使用gloo注册服务api 发现断电以及serverless 函数 更新graphql schema 在qloo的resolvermap 中连接schema定义的字段 特性 不用 ...
- maven学习--基础篇
2016-01-5 16:13:43 发现一些错误,文章修改中…… (部分图片截取自其他地方,不是很清楚) 一. maven的项目创建和基本命令 maven是一个项目管理工具,包含了一个项目对象模型P ...
- 不以main为入口的函数
先看一段程序 #include <stdio.h> void test() { printf("Hello Word!\n"); return 0; } 没有main函 ...
- ASP/ASP.NET/VB6文件上传
1. asp asp 上传文件真的蛋疼,很麻烦,有时候就用第三方组件,或者比较复杂的写法来实现无组件上传. 测试OK的一个叫风声无组件上传类 V2.1 [Fonshen UpLoadClass Ver ...
- bat文件
bat文件是dos下的批处理文件.批处理文件是无格式的文本文件,它包含一条或多条命令.它的文件扩展名为 .bat 或 .cmd.在命令提示下键入批处理文件的名称,或者双击该批处理文件,系统就会调用cm ...
- Vue基础知识之过滤器(四)
过滤器 1.过滤器的用法,用 '|' 分割表达式和过滤器. 例如:{{ msg | filter}} {{msg | filter(a)}} a就标识filter的一个参数. 用两个过滤器:{{msg ...
- linux nginx安装以及配置
一.Nginx简介 Nginx (“engine x”) 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器.Nginx是由Igor Sysoev为俄罗斯访问量第二的R ...
- 初尝微信小程序开发与实践
这可能是一个java程序员最不务正业的一次分享了. 小程序的火热相信不用我多说了,年初的时候老婆去浦东某达面试,甚至都被问有没有小程序测试经验.俨然小程序成为了互联网公司自PC,WAP,安卓,IOS之 ...
- Phython智能分词开发
Git/GitHub 一.开发环境安装 1.安装Anaconda 官方下载地址:https://www.anaconda.com/download/ Anaconda自带Flask 2.安装模块/插件 ...