在工作中遇到k8s利用脚本启动业务的容器,在停止容器时,总需要最大的停止时间。但直接在容器中启动业务程序,则可以比较快地退出。

同时,在k8s中,用busybox作为镜像启动无限循环停留一秒打印日志的脚本,则清除pod时也遭遇了比较长的时间。根据k8s官网介绍,如果没有提供preStop配置,则直接发送SIGTERM信号,明显启动脚本对于此信号没有处理好。对启动脚本加入截获信号操作,则可以正常退出。

# 主动截获信号
trap "exit" TERM

while True; do
echo "print $(date) ..."
sleep 1
done

由此,推想到经由启动脚本启动的业务程序,已经不是容器的1号进程,所以,SIGTERM信号不能够正常接收到,而且启动脚本屏蔽了SIGTERM信号处理,故退出缓慢!

解决由启动脚本带来的退出缓慢问题 ,存在几个解决办法:

  • 启动脚本增加信号截获处理,启动脚本退出后,会进一步导致子进程业务程序退出
  • 在启动脚本最后启动业务程序的地方,利用exec让业务程序替代启动脚本成为一号进程
  • 分拆为多容器、利用k8s官方推荐的init容器+业务程序容器的办法,让业务程序成为容器的一号进程


在解决办法中,容器内的一号进程是谁影响颇大,而且是否可以正确处理SIGTERM信号也至关重要!

容器内一号进程


如果你是Linux的教徒,则容器内仅提供一种业务是一个源自KISS原则的自然延伸

在Linux程序世界中,经常见到单一职责的进程,和各种Shell小工具。Linux并不倾向于将问题复杂化,而是小而美,控制其简单性。

但是,见到很多文章介绍在docker容器内装入多种服务的介绍,其实,如果是合适的场景,估计,也不是不可以。

但是,基本上来讲,大多数的情况是不需要的!在容器的世界里,利用消息中心、日志收集和持久化存储机制,基本上来讲将类似sshd服务并入容器以提供基础设施服务的需要是非常小的,程序运行的环境和世界已经发生大的变化,所谓“云原生”而已。同时,将sshd纳入到容器后,容器内的一号进程问题由冒了出来,建议的解决方式是采用近些年Linux发行版中常见的systemd作为一号进程,其他需要的服务或业务程序做成service,将其组团启动起来。

anolios docker

FROM openanolis/anolisos:8.2-x86_64
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]

在Linux中利用pstree可以观察系统内的1号进程和0号进程,也非常有意思。补充,在CentOS6时代,还并没有0号进程的显现!

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐