设为首页 收藏本站
查看: 10043|回复: 0

[经验分享] pv和pvc状态

[复制链接]

尚未签到

发表于 2018-1-6 16:40:50 | 显示全部楼层 |阅读模式
原文地址: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设置为非法地址。
  

[iyunv@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状态。
  

[iyunv@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:
  

[iyunv@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
  

  
[iyunv@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)。
  

[iyunv@dev pv]# kubectl delete pv pv3  
persistentvolume "pv3" deleted
  
[iyunv@dev pv]# kubectl get pvc myclaim -o yaml
  
...
  
spec:
  
volumeName: pv3
  
status:
  
phase: Lost
  

  

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

[iyunv@dev pv]# kubectl create -f 1.yaml  
persistentvolume "pv3" created
  
[iyunv@dev pv]# kubectl get pvc myclaim -o yaml
  
...
  
phase: Bound
  

  

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

[iyunv@dev pv]# kubectl delete pvc myclaim  
persistentvolumeclaim "myclaim" deleted
  
[iyunv@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:>  

  

6. Storage不可用
  如果PV的ReclaimPolicy是Recycle,系统会试图mount真实的存储并做删除操作(rm -rm /volume/*),因为我们配置了错误的存储server,Recycle会失败。
  

[iyunv@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。
  

[iyunv@dev pv]# kubectl edit pv pv3  
persistentvolume "pv3" edited
  
[iyunv@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,>  
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处理。


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-432276-1-1.html 上篇帖子: Docker在游戏业务中的应用介绍(转) 下篇帖子: Kubernetes资源管理
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表