Kubernetes源码解析之controller-manager deployment同步流程

本文深入解析Kubernetes controller-manager在Deployment的syncDeployment和syncReplicaSet过程,详细阐述了Deployment的更新、回滚、暂停恢复流程以及更新策略,包括RollingUpdate和Recreate。同时探讨了Label、Selector和OwnerReference的作用,以及ControllerManager如何通过Informer处理事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本使用

1 简单的yaml文件

在K8s集群上可使用Kubectl命令以指定文件方式创建一个kind=Deployment的资源对象
$ kubectl create -f nginx.yaml

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nginx
  
spec:
  replicas: 3
    template:
      metadata:
        labels:
          app: nginx
      spec:
        containers:
        - name: nginx
         image: nginx:1.9.1

下图分别为 在终端查看生成的DeployMent, ReplicaSet, pod资源,以及他们之前的拓扑关系图(可以先忽略oldReplicaSet)
图1
在这里插入图片描述
如图,k8s根据yaml中指定的spec.replicas值为我们创建3个pod,并在deployment整个运行周期中维护这个数量,然后根据spec.template.spec中的container数组配置,将容器组启动在每个pod中。
这是一个简单创建deployment任务过程。

2 更新及回滚

Deployment作为一个大数据结构(yaml文件)控制维护我们的业务,我们通过更新这个yaml文件来更新业务部署。

上节提到spec.template下是具体pod要启动的业务及配置,只有对spec.template进行更新才会触发pod重新部署(横向扩缩容不触发重新部署)

命令行支持两种更新方式,更新后自动触发deployment更新
更新结果是根据deployment中配置的replicas数和spec.template中定义的模板,生成pod。然后清理上版本的旧pod。

//直接使用 kubectl set 更新对象
$ kubectl set image deployment/nginx  nginx=nginx:1.9.1
//直接更新nginx yaml文件
$ kubectl edit deployment/nginx

此时观察到系统中存在两个replicaSet,如果正常发布,Dp拥有两个Rs,新版Rs下维护3个pod,旧版下0个,k8s默认为我们保留更新过的版本,方便我们回滚版本使用。
以下是一个更新及回滚过程中Rs的状态
(初次发布后Rs状态 -> set修改镜像触发更新 -> 新pod生成旧版本下pod被清理 -> 回滚 -> "旧"版本pod被重建,"新"版本pod被清理)
在这里插入图片描述
以上为基本的更新/回滚流程。两个问题:

  1. 过程描述中,回滚后的新旧版本被我加了双引号
  2. 倒数第2次get Rs信息,发现版本之间数量的变化并非单独的清理旧版,发起新版。
    (后面读源码将讲到)
暂停与恢复

暂停态时,对spec.template资源的更新都不会生效。恢复状态后,再执行更新操作。官方现在给的解释为:暂停态为支持多次更新配置而不用触发更新。
命令:

$ kubectl rollout pause deployment/nginx  //暂停
$ kubectl rollout resume  deployment/nginx  //恢复

因为不会触发更新,所以理论上也不支持回滚。在暂停态时,发起回滚属于非法操作。

STATUS

Dp结构体主要包含3个部分:
* ObjectMeta 元数据
* DeploymentSpec Dp任务期望状态
* Status 处理状态

其中Meta由用户指定一部分,另一部分系统维护。DpSpec基本由用户指定,Status完全基本由系统控制,在同步过程中对此状态进行参考修改。

我目前根据Dp配置中的condition判断k8s在处理过程中的状态:
在这里插入图片描述

以上表示两项结果:
  • Available 服务是否达到可用状态(可自定义livenessProbe、readinessProbe等来指定服务可用标志,默认pod内容器正常启动即为可用),图中此项status为True,原因为满足用户期望的最小可用实例数
  • Progressing 指Dp收到的最近一个更新请求是否完成。例如回滚操作,指定时间内达到用户预期结果status将置为true,否则为False并设置错误原因。指定时间由spec.progressDeadlineSecond参数指定,Pause状态时此值不定义超时。 (此处更新指所有对Dp的更新,包括水平扩容操作)

概念

Label、Seletor and OwnerReference

观察本文图1,发现资源名的特点:
创建Dp时,我们定义nginx为name;Dp生成的Rs名均为nginx-hashstr;Rs又创建多个pod,pod名为rs-hashstr

假定Dp->Rs->Pod是一个从上到下的关系,那k8s通过上层selector和下层labels来确认下属于上,同时下层会保存上层的metaUid信息,用于所属确认和垃圾回收。

我通过–show-labels 来查看三项资源的lebels信息:
在这里插入图片描述
如上,Dp通过 app=roll 来确定Rs,但是不同版本Rs之间必须有差别,所以创建Rs时引入pod-template-hash作为selector 和 labels,并将其复制给pod.labels,这样在dp下同时存在两个版本时,多个Rs可以接管各自的pod

在这里插入图片描述

Rs和Pod中,都保存了ownerReferences信息。uid为所属Dp.uid。有两项用处(以获取dp下拥有的rs为例):
  • 遍历检查rs.labels,首先检查并确认dp.selector需要是它的子集。然后检查rs.ownerReferences,确认为Dp信息时,表示此Rs属于Dp
  • 删除Deployment时,仅操作Dp资源。检查Rs时,通过确认其uid标识的owner已被删除,确认是不是清理当前Rs资源

ControllerManager源码阅读

简单介绍一下事件处理前的如何获取事件集:
为了减轻对apiserver的压力,客户端存在一个Informer,它负责从apiserver端同步发生变更的数据到store,然后从store中读取需要处理的事件调用相应的Handler。
deploymentController会启动多个worker去接收store中的deployment-key,Handler处理函数为syncDeployment

syncDeployment
func (dc *DeploymentController) syncDeployment(key string) error {
   
	//由key值获取Dp的namespaces和name
	namespace, name, err := cache.SplitMetaNamespaceKey(key)
	
	//根据ns、name从系统中获取deployment当前信息(此时有可能已被delete,在处理同步中会不断检查删除状态)
	deployment, err := dc.dLister.Deployments(namespace).Get(name)
	
	//deepcopy信息,更新状态时更新拷贝信息然后将副本更新到server
	d := deployment.DeepCopy()

	//行为:获取属于当前Dp的所有Rs,同时进行一些adopt和release操作
	rsList, err := dc.getReplicaSetsForDeployment(d)
	
	//获取rs列表下的所有pod,返回Map(key为Rs.UID  value为PodList)
	podMap, err := dc.getPodMapForDeployment(d, rsList)
	
	//如果Pod已经被delete,调用getAllReplicaSetsAndSyncRevision更新版本信息,并同步状态信息。不明白这里,为什么已删除还要同步状态
	if d.DeletionTimestamp != nil {
   
		return dc.syncStatusOnly(d, rsList)
	}

	//检查是否为暂停或恢复事件。
	//暂停时将condition中Progressing中 status=Unknown reason=DpPaused,此时不对其进行处理超时等检查
	//检查为恢复请求并且当前为暂停时,更新Progressing为 status=Unknown reason=DpResume
	if err = dc.checkPausedConditions(d)

	//暂停态时,执行sync同步状态(本节会单独分析函数)
	if d.Spec.Paused {
   
		return dc.sync(d, rsList)
	}

	//检查有回滚事件时,回滚版本(下节会分析此函数)
	if getRollbackTo(d) != nil {
   
		return dc.rollback(d, rsList)
	}

	//发现desire与dp.replicas不符时,确定为正在进行扩缩容事件,调用sync同步
	scalingEvent, err := dc.isScalingEvent(d, rsList)
	if scalingEvent {
   
		return dc.sync(d, rsList)
	}

	//根据两种发布策略检查并更新deployment到最新状态(下节会分析处理函数)
	switch d
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值