Search code examples
dockercron

'docker stop' for crond times out


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)