Automatic Container Restart
In compiled programming languages such as golang it is cumbersome to build a container that is able to automatically reload on a file change. With v4.11.0 and config version v1beta9, DevSpace is able to do the heavy lifting for you and simplifies the process drastically in a non invasive way. You only have to set 2 config options in the devspace.yaml
and it should work for most Dockerfiles and applications out of the box. This example configuration will tell DevSpace to start an application in restart mode and the sync to restart the container after a change:
version: v1beta9
images:
default:
image: myusername/devspace
# this new option tells devspace to automatically wrap the Dockerfile entrypoint in memory
# with a small restart helper script so that the process can be easily restarted from within the
# container. This should work with most Dockerfiles that have an ENTRYPOINT statement.
# This will also work for build targets.
# Note: If you override the entrypoint in the kubernetes yaml via the Pod.spec.containers.command,
# please make sure you wrap the command with the devspace script '/devspace-restart-helper'
injectRestartHelper: true
# If you don't have an entrypoint defined in your Dockerfile, you can also define an entrypoint here
# entrypoint: ["go"]
# cmd: ["run", "main.go"]
dev:
sync:
- imageName: default
onUpload:
# this new option tells DevSpace to restart the container process if something changes within
# the container. This obviously only works if the restart helper script is present in the container.
# You can either manually add the restart script or add the injectRestartHelper option to the image
restartContainer: true
deployments:
...
So you just have to add these two new options and your containers can be restarted without changing the Dockerfile or any other files. This makes developing golang and other compiled languages way more fun! For a complete example you can take a look at hot-reload-container-restart.
How does it work?
The new option injectRestartHelper
tells DevSpace to rewrite the Dockerfile in memory and add the inject script. It will also inject the actual script contents into the context sent to the docker daemon or to the kaniko pod. The resulting Dockerfile will look like this:
## Original Dockerfile
FROM myimage
RUN mycommand
ENTRYPOINT ["go","run","main.go"]
...
## Injected by DevSpace
COPY /.devspace/devspace-restart-helper /
ENTRYPOINT ["/devspace-restart-helper","go","run","main.go"]
DevSpace makes sure that the script at the context path /.devspace/devspace-restart-helper
does exist. The script itself is just a simple shell script that starts and restarts a given command:
#
# A process wrapper script to simulate a container restart. This file was injected with devspace during the build process
#
set -e
pid=""
trap quit TERM INT
quit() {
if [ -n "$pid" ]; then
kill $pid
fi
}
while true; do
setsid "$@" &
pid=$!
echo "$pid" > /devspace-pid
set +e
wait $pid
exit_code=$?
if [ -f /devspace-pid ]; then
# if the sync is currently active we try to restart instead of exiting
if [ -f /tmp/sync ]; then
rm -f /devspace-pid
printf "\nContainer exited with $exit_code. Will restart in 7 seconds...\n"
sleep 7
else
exit $exit_code
fi
fi
set -e
printf "\nRestart container\n"
done
This by itself is not doing much, however if you configure the dev.sync.onUpload.restartContainer
option, DevSpace will automatically kill the container entrypoint on file change and the script will restart the container entrypoint. The container is only restarted after a batch of changes and not on every file change to reduce the amounts of restarts if a lot of changes are uploaded.
Other Changes
- New config version v1beta9 (old config versions will get converted in memory automatically as always):
- new
images.*.injectRestartHelper
: if this option is true DevSpace injects a small restart script into the container and wraps the entrypoint of that container with this script, so DevSpace is able to restart the main container process during the sync process. Only works if there is either an Entrypoint defined in the DevSpace config or in the dockerfile for this image, otherwise DevSpace will fail. See Container Restart above for more information. - new
dev.sync.*.onUpload.restartContainer
: if this option is true DevSpace will try to restart the container main process after a change has been made. Only works ifimages.*.injectRestartHelper
is enabled for the container that should be restarted or the devspace-restart-helper script is present in the container root folder. See Container Restart above for more information. - new
dev.sync.*.onUpload.execRemote.onBatch
: executes the given command after a batch of changes has been processed. DevSpace will wait for the command to finish and then will continue execution. This is useful for commands that shouldn't be executed after every single change that may take a little bit longer like recompiling etc. - new
images.*.preferSyncOverRebuild
: if enabled, DevSpace will not rebuild the image even though files have changed within the building context if a syncpath for this image is defined. Since this was the default behavior for all images before this change, older config versions will convert this to be enabled so that this is a non breaking change.
- new
- DevSpace now prefers docker over kaniko if both are set in the config