The importance of PID 1 in containers

The Docker platform leverages Docker containers to enable IT operations teams and Developer teams to build, ship and run any application, anywhere. (from docker.com)

I’ve been working with Docker for 3 years now and seen some cases where an image has to perform some steps before booting the application(s). It’s usual to see that done with a bash script that doesn’t launch the application preceded by an exec command. Let me explain:

– Create a start bash script that check if the file /foo  exists, print a message about it and simulates an application with netcat:

#!/bin/sh

if [[ -f /foo ]]
then
        echo 'File found'
else
        echo 'File not found!'
fi

nc -l 4000 -k

– Create a Dockerfile that will add the start script and launch it:

FROM alpine

ADD start /start
RUN chmod +x /start

CMD ./start

– Build, run and test it:

$ docker build -t test-pid .
$ docker run -it -d --name t-pid test-pid
# Now let's run a shell to access the container:
$ docker exec -it t-pid sh
/ # ps
PID USER TIME COMMAND
   1 root 0:00 /bin/sh -c ./start
   5 root 0:00 {start} /bin/sh ./start
   6 root 0:00 nc -l 4000 -k
   7 root 0:00 sh
  11 root 0:00 ps

You’ve noticed that start script is the one that has PID 1 and that’s bad! Why is it bad? Because start script can’t leverage signals, for example: SIGTERM (docker stop) !

$ # Stop the container
$ docker stop t-pid && docker rm t-pid
$ # You will notice that it will take 
$ # 10 seconds to stop: https://github.com/docker/docker/issues/3766
$ # That's the default timeout for docker stop.
$ # If the container wasn't able to deal with the SIGTERM, the force kill it.

– Change the above Dockerfile  and start  script to:

FROM alpine

ADD start /start
RUN chmod +x /start

CMD exec ./start
#!/bin/sh

if [[ -f /foo ]]
then
        echo 'File found'
else
        echo 'File not found!'
fi

exec nc -l 4000 -k

– Build, run and test it:

$ docker build -t test-pid-ok .
$ docker run -it -d --name t-pid test-pid-ok
# Now let's run a shell to access the container:
$ docker exec -it t-pid sh
/ # ps
PID   USER     TIME   COMMAND
    1 root       0:00 nc -l 4000 -k
    5 root       0:00 sh
    9 root       0:00 ps
/ # # Yay!!
/ # exit
$ # Stop the container and see that it stops immediately!
$ docker stop t-pid && docker rm t-pid 

You can read more about it here , here and here.

Leave a comment

Filed under docker, Tech

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.