Docker Tips #3: How to lose data with a bad CMD
Scenario
I want to be sure I don’t lose data when I stop my container.
Given
A simple program which add to a list the current time every second (Very critical program) and write the list to a file when it exits.
I assume it’s understandable even if you are not familiar with java. If not, let me know and I’ll explain it.
When
I launch it without docker, (java -jar docker/docker-stop-test-0.1-SNAPSHOT.jar
) wait for a few seconds, then kill it (kill $(ps aux | grep java | grep docker-stop-test-0.1-SNAPSHOT.jar | awk '{print $2}')
)
Then
I check in dataFolder/data
file and I see
But
If I kill -9 instead, the data file is empty.
Let’s move to docker now
Given
A docker image with the jre and my jar installed
When
I launch a container, wait for a few seconds, then STOP (not KILL) it
Then
I expect to see data in dataFolder-bad-cmd/data
right? Wrong.
There is nothing written in the data file, that means I just lost everything!
Explanations
If you look at the CMD command: CMD java -jar docker-stop-test-0.1-SNAPSHOT.jar
everything looks ok.
But when you run this image and inspect the created container, you will see this:
Docker wrapped my command within a shell script. So what, that’s not that big a deal right?
In fact, if you look at the docker documentation, you don’t see anything useful. You have to look at the ENTRYPOINT documentation and dig into it a little to see that:
The shell form prevents any CMD or run command line arguments from being used, but has the disadvantage that your ENTRYPOINT will be started as a subcommand of /bin/sh -c, which does not pass signals. This means that the executable will not be the container’s PID 1 - and will not receive Unix signals - so your executable will not receive a SIGTERM from docker stop
.
Conclusion
Don’t use the most intuitive syntax in the CMD or ENTRYPOINT command, use the exec form. If you replace the CMD command in the dockerfile by this one:
Then everything works like a charm, the SIGTERM is received and the java application save its list into the data file before exiting.
DIY
If you want to try it by yourself, everything is on my github repository. You have two shell scripts: docker-build-all.sh
and docker-run-all.sh
. The first will build the images with the bad syntax and the good one. The second script will run containers from these images, wait 5 seconds, stop them.
You can then check in dataFolder-bad-cmd/data
and dataFolder-good-cmd/data
to see the differences.