Dockerfile tips and tricks: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
== Run script at Container stop<ref>https://kmg.group/posts/2022-05-23-docker-stop-containers-with-signals/</ref> == | |||
By default [[docker]] stops your container by sending the <code>'''SIGTERM'''</code> signal to the entry point process (normally with process id 1 in the container). If the container is still running after 10 seconds, <code>docker stop</code> and <code>docker-compose down</code> will send the <code>'''SIGKILL'''</code> signal, which will remove the process from the OS scheduler. | |||
This can be overridden depending on, | |||
* The <code>ENTRYPOINT</code> in your Dockerfile, and how it behaves when receiving a signal | |||
* The <code>STOPSIGNAL</code> in your Dockerfile (default: <code>SIGTERM</code>, but this is not always used in all base containers, see php:8.0-fpm and nginx). | |||
* The <code>stop_signal</code> in your docker-compose.yml file | |||
* The <code>stop_grace_period</code> in your docker-compose.yml file | |||
For example, the php-fpm and nginx containers use <code>SIGQUIT</code>instead of <code>SIGTERM</code> as stop signa to graceful shutdown process so that user will not affected from the shutdown. | |||
<code>$ docker inspect nginx:latest | jq '.[].Config.StopSignal' | |||
"SIGQUIT" | |||
$ docker inspect php:7.4-fpm | jq '.[].Config.StopSignal' | |||
"SIGQUIT"</code> | |||
=== Container stop after 10s === | |||
<code>#--- create the init.sh script | |||
cat<<EOT > init.sh | |||
#!/bin/bash</code> | |||
<code>#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</code> | |||
=== Container stop as soon as SIGTERM ~ $docker stop <container> === | |||
<code>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</code> | |||
=== Select which signal to use with the STOPSIGNAL keyward in Dockerfile === | |||
<code>cat<<EOT > Dockerfile | |||
from php:8.0-fpm | |||
COPY . / | |||
'''#--- override the SIGQUIT used in php:8.0-fpm | |||
STOPSIGNAL SIGTERM''' | |||
ENTRYPOINT ["/init.sh"] | |||
EOT</code> | |||
=== Test it === | |||
<code>#--- 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</code> | |||
=== Handle signal correctly in the bash script === | |||
if you don’t take care of how you <code>sleep</code> at the end of the script (bash), the script will not catch any signals sent to it, even if you have a <code>trap</code> in your [[bash script]]. | |||
{| class="wikitable" | |||
|+ | |||
!This does not work | |||
!This works | |||
|- | |||
| | |||
<code>function exit_script(){ | |||
echo "Caught SIGTERM" | |||
exit 0 | |||
} | |||
trap exit_script SIGTERM | |||
#--- my init.sh script | |||
./start/my/program & | |||
sleep infinity</code> | |||
| | |||
<code>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</code> | |||
|} | |||
== Install nvm in Dockerfile<ref>https://hub.docker.com/r/nuccess/nuclos/dockerfile</ref> == | == Install nvm in Dockerfile<ref>https://hub.docker.com/r/nuccess/nuclos/dockerfile</ref> == | ||
<RUN mkdir -p $NVM_DIR && \ | <RUN mkdir -p $NVM_DIR && \ | ||
curl <nowiki>https://raw.githubusercontent.com/creationix/nvm/v0.36.0/install.sh</nowiki> | bash && \ | curl <nowiki>https://raw.githubusercontent.com/creationix/nvm/v0.36.0/install.sh</nowiki> | bash && \ | ||
. $NVM_DIR/nvm.sh && \ | . $NVM_DIR/nvm.sh && \ | ||
nvm install $NODE_VERSION | nvm install $NODE_VERSION | ||
== Reference == | == Reference == | ||
<references /> | <references /> |
Revision as of 17:11, 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 SIGQUIT
instead 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 |
---|---|
|
|
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