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 ControllerNodeController等。

下图是对这个过程的简单描述:

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设置为非法地址。

[[email protected] 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状态。

[[email protected] 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:

[[email protected] 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

[[email protected] 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)。

[[email protected] pv]# kubectl delete pv pv3
persistentvolume "pv3" deleted
[[email protected] pv]# kubectl get pvc myclaim -o yaml
...
spec:
volumeName: pv3
status:
phase: Lost
4. 再次添加PV

再次把刚才的PV添加回来后,PV会被自动绑定到PVC,PVC再次变为Bound。

[[email protected] pv]# kubectl create -f 1.yaml
persistentvolume "pv3" created
[[email protected] pv]# kubectl get pvc myclaim -o yaml
...
phase: Bound
5. 删除PVC

删除PVC后,PV状态变为Released,请注意这时PV中还保留对PVC的引用(spec.claimRef)。

[[email protected] pv]# kubectl delete pvc myclaim
persistentvolumeclaim "myclaim" deleted
[[email protected] 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会失败。

[[email protected] 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。

[[email protected] pv]# kubectl edit pv pv3
persistentvolume "pv3" edited
[[email protected] 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处理。

时间: 03-05

pv和pvc状态的相关文章

Kubernetes的系统架构与设计理念

Kubernetes与云原生应用简介 随着Docker技术的发展和广泛流行,云原生应用和容器调度管理系统也成为IT领域大热的词汇.事实上,云原生应用的思想,在Docker技术火爆之前,已经由云计算技术的领导者和分布式系统架构的推广者广泛传播,例如云原生应用的12要素早在2011年就由Heroku的工程师提出了:只不过以虚拟机技术作为云原生应用的基础实施,由于虚拟机镜像大.镜像标准不统一以及打包流程和工具不统一,无法业界广泛接受的云原生应用标准,限制了云原生应用的流行.而Docker的出现正好解决

同时面向运维和开发的企业级PaaS平台--OpenShift

大卫说:笔者在年初分享过一篇文章<大卫看Docker-第一篇>.文中介绍了Docker一些基本概念.本文同时作为<大卫看Docker-第二篇>而存在.     随着容器技术的兴起,越来越多的人都在关注这项技术.既然Docker是一项很不错的技术,如何将它应用到企业中呢?对此,红帽的提供了基于容器的.同时面向运维和开发的企业级开源PaaS解决方案. 此前文章已经提到过,红帽作为开源界的领导者,其所有企业级解决方案在社区都有对应的开源项目,openshift也不例外.2011年,Red

磁盘管理之逻辑卷(转载)

写在前面: 本文一共分个部分来讲解逻辑卷的一些操作及注意事项,其中第一部分介绍了什么是逻辑卷,逻辑卷的实现原理是什么,还有包括其中的一些名词解释;第二部分主 要是介绍怎么创建,删除,和增加物理卷(PV);第三部分是介绍怎么创建,删除,扩展,缩减卷组;第四部分主要是介绍逻辑卷的一些操作,其中包括逻辑卷的 创建,删除,挂载,在线扩容,缩减.第五部分是介绍关于LVM的快照功能及实现.实验操作是在centos6.8操作系统上完成,如有补充,或建议请尽情 的揉虐我的留言区.   一.逻辑卷介绍及名词解释

LVM原理和实践

LVM原理和实践 目录:    一:LVM原理详解    二:LVM创建    三:LVM的增大和放缩    四:LVM快照    五:相关扩展阅读 一:LVM原理详解1.LVM是什么?    LVM是linux系统上的一个逻辑卷管理器有两个版本lvm1和lvm2现在默认是lvmm2,lvm2兼容lvm1但是对于lvm1的快照是不兼容的,所以如果你使用lvm1创建了快照,请在升级为lvm2的时候将快照卷卸载Lvm2使用的是设备映射器(device mapper)2.6版本的内核有其驱动,2.4的

cf596d

题意:有一排等高的树木,高度都为h.给出每棵树在数轴上的坐标,每次有可能是最左边或者最右边的立着的树倒下,概率都是0.5.最终所有树都倒下.每棵树在倒下的时候有p的概率向左倒,1-p的概率向右倒.如果某些树之间的距离小于h,那么倒下的时候可能产生连带效应.问最后所有树都倒下时,在数轴上覆盖的线段的总长度是多少. 分析:概率DP求期望:我们以前学过的求期望的方法是每种结果出现的概率乘以每种结果的值,然后相加.但是通常解决这类问题我们都要对每个中间状态求期望值,最终算出总的期望.这时我们就可以把每个

磁盘管理之逻辑卷

写在前面: 本文一共分个部分来讲解逻辑卷的一些操作及注意事项,其中第一部分介绍了什么是逻辑卷,逻辑卷的实现原理是什么,还有包括其中的一些名词解释;第二部分主要是介绍怎么创建,删除,和增加物理卷(PV);第三部分是介绍怎么创建,删除,扩展,缩减卷组;第四部分主要是介绍逻辑卷的一些操作,其中包括逻辑卷的创建,删除,挂载,在线扩容,缩减.第五部分是介绍关于LVM的快照功能及实现.实验操作是在centos6.8操作系统上完成,如有补充,或建议请尽情的揉虐我的留言区. 一.逻辑卷介绍及名词解释 逻辑卷是一

Kubernetes有状态应用管理——PetSet

1.介绍 在Kubernetes中,大多数的Pod管理都是基于无状态.一次性的理念.例如Replication Controller,它只是简单的保证可提供服务的Pod数量.如果一个Pod被认定为不健康的,Kubernetes就会以对待牲畜的态度对待这个Pod--删掉.重建.相比于牲畜应用,PetSet(宠物应用),是由一组有状态的Pod组成,每个Pod有自己特殊且不可改变的ID,且每个Pod中都有自己独一无二.不能删除的数据. 众所周知,相比于无状态应用的管理,有状态应用的管理是非常困难的.有

10.6 监控io性能 - 10.7 free命令 - 10.8 ps命令 - 10.9 查看网络状态 - 10.10 linux下抓包

- 10.6 监控io性能 - 10.7 free命令 - 10.8 ps命令 - 10.9 查看网络状态 - 10.10 linux下抓包 - 扩展tcp三次握手四次挥手 http://www.doc88.com/p-9913773324388.html  - tshark几个用法:http://www.aminglinux.com/bbs/thread-995-1-1.html  # 10.6 监控io性能 ![mark](http://oqxf7c508.bkt.clouddn.com/b

PV操作,我终于懂你了!

上个星期,米老师给我们讲课实在是精彩!本人终于对Pv操作有了自己的理解.之前一直不太理解Pv操作,现在总结一下,以供下阶段学习和总结. 为什么叫PV操作?原因是:这是狄克斯特拉用荷兰文定义的,因为在荷 兰文中,通过叫passeren,释放叫vrijgeven,PV操作因此得名. 这张图乍一看谁也不知道我想说明什么.我想通过这张图来给大家解释一下PV操作! 中间这加粗的黑线是秤杆,就像我们生活中的上下控制的电源开关!只有两个状态,一个是向上,一个是向下. 这张图的上面是消费者(儿子),对于消费者来