Issue
I'm trying to understand why my Docker container does not stop gracefully and just times out. The container is running crond
:
FROM alpine:latest
ADD crontab /etc/crontabs/root
RUN chmod 0644 /etc/crontabs/root
CMD ["crond", "-f"]
And the crontab
file is:
* * * * * echo 'Working'
# this empty line required by cron
Built with docker build . -t periodic:latest
And run with docker run --rm --name periodic periodic:latest
This is all good, but when I try to docker stop periodic
from another terminal, it doesn't stop gracefully, the time out kicks in and is killed abruptly. It's like crond
isn't responding to the SIGTERM.
crond
is definitely PID 1
/ # ps
PID USER TIME COMMAND
1 root 0:00 crond -f
6 root 0:00 ash
11 root 0:00 ps
However, if I do this:
docker run -it --rm --name shell alpine:latest ash
and
docker exec -it shell crond -f
in another terminal, I can kill crond
from the first shell with SIGTERM so I know it can be stopped with SIGTERM.
Thanks for any help.
Solution
Adding an init process to the container (init: true
in docker-compose.yml
) solved the problem.
EDIT: I read this https://blog.thesparktree.com/cron-in-docker to understand the issues and solutions around running cron in Docker. From this article:
"Finally, as you’ve been playing around, you may have noticed that it’s difficult to kill the container running cron. You may have had to use docker kill or docker-compose kill to terminate the container, rather than using ctrl + C or docker stop.
Unfortunately, it seems like SIGINT is not always correctly handled by cron implementations when running in the foreground.
After researching a couple of alternatives, the only solution that seemed to work was using a process supervisor (like tini or s6-overlay). Since tini was merged into Docker 1.13, technically, you can use it transparently by passing --init to your docker run command. In practice you often can’t because your cluster manager doesn’t support it."
Since my original post and answer, I've migrated to Kubernetes, so init
in docker-compose.yml won't work. My container is based on Debian Buster, so I've now installed tini
in the Dockerfile, and changed the ENTRYPOINT to ["/usr/bin/tini", "--", "/usr/local/bin/entrypoint.sh"]
(my entrypoint.sh finally does exec cron -f
)
Answered By - Steve Folly Answer Checked By - Pedro (WPSolving Volunteer)