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

简介: 咱们工作的环境在不断的变好,我们也会思考去提升程序运行的环境,让我们的服务更加容易部署,极简维护,现在很多公司都在向着 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

好了,本次就到这里

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

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

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
11月前
|
运维 Kubernetes 持续交付
ACK One GitOps:让全球化游戏服务持续交付更简单
ACK One GitOps 致力于提供开箱即用的多集群 GitOps 持续交付能力,简化游戏等服务的多集群/多地域统一部署,让您更加专注于业务开发。
|
Prometheus Kubernetes 监控
深入探索Kubernetes中的Pod自动扩展(Horizontal Pod Autoscaler, HPA)
深入探索Kubernetes中的Pod自动扩展(Horizontal Pod Autoscaler, HPA)
|
Kubernetes Docker 容器
Kubernetes与Docker参数对照:理解Pod中的command、args与Dockerfile中的CMD、ENTRYPOINT。
需要明确的是,理解这些都需要对Docker和Kubernetes有一定深度的理解,才能把握二者的区别和联系。虽然它们都是容器技术的二个重要组成部分,但各有其特性和适用场景,理解它们的本质和工作方式,才能更好的使用这些工具,将各自的优点整合到生产环境中,实现软件的快速开发和部署。
601 25
|
Kubernetes Shell Windows
【Azure K8S | AKS】在AKS的节点中抓取目标POD的网络包方法分享
在AKS中遇到复杂网络问题时,可通过以下步骤进入特定POD抓取网络包进行分析:1. 使用`kubectl get pods`确认Pod所在Node;2. 通过`kubectl node-shell`登录Node;3. 使用`crictl ps`找到Pod的Container ID;4. 获取PID并使用`nsenter`进入Pod的网络空间;5. 在`/var/tmp`目录下使用`tcpdump`抓包。完成后按Ctrl+C停止抓包。
559 12
|
存储 Kubernetes Docker
【赵渝强老师】Kubernetes中Pod的基础容器
Pod 是 Kubernetes 中的基本单位,代表集群上运行的一个进程。它由一个或多个容器组成,包括业务容器、基础容器、初始化容器和临时容器。基础容器负责维护 Pod 的网络空间,对用户透明。文中附有图片和视频讲解,详细介绍了 Pod 的组成结构及其在网络配置中的作用。
330 1
【赵渝强老师】Kubernetes中Pod的基础容器
|
存储 Kubernetes 网络协议
k8s的无头服务
Headless Service 是一种特殊的 Kubernetes 服务,其 `spec:clusterIP` 设置为 `None`,不会分配 ClusterIP,通过 DNS 解析提供服务发现。与普通服务不同,Headless Service 不提供负载均衡功能,每个 Pod 都有唯一的 DNS 记录,直接映射到其 IP 地址,适用于有状态应用的场景,如与 StatefulSet 一起部署数据库。示例中通过创建 Nginx 的 StatefulSet 和 Headless Service,展示了如何直接访问单个 Pod 并进行内容修改。
555 3
|
运维 Kubernetes Shell
【赵渝强老师】K8s中Pod的临时容器
Pod 是 Kubernetes 中的基本调度单位,由一个或多个容器组成,包括业务容器、基础容器、初始化容器和临时容器。临时容器用于故障排查和性能诊断,不适用于构建应用程序。当 Pod 中的容器异常退出或容器镜像不包含调试工具时,临时容器非常有用。文中通过示例展示了如何使用 `kubectl debug` 命令创建临时容器进行调试。
399 1
|
Kubernetes 调度 容器
【赵渝强老师】K8s中Pod中的业务容器
Pod 是 Kubernetes 中的基本调度单元,由一个或多个容器组成。除了业务容器,Pod 还包括基础容器、初始化容器和临时容器。本文通过示例介绍如何创建包含业务容器的 Pod,并提供了一个视频讲解。示例中创建了一个名为 &quot;busybox-container&quot; 的业务容器,并使用 `kubectl create -f firstpod.yaml` 命令部署 Pod。
300 1
|
存储 Kubernetes Devops
Kubernetes集群管理和服务部署实战
Kubernetes集群管理和服务部署实战
332 0
|
8月前
|
人工智能 算法 调度
阿里云ACK托管集群Pro版共享GPU调度操作指南
本文介绍在阿里云ACK托管集群Pro版中,如何通过共享GPU调度实现显存与算力的精细化分配,涵盖前提条件、使用限制、节点池配置及任务部署全流程,提升GPU资源利用率,适用于AI训练与推理场景。
701 1

热门文章

最新文章

推荐镜像

更多