最近给自己的项目编写一个Dockerfile,这个项目需要用到Cron定时任务。在Dockerfile里apt安装cron后不论如何使用RUN命令启动cron都无效(包括使用service和直接执行cron命令)。后来将所有任务集成在了一个sh脚本里解决了问题。举例,我要运行的任务是apache。那么我可以写一个脚本startup.sh,把Dockerfile的ENTRYPOINT设为这个脚本。
1 2 3 | #!/bin/sh cron apache2-foreground |
原因是什么呢?
方法1和方法2不能成功,是因为docker只是一个进程隔离的沙箱环境,并不是真正的虚拟机。而service xxx start 和systemctl start xxx 分别是upstart和systemd这两个/sbin/init进程的替代者的服务管理命令。而upstart和systemd都要求系统必须是物理机或虚拟机,并不支持作为container的init进程。方法3存在问题是因为,在正常的系统中,init进程永远占用PID=1的位置,回收僵尸进程、处理未处理的信号等都是由init进程帮我们完成的,一个子进程如果失去了父进程,也会由init进程接管。但是在container中,init进程并不存在,PID=1的进程是我们在Dockerfile中定义的Entrypoint或最后一个CMD指定的命令。
参考资料:https://www.asuri.org/2018/08/25/run-multi-service-in-one-container/
而直接执行cron命令为何失败呢?我推测,Dockerfile设计RUN命令的本义是对文件系统进行一定的操作。而非监控Container在启动时需要开启什么进程。所以一定要把所有需要运行的程序都写到一个shell脚本里并且把其设为入口点才行。