docker/k8s容器优雅退出(python,go,java)

腾讯数据架构师 2020-11-13 07:21:27
docker 容器 k8s 优雅 退出


全栈工程师开发手册 (作者:栾鹏)
架构系列文章

注意:docker 正常退出和异常退出都不会自动发起SIGTERM,java正常或异常退出,jvm会发起SIGTERM信号

docker kill 直接杀死容器进程
docker stop是向容器进程发送SIGTERM信号,本文介绍容器中的进程捕获 SIGTERM 信号,优雅的退出。

github地址:https://github.com/626626cdllp/k8s/tree/master/test/docker-signal

先来了解一下信号

SIGINT

程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。

SIGQUIT

和SIGINT类似, 但由QUIT字符(通常是Ctrl-)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。

SIGTERM

程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号。如果进程终止不了,我们才会尝试SIGKILL。

SIGSTOP

停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略.

添加退出处理逻辑

假设源dockerfile中定义的entrypoint为python /app/server.py

现在需要重新写一个脚本entrypoint.sh

#!/bin/sh
# 实际运行的工作程序,将源主程序一般后台运行形势打开
nohup python /app/server.py &
# 中断信号处理函数,关闭python主程序
prog_exit()
{
ps -ef| grep python |grep -v grep |awk '{print $2}'|xargs kill -15
}
# 注册中断处理函数
trap "prog_exit" 15
flag=1
# 前端形式运行睡眠,并交叉是否可以退出(python进程已不存在,也能在python进程自己退出的情况下关闭容器)
while [ $flag -ne 0 ];do
sleep 3;
flag=`ps -ef| grep atm |grep -v grep | wc -l`
done;

然后将dockerfile中的entrypoint改成启动新的脚本


FROM ubuntu:18.04
RUN apt-get update && \
apt-get install -y python3.6 && \
rm -rf /var/lib/apt/lists/*
COPY ./server.py /data/
COPY ./entrypoint.sh /data/
WORKDIR /data/
# 使用sh做优雅退出
ENTRYPOINT ["/data/entrypoint.sh"]
CMD ["bash"]
# 直接向python发起退出命令
# ENTRYPOINT ["python3.6","/data/server.py"]

在业务代码中添加退出处理逻辑(python)

优雅退出的目的一般为处理业务没有处理完的事情。则一般需要在业务代码中处理退出信号。比如在上面的server.py中添加处理逻辑。

第一种方式,
上面我们使用ps -ef| grep python |grep -v grep |awk '{print $2}'|xargs kill -15命令向python服务发起了kill信号,我们可以在python脚本中也接收这个bash发起的kill信号。

第二种方式,
我们直接在业务代码中接收容器发起的SIGTERM 信号(方法更直接),这样dockerfile中就还是使用源入口点

ENTRYPOINT ["python3.6","/data/server.py"]

比如我们可以这样编写server.py

import signal
import time
is_running = True
def sigint_handler(num, stack):
print(num,stack)
print('receive sigint')
global is_running
is_running = False
def sigterm_handler(num, stack):
print(num,stack)
print('receive sigterm')
global is_running
is_running = False
def main():
signal.signal(signal.SIGINT, sigint_handler)
signal.signal(signal.SIGTERM, sigterm_handler)
signal.siginterrupt(signal.SIGINT, False)
signal.siginterrupt(signal.SIGTERM, False)
while is_running:
print('begin sleep')
# 启动你的业务函数
time.sleep(3)
print("prepare exit")
print("sleep 10")
time.sleep(10)
print("exit")
if __name__ == "__main__":
main()

执行python3.6 server.py将看到这样的日志

begin sleep
begin sleep
begin sleep
15 <frame object at 0x2371b18>
receive sigterm
prepare exit
sleep 10

go语言接收退出信号

关于Go语言对系统Signal的处理,可以参考《Go中的系统Signal处理》一文。

https://tonybai.com/2014/10/09/gracefully-shutdown-app-running-in-docker/

java语言接收退出信号

https://blog.csdn.net/zhangpeterx/article/details/89454050

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// import com.lmax.disruptor.LifecycleAware;
//要注意让java进程的pid为1,不然docker stop信号接收不到
public class demo {

public static void main(String[] args) {

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {

@Override
public void run() {

System.out.println("Exited!");
}
}));
System.out.println("begin!");
try{

Thread.sleep(1000*60);
} catch (Exception e) {

e.printStackTrace();
}
}
}

k8s容器生命周期钩子

参考https://kubernetes.io/zh/docs/concepts/containers/container-lifecycle-hooks/

有两个钩子暴露在容器中:

PostStart

这个钩子在创建容器之后立即执行。 但是,不能保证钩子会在容器入口点之前执行。 没有参数传递给处理程序。

PreStop

在容器终止之前是否立即调用此钩子,取决于 API 的请求或者管理事件,类似活动探针故障、资源抢占、资源竞争等等。 如果容器已经完全处于终止或者完成状态,则对 preStop 钩子的调用将失败。 它是阻塞的,同时也是同步的,因此它必须在删除容器的调用之前完成。 没有参数传递给处理程序

k8s示例

# Source: superset/templates/secret.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: python-config
data:
pre_start.py: |-
import time
import os
if __name__=='__main__':
print('pre start process %s.' % os.getpid())
print('end')
time.sleep(10)
print('Process start.')
pre_stop.py: |-
import time
import os
if __name__=='__main__':
print('pre stop process %s.' % os.getpid())
print('end')
print('Process end.')
---
apiVersion: v1
kind: Pod
metadata:
labels:
app: python
name: python-pod
spec:
volumes:
- name: python-configmap
configMap:
name: python-config
items:
- key: pre_stop.py
path: pre_stop.py
- key: pre_start.py
path: pre_start.py
containers:
- command: ['xxxxx','xxxxx']
name: python
workingDir: /
image: xxxxxxxxx
lifecycle:
postStart:
exec:
command: ["/bin/bash","-c","python /pre_start.py >> pre_start.txt"]
preStop:
exec:
command: ["/bin/bash","-c","python /pre_stop.py >> pre_stop.txt"]
volumeMounts:
- name: python-configmap
mountPath: /pre_stop.py
subPath: pre_stop.py
- name: python-configmap
mountPath: /pre_start.py
subPath: pre_start.py

钩子处理程序的实现(可能会重复触发)

容器可以通过实现和注册该钩子的处理程序来访问该钩子。 针对容器,有两种类型的钩子处理程序可供实现:

  • Exec - 执行一个特定的命令,例如 pre-stop.sh,在容器的 cgroups 和名称空间中。 命令所消耗的资源根据容器进行计算。
  • HTTP - 对容器上的特定端点执行 HTTP 请求

对于PostStart 钩子,容器入口点和钩子异步触发。两个都运行完成,容器才进入running状态。
对于PreStop钩子。如果PreStop钩子在执行过程中挂起,Pod 阶段将保持在 Terminating 状态,并在 Pod 结束的 terminationGracePeriodSeconds 之后被杀死。 也就是说PreStop钩子的最多运行时间为terminationGracePeriodSeconds属性配置的值。

如果 PostStart 或 PreStop 钩子失败,它会杀死容器。

钩子处理程序的日志不会在 Pod 事件中公开。 如果处理程序由于某种原因失败,它将播放一个事件。 对于 PostStart,这是 FailedPostStartHook 事件,对于 PreStop,这是 FailedPreStopHook 事件。 您可以通过运行 kubectl describe pod <pod_name> 命令来查看这些事件

版权声明
本文为[腾讯数据架构师]所创,转载请带上原文链接,感谢
https://luanpeng.blog.csdn.net/article/details/104513249

  1. 利用Python爬虫获取招聘网站职位信息
  2. Using Python crawler to obtain job information of recruitment website
  3. Several highly rated Python libraries arrow, jsonpath, psutil and tenacity are recommended
  4. Python装饰器
  5. Python实现LDAP认证
  6. Python decorator
  7. Implementing LDAP authentication with Python
  8. Vscode configures Python development environment!
  9. In Python, how dare you say you can't log module? ️
  10. 我收藏的有关Python的电子书和资料
  11. python 中 lambda的一些tips
  12. python中字典的一些tips
  13. python 用生成器生成斐波那契数列
  14. python脚本转pyc踩了个坑。。。
  15. My collection of e-books and materials about Python
  16. Some tips of lambda in Python
  17. Some tips of dictionary in Python
  18. Using Python generator to generate Fibonacci sequence
  19. The conversion of Python script to PyC stepped on a pit...
  20. Python游戏开发,pygame模块,Python实现扫雷小游戏
  21. Python game development, pyGame module, python implementation of minesweeping games
  22. Python实用工具,email模块,Python实现邮件远程控制自己电脑
  23. Python utility, email module, python realizes mail remote control of its own computer
  24. 毫无头绪的自学Python,你可能连门槛都摸不到!【最佳学习路线】
  25. Python读取二进制文件代码方法解析
  26. Python字典的实现原理
  27. Without a clue, you may not even touch the threshold【 Best learning route]
  28. Parsing method of Python reading binary file code
  29. Implementation principle of Python dictionary
  30. You must know the function of pandas to parse JSON data - JSON_ normalize()
  31. Python实用案例,私人定制,Python自动化生成爱豆专属2021日历
  32. Python practical case, private customization, python automatic generation of Adu exclusive 2021 calendar
  33. 《Python实例》震惊了,用Python这么简单实现了聊天系统的脏话,广告检测
  34. "Python instance" was shocked and realized the dirty words and advertisement detection of the chat system in Python
  35. Convolutional neural network processing sequence for Python deep learning
  36. Python data structure and algorithm (1) -- enum type enum
  37. 超全大厂算法岗百问百答(推荐系统/机器学习/深度学习/C++/Spark/python)
  38. 【Python进阶】你真的明白NumPy中的ndarray吗?
  39. All questions and answers for algorithm posts of super large factories (recommended system / machine learning / deep learning / C + + / spark / Python)
  40. [advanced Python] do you really understand ndarray in numpy?
  41. 【Python进阶】Python进阶专栏栏主自述:不忘初心,砥砺前行
  42. [advanced Python] Python advanced column main readme: never forget the original intention and forge ahead
  43. python垃圾回收和缓存管理
  44. java调用Python程序
  45. java调用Python程序
  46. Python常用函数有哪些?Python基础入门课程
  47. Python garbage collection and cache management
  48. Java calling Python program
  49. Java calling Python program
  50. What functions are commonly used in Python? Introduction to Python Basics
  51. Python basic knowledge
  52. Anaconda5.2 安装 Python 库(MySQLdb)的方法
  53. Python实现对脑电数据情绪分析
  54. Anaconda 5.2 method of installing Python Library (mysqldb)
  55. Python implements emotion analysis of EEG data
  56. Master some advanced usage of Python in 30 seconds, which makes others envy it
  57. python爬取百度图片并对图片做一系列处理
  58. Python crawls Baidu pictures and does a series of processing on them
  59. python链接mysql数据库
  60. Python link MySQL database