skip to Main Content

With this image (the Caddy webserver):

docker run --rm -p 80:80 caddy:latest 

I can stop it with sending CTRL+C within the terminal.

Some other images won’t work this way, for example MariaDB:

docker run -it --rm -p 3306:3306 -e MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=true mariadb:latest

I’m not able to stop it with CTRL+C

I’ve noticed that in Caddy Dockerfile there is no ENTRYPOINT but only CMD, whereas MariaDB has both an ENTRYPOINT and a CMD.

Why? Is there any reason NOT to support the handling of a kill signal? How can one support the SIGTERM in a docker entrypoint, if that is the reason?

2

Answers


  1. but I’m a bit curious about how the official images solves the problem….

    Don’t forget that Docker 1.13 comes with tini, originally from krallin/tini.

    Any image run with docker run --init would include an init inside the container that forwards signals and reaps processes.
    As mentioned here, tini works transparently, Dockerfiles don’t need to be modified in any way.

    So, In Unix systems, when you press CTRL+C in a terminal, a SIGINT (Signal Interrupt) is sent to the foreground process group, which in this case is the Docker container. If you use CTRL+, it sends SIGQUIT, and if you use CTRL+Z, it sends SIGTSTP (Signal Stop).

    Docker containers run a single main process, and this process runs in PID 1.
    PID 1 is special on Linux: it is the first process that runs and is the ancestor of all other processes.
    It also has a special relationship with Unix signals: it is the only process that can choose to ignore SIGINT and SIGTERM. Other processes cannot ignore these signals, but they can have handlers that execute when they receive them.

    In Docker, when you use CMD to specify the process to run, Docker will wrap that process with a small init system (like tini), which properly handles Unix signals and forwards them to the main process (I mentioned it originally here).
    This is why your caddy image, which does not have an ENTRYPOINT and only has CMD, can handle the CTRL+C.

    However, when you use ENTRYPOINT, Docker does not wrap the process with this small init system, and the process runs as PID 1.

    If the process does not have built-in handling for SIGINT or SIGTERM, it will not respond to CTRL+C. This is why your mariadb image, which has an ENTRYPOINT, does not stop when you press CTRL+C.

    The handling of a kill signal is an important part of a graceful shutdown. When a process receives a SIGTERM (or SIGINT), it should stop accepting new work, finish its current work, and then exit. This allows it to clean up any resources it is using and ensure data consistency.

    If the process does not handle these signals and is simply killed (with SIGKILL), it does not have a chance to clean up and may leave resources in an inconsistent state. This could be harmful in the case of a database like MariaDB, which could have uncommitted transactions or partially written data.

    To support the handling of a kill signal in a Docker entrypoint, you can:

    1. Add signal handling to the entrypoint script itself. This requires modifying the script and might not be feasible if the entrypoint is a binary.

    2. Use an init system that can handle signals and forward them to the main process. There are small init systems like tini that are designed for this purpose. You can use them in your Dockerfile like this:

      FROM your-base-image
      RUN apt-get update && apt-get install -y tini
      ENTRYPOINT ["/usr/bin/tini", "--", "your-command"]
      

      This will run tini as PID 1, which will handle signals and forward them to your command.

    3. Use Docker’s built-in init, which is a minimal tini implementation. You can enable it with the --init option when you run your container:

      docker run --init -it --rm -p 3306:3306 -e MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=true mariadb:latest
      

      This will run Docker’s built-in init as PID 1, which will handle signals and forward them to MariaDB.

    These methods ensure that your Docker entrypoint can handle kill signals and perform a graceful shutdown when necessary.


    Is there any reason NOT to support the handling of a kill signal?

    Not sure, unless you want your image to be really:

    • simple, for a very simple or short-lived processes, with no need of signal handling
    • fast, to avoid any shutdown signals during critical sections of their code
    • resilient, when you want to prevent unwanted or unauthorized shutdown.

    But generally, ignoring termination signals can lead to issues like data loss, resource leakage, or zombie processes, and should be avoided.

    Login or Signup to reply.
  2. MariaDB ignores SIGINT by masking its delivery to the process using sigprocmask.

    This was done a long time ago on some assumptions maybe around accidental triggering on shutdown when started in a terminal. There might be a case in old-school sysv scripts where a closed terminal quickly after service mariadb start may have delivered a SIGINT to mariadbd (unverified). I can’t see any requests to remove the SIGINT masking.

    The –gdb option on the command line will prevent the ignoring of SIGINT and achieve the results. It can also be provided in a .cnf file.

    MariaDB can handle termination at any point, including SIGKILL (cannot be caught except by an init process) or power failures. This is part of the durability (the D in ACID) for transactional databases. Upon restart uncommitted transactions are cleaned up. Doing a graceful termination does mean the startup doesn’t need a crash recovery and its quicker however.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search