记一次在deployment中添加灰度暂停功能

本文详细介绍了如何在Kubernetes Deployment中添加灰度暂停功能,通过对Deployment的源码分析,理解其处理逻辑,特别是Informer的启动和同步流程。文章讨论了在Deployment更新过程中如何触发流程,以及在syncDeployment函数中如何检查并处理paused标志。在设计和测试过程中,作者遇到了比例扩缩的问题,最终找到解决方案,实现了根据annotation设置灰度值并在达到条件时暂停更新的功能。
摘要由CSDN通过智能技术生成

本文主要聊聊如何在k8s deployment中添加灰度暂停功能。因为是基于deployment原本支持的RollingUpdate更新方式 和 pause进行设计,所以文章中大篇幅会对deployment源码阅读分析。
k8s v1.16

deployment 目前处理逻辑

首先deployment是k8s暴露给用户的声明式API,用户通过定义spec(期待模板信息) 和 replicas(实例数)来告知期望状态, deploymentController作为控制循环将监听对应资源 尽力调整为用户期望状态。
k8s提供多种资源,各有特定的Controller,共同包含在kube-controller-manager组件中,运行在master节点上,与apiServer通信。
而驱动这些controller运作的重要部分为Informer,主要负责监听api-server的对象变化后同步到cache,并交给controller.queue去处理。

如何触发deployment更新流程

以下涉及到的主要结构体关系图大致如下
在这里插入图片描述

k8s的各组件使用Cobra库开发,入口为cmd/kube-controller-manager/controller-manager.go

	command := app.NewControllerManagerCommand()
	logs.InitLogs()
	defer logs.FlushLogs()
	
	if err := command.Execute(); err != nil {
   
		os.Exit(1)
	}

初始化command后,command.Execute()将执行command.Run定义的方法,Run的部分代码如下:

		if err := StartControllers(controllerContext, saTokenControllerInitFunc, NewControllerInitializers(controllerContext.LoopMode), unsecuredMux); err != nil {
   
			klog.Fatalf("error starting controllers: %v", err)
		}

		controllerContext.InformerFactory.Start(controllerContext.Stop)
		close(controllerContext.InformersStarted)

以上,主要调用三个函数,调用顺序依次为NewControllerInitializers()StartControllersInformerFactory.Start,逐个看下:

//step1:
// NewConrollerInitializers返回map[Type]ControllerFunc,包含所有类型控制器启动func
// step2:
// 依次为每个类型调用启动每个类型的Controller,以下为deployment的
func startDeploymentController(ctx ControllerContext) (http.Handler, bool, error) {
   
	dc, err := deployment.NewDeploymentController(
		ctx.InformerFactory.Apps().V1().Deployments(),
		ctx.InformerFactory.Apps().V1().ReplicaSets(),
		ctx.InformerFactory.Core().V1().Pods(),
		ctx.ClientBuilder.ClientOrDie("deployment-controller"),
	)
	go dc.Run(int(ctx.ComponentConfig.DeploymentController.ConcurrentDeploymentSyncs), ctx.Stop)
	return nil, true, nil
}

// step3
// 启动总的sharedInformerFactory
func (f *sharedInformerFactory) Start(stopCh <-chan struct{
   }) {
   
	f.lock.Lock()
	defer f.lock.Unlock()

	for informerType, informer := range f.informers {
   
		if !f.startedInformers[informerType] {
   
			go informer.Run(stopCh)
			f.startedInformers[informerType] = true
		}
	}
}

上面step2中,关于ctx.InformerFactory.Apps().V1().Deployments()的部分,将调用以下,返回类型为deploymentInformer

func (v *version) Deployments() DeploymentInformer {
   
	return &deploymentInformer{
   factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}

外层NewDeploymentController又调用以下,

	dInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
   
		AddFunc:    dc.addDeployment,
		UpdateFunc: dc.updateDeployment,
		// This will enter the sync loop and no-op, because the deployment has been deleted from the store.
		DeleteFunc: dc.deleteDeployment,
	})
	// 这两个都是func。
	dc.syncHandler = dc.syncDeployment
	dc.enqueueDeployment = dc.enqueue

先看Informer函数

// 以下为多层嵌套调用,不是顺序调用
//调用InformerFor(),第一个参数为Deployment类型对象,第二个参数调用defaultInformer
func (f *deploymentInformer) Informer() cache.SharedIndexInformer {
   
	return f.factory.InformerFor(&appsv1.Deployment{
   }, f.defaultInformer)
}

// defaultInformer()调用NewFilteredDeploymentInformer
func (f *deploymentInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
   
	
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值