k8s pod 中的程序为啥服务优雅关闭不生效?收不到 sigterm 信号?

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 咱们工作的环境在不断的变好,我们也会思考去提升程序运行的环境,让我们的服务更加容易部署,极简维护,现在很多公司都在向着 devpos 发展,殊不知已经被某些大企玩剩下了

咱们工作的环境在不断的变好,我们也会思考去提升程序运行的环境,让我们的服务更加容易部署,极简维护,现在很多公司都在向着 devpos 发展,殊不知已经被某些大企玩剩下了

不过没关系,路得一步一步的走,饭得一口一口的吃,这样我们才会走的稳,长的好

情况描述:

起初我们还是主机环境的时候,使用 ansible 来一键部署我们主机环境上的服务,对于我们的服务自然也是做无状态的

对于服务我们有做优雅关闭,简单来说,就是当程序收到 sigterm 等关闭信号的时候,咱们的服务不会一下子断掉,服务会将当前手里的事情迅速做完再关闭咱们的服务

例如咱们一般在 golang 里面会这样来实现:

stopChan := make(chan os.Signal)
// bind OS events to the signal channel
signal.Notify(stopChan,  syscall.SIGTERM)
// 优雅关闭咱们的服务
defer func() {
       log.Println("closing....")
       // xxxx 做关闭的动作
       // TODO ...
}()
// 阻塞等待关闭信号
select {
case <-stopChan:
}

相信对于熟悉 golang 的兄弟对于这个已经不再陌生了,这个会有啥问题呢?

当然,对于在主机环境里面我们过去都跑了很久了,优雅关闭的功能都是正常运行的,久而久之,就没有人关注他了


开始应用 k8s 来部署我们的服务

慢慢的我们过渡到了容器化的方式来部署我们的服务

一般使用容器化,我们回去编写 Dockerfile ,写我们的启动脚本,做成镜像,进而做成 helm 包,推到 helm 仓库中,在环境中我们就可以使用 helm 工具来高效的部署咱们的服务了,此处就过多赘述了,感兴趣的可以查看如下 2 篇历史文章:

实际情况上,服务在线上跑了一年多了,最近要做一个需求,涉及到服务被 kill 的时候,要到优雅关闭中做一些事情,例如清空某些过程数据

万万没想到,正是优雅关闭在 k8s 部署的时候出了问题,还记当刚才我们说到的在 k8s 中部署的时候,咱们会写启动脚本吗?,例如启动脚本是这样的:

start.sh

#!/bin/bash
./my_demo_svr

例如我们的 Dockerfile 是这样的(仅做示例):

FROM centos
ADD my_demo_svr /
ADD start.sh /
ENTRYPOINT ["sh", "start.sh"]

正是因为咱们在容器中是通过 shell 脚本来启动咱们的 my_demo_svr 服务,那么实际情况是这样来的

bash(xxxpid) --- shell(xxpid) --- my_demo_svr(xxxpid)

那就相当于 my_demo_svr 是 shell 的子进程,shell 收到 k8s 发送的 sigterm 信号的时候,是不会传递给子进程 my_demo_svr 的,因此 my_demo_svr 是不会进行优雅关闭的

看到这里,实际上我们处理的思路就是:

  • 如何让 shell 收到 sigterm 信号的时候,可以传递给他的子进程

实际应用了两种方式

  • 在脚本中,实际启动程序的时候 我们加上 exec 命令exec 命令可以用于调用并执行命令,我们可以这样来修改
#!/bin/bash
exec ./my_demo_svr

简单的修改了这个脚本之后,咱们的 my_demo_svr 程序会替换 shell,并且不会出现子进程,此时 k8s 发送 sigterm 信号的时候,那么接收信号的直接就是 my_demo_svr 服务,此时的优雅关闭就可以正常触发了

  • 使用 linux 中的 trap 命令

trap 命令,可以用来传递信号,我们正好就可以应用它来解决我们的实际问题

例如我们就可以这样来写

此处要注意,咱们的服务启动后面是有 & 的,让我们的 my_demo_svr 在后台运行

#!/bin/sh
./my_demo_svr &
pid="$!"
_kill() {
  echo "start closing ..."
  kill $pid 
  wait $pid
  exit 0
}
trap _kill SIGTERM 
wait

这个时候,当我们的 k8s 中的 pod 被 delete 或者被 rollout restart 的时候,会给咱们容器中的 shell 发送 sigterm 信号,脚本中由于我们使用 trap 命令来传递信号给到 my_demo_svr 程序中,进而触发 my_demo_svr 优雅关闭

至此,请大家引以为鉴,尽量减少踩坑吧,如果有相同经历的欢迎评论交流哦

感谢阅读,欢迎交流,点个赞,关注一波 再走吧

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

image.png

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
2月前
|
JSON Kubernetes Shell
【Azure K8S | AKS】在不丢失文件/不影响POD运行的情况下增加PVC的大小
【Azure K8S | AKS】在不丢失文件/不影响POD运行的情况下增加PVC的大小
|
2月前
|
Kubernetes Shell Perl
【Azure K8S|AKS】进入AKS的POD中查看文件,例如PVC Volume Mounts使用情况
【Azure K8S|AKS】进入AKS的POD中查看文件,例如PVC Volume Mounts使用情况
|
7天前
|
Kubernetes Docker Python
dockercompose与k8s的pod文件的爱恨情仇
dockercompose与k8s的pod文件的爱恨情仇
|
2月前
|
运维 Kubernetes 容器
【Azure K8S】演示修复因AKS密钥过期而导致创建服务不成功的问题(The provided client secret keys for app ****** are expired)
【Azure K8S】演示修复因AKS密钥过期而导致创建服务不成功的问题(The provided client secret keys for app ****** are expired)
【Azure K8S】演示修复因AKS密钥过期而导致创建服务不成功的问题(The provided client secret keys for app ****** are expired)
|
2月前
|
Kubernetes Docker Perl
在K8S中,如果是因为开发写的镜像问题导致pod起不来该怎么排查?
在K8S中,如果是因为开发写的镜像问题导致pod起不来该怎么排查?
|
2月前
|
Kubernetes 安全 Docker
在K8S中,在服务上线的时候Pod起不来怎么进行排查?
在K8S中,在服务上线的时候Pod起不来怎么进行排查?
|
2月前
|
存储 Kubernetes 调度
在K8S中,⼀个pod的不同container能够分开被调动到不同的节点上吗?
在K8S中,⼀个pod的不同container能够分开被调动到不同的节点上吗?
|
1天前
|
Kubernetes Cloud Native Ubuntu
云原生之旅:Kubernetes集群搭建与应用部署
【8月更文挑战第65天】本文将带你进入云原生的世界,通过一步步指导如何在本地环境中搭建Kubernetes集群,并部署一个简单的应用。我们将使用Minikube和Docker作为工具,探索云原生技术的魅力所在。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和实践技巧。
|
5天前
|
存储 Kubernetes 关系型数据库
阿里云ACK备份中心,K8s集群业务应用数据的一站式灾备方案
阿里云ACK备份中心,K8s集群业务应用数据的一站式灾备方案
|
1月前
|
存储 Kubernetes 负载均衡
CentOS 7.9二进制部署K8S 1.28.3+集群实战
本文详细介绍了在CentOS 7.9上通过二进制方式部署Kubernetes 1.28.3+集群的全过程,包括环境准备、组件安装、证书生成、高可用配置以及网络插件部署等关键步骤。
181 3
CentOS 7.9二进制部署K8S 1.28.3+集群实战
下一篇
无影云桌面