前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kubernetes Pod优雅停机分析

Kubernetes Pod优雅停机分析

原创
作者头像
白鹏飞
发布2023-06-14 20:58:37
7210
发布2023-06-14 20:58:37
举报
文章被收录于专栏:拥抱云原生拥抱云原生

一 背景说明

业务容器化上云之后,时常会有版本的动态变更,如何无损升级越发重要。结合底层技术原理,本文将对Pod优雅停机展开分析,供业务团队参考。

二 技术原理

绕过平台控制器,以及kubelet组件复杂的sync、manager逻辑,Pod被删除或者被节点压力驱逐后,Node Kubelet组件都会走到一个内部函数:killContainer()。killContainer内部再调用runtimeService接口StopContainer,走到CRI运行时层面,完成进程的停止(sigterm)、杀死(sigKill)。

2.1 KillContainer函数

先来看下killContainer函数:

(1)从注释上不难看出,函数主体大致可分为2步:如果有preStop逻辑,先Run一下;然后走StopContainer逻辑

代码语言:javascript
复制
// killContainer kills a container through the following steps:
// * Run the pre-stop lifecycle hooks (if applicable).
// * Stop the container.

(2)结合代码,可以看到kubelet内置了一个2s 的优雅终止时间,如果业务Pod没有配置TerminationGracePeriodSeconds,就会使用这个默认值(minimumGracePeriodInSeconds)。

(3)如果用户Pod配置了preStop 生命周期hook且gracePeriod>0, 执行preStopHook逻辑;

这里gracePeriod,将会作为preStopHook执行的超时时间。所以,日常实践中,Pod TerminationGracePeriodSeconds配置需要大于preStop 执行的时间——需要注意。

(4)从killContainer代码中,也不难发现,preStopHook执行的时间(如果有的话),会算在整体的gracePeriod中。GracePeriod扣除之后,走到StopContainer逻辑,作为其stop 容器的超时参数timeout。

2.2 StopContainer函数

以containerd 运行时为例,runtimeService的StopContainer,会继续调用CRI接口,经GRPC调用到运行时层面:

kubelet 调用逻辑:

containerd stopContainer 方法具体实现:

代码解读:

> timeout>0 , 发sigterm 信号,终止容器;

> timeout<=0, 或者上述sigterm 逻辑结束,发sigkill信号,杀死容器;

三 优雅停机Demo

这里分享一个优雅停机的golang实例,供交流参考:

3.1 信号处理逻辑

代码语言:javascript
复制
var onlyOneSignalHandler = make(chan struct{})
var shutdownHandler chan os.Signal
var shutdownSignals = []os.Signal{syscall.SIGTERM, syscall.SIGKILL}

// SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned
// which is closed on one of these signals. If a second signal is caught, the program
// is terminated with exit code 1.
func SetupSignalHandler() <-chan struct{} {
	close(onlyOneSignalHandler) // panics when called twice

	shutdownHandler = make(chan os.Signal, 2)

	stop := make(chan struct{})
	signal.Notify(shutdownHandler, shutdownSignals...)
	go func() {
		<-shutdownHandler
		close(stop)
		sig := <-shutdownHandler
		if sig == syscall.SIGKILL {
			os.Exit(1) // if sigkill signal. Exit directly.
		}
	}()

	return stop
}

(1)处理信号sigterm、sigkill;

(2)只在收到sigkill信号,才立即exit 1 退出运行;

3.2 Main函数

代码语言:javascript
复制
func main() {
	logs.Info("server started")
	stop := util.SetupSignalHandler()
	tick := time.NewTicker(time.Second * 3)

	//business logic
	exit := false
	for {
		select {
		case <-stop:
			exit = true
		case <-tick.C:
			logs.Info("loop once")
		}

		if exit {
			break
		}
	}

	logs.Info("grace shutting down 120 seconds...")
	time.Sleep(time.Second * 120)
	logs.Info("server end")
}

(1) select 逻辑收到stop 信号,才会退出for 循环,模拟业务运行逻辑;

(2)sleep 120s,模拟grace shutdown 优雅停机时的收尾逻辑;

4 小结

由此可见,业务pod 实现优雅停机的必要条件,包含:

(1)pod 内部业务支持sigterm、sigkill 信号的分别处理,前者优雅shutdown、后者直接退出;

(2)配置合理的pod终止宽限期:TerminationGracePeriodSeconds;

(3)必要时Pod可以配置preStop hook;

参考

https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination

https://github.com/kubernetes/kubernetes

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一 背景说明
  • 二 技术原理
    • 2.1 KillContainer函数
      • 2.2 StopContainer函数
      • 三 优雅停机Demo
        • 3.1 信号处理逻辑
          • 3.2 Main函数
            • 4 小结
            • 参考
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
            http://www.vxiaotou.com