Dockerfile tips and tricks: Difference between revisions

From HPCWIKI
Jump to navigation Jump to search
Line 83: Line 83:
{| class="wikitable"
{| class="wikitable"
|+
|+
style="width: 50%"| !This does not work
|style="width: 50%"| !This does not work
style="width: 50%"| !This works
|style="width: 50%"| !This works
|-
|-
|
|

Revision as of 17:13, 2 May 2023

Run script at Container stop[1]

By default docker stops your container by sending the SIGTERM signal to the entry point process (normally with process id 1 in the container). If the container is still running after 10 seconds, docker stop and docker-compose down will send the SIGKILL signal, which will remove the process from the OS scheduler.

This can be overridden depending on,

  • The ENTRYPOINT in your Dockerfile, and how it behaves when receiving a signal
  • The STOPSIGNAL in your Dockerfile (default: SIGTERM, but this is not always used in all base containers, see php:8.0-fpm and nginx).
  • The stop_signal in your docker-compose.yml file
  • The stop_grace_period in your docker-compose.yml file


For example, the php-fpm and nginx containers use SIGQUITinstead of SIGTERM as stop signa to graceful shutdown process so that user will not affected from the shutdown.

$ docker inspect nginx:latest | jq '.[].Config.StopSignal'
"SIGQUIT"
$ docker inspect php:7.4-fpm | jq '.[].Config.StopSignal'
"SIGQUIT"

Container stop after 10s

#--- create the init.sh script
cat<<EOT > init.sh
#!/bin/bash

#We don’t trap the signal, so that we can handle SIGTEM to exit the script
echo "This container will not stop immediately after SIGTERM, it uses SIGQUIT"

sleep infinity #sleep infinity in a way so that our bash script can’t trap the signal
EOT

chmod 755 init.sh

#--- create the Dockerfile
cat<<EOT > Dockerfile
from php:8.0-fpm

COPY . /

ENTRYPOINT ["/init.sh"]
EOT

Container stop as soon as SIGTERM ~ $docker stop <container>

cat<<EOT > init.sh
#!/bin/bash

#--- add a function to exit nicely (perhaps kill a few processes and remove some temp files)
function exit_container_SIGTERM(){
  echo "Caught SIGTERM"
  exit 0
}

#--- trap the SIGTERM signal
trap exit_container_SIGTERM SIGTERM 

echo "This container will stop immediately after SIGTERM"

sleep infinity &
wait
EOT

Select which signal to use with the STOPSIGNAL keyward in Dockerfile

cat<<EOT > Dockerfile
from php:8.0-fpm

COPY . /

#--- override the SIGQUIT used in php:8.0-fpm
STOPSIGNAL SIGTERM

ENTRYPOINT ["/init.sh"]
EOT

Test it

#--- build the container
docker build -t stop-container:latest .

#--- run the container (in one terminal window)
docker run --name=stop-demo --rm -it stop-container

#--- Test stop the container
docker stop stop-demo

Handle signal correctly in the bash script

if you don’t take care of how you sleep at the end of the script (bash), the script will not catch any signals sent to it, even if you have a trap in your bash script.

!This does not work !This works
function exit_script(){
  echo "Caught SIGTERM"
  exit 0
}


trap exit_script SIGTERM

#--- my init.sh script
./start/my/program &
sleep infinity
function exit_script(){
  echo "Caught SIGTERM"
  exit 0
}

trap exit_script SIGTERM

#--- my init.sh script
./start/my/program &

#--- send sleep into the background, then wait for it.
sleep infinity &
#--- "wait" will wait until the command you sent to the background terminates, which will be never.
#--- "wait" is a bash built-in, so bash can now handle the signals sent by "docker stop"
wait

Install nvm in Dockerfile[2]

<RUN mkdir -p $NVM_DIR && \
   curl https://raw.githubusercontent.com/creationix/nvm/v0.36.0/install.sh | bash && \
   . $NVM_DIR/nvm.sh && \
   nvm install $NODE_VERSION

Reference