I want to create a docker image with a cmdline-specifiable exit code.
From this question, I learned that I must use exit
as an argument to sh
because it is a shell built-in command, not an executable: How to make a docker container exit with a specific error-code with docker-compose?
I.e. I can create a docker container that exits with error-code 42 as follows:
# Dockerfile
FROM alpine:3.15 as base
ENTRYPOINT ["sh", "-c", "exit 42"]
$ docker build -t tmp:tmp . && docker run tmp:tmp
[ ] Building 0.4s (5/5) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 181B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/alpine:3.15 0.0s
=> CACHED [1/1] FROM docker.io/library/alpine:3.15 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:3034115e85f4ac9322c3e3e5d69f4445e30cc652f3b836d0145545305fda6ad1 0.0s
=> => naming to docker.io/library/tmp:tmp 0.0s
$ echo $?
42
$
Question:
Can the docker container be made to return an exit-code specified as a cmdline argument?
E.g. is this possible:
$ docker build -t tmp:tmp . && docker run tmp:tmp 64
...
$ echo $?
64
$
?
What I've tried:
This article -- https://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/ -- led me to try this combination of ENTRYPOINT
and CMD
:
# Dockerfile
FROM alpine:3.15 as base
ENTRYPOINT ["sh", "-c", "exit"]
CMD ["0"]
$ docker build -t tmp:tmp . && docker run tmp:tmp 64
...
$ echo $?
0
Interestingly, this same "pattern" of Dockerfile worked for echo
:
# Dockerfile
FROM alpine:3.15 as base
ENTRYPOINT ["echo", "hello"]
CMD ["world"]
$ docker build -t tmp:tmp . && docker run tmp:tmp
...
hello world
$
$ docker build -t tmp:tmp . && docker run tmp:tmp foo
...
hello foo
$
I think my failed experiment with ENTRYPOINT
and CMD
is explained by this experiment:
$ sh -c "exit 42"
$ echo $?
42
$ sh -c "exit" 42
$ echo $?
0
...I hoped that my Dockerfile with ENTRYPOINT ["sh", "-c", "exit"]
and CMD ["0"]
would result in the former, but I think it results in the latter -- true?
CodePudding user response:
All your docker run arguments are being passed to your entrypoint.sh
if you have one defined.
For example in my Dockerfile I have:
# prepare container
COPY entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
And in my entrypoint.sh
printf "Custom exit code '$*'\n"
exit "$@"
And then just run with args:
$ docker run verify 129
Custom exit code '129'
$ echo $?
129
$ _
CodePudding user response:
You are correct, CMD
always passes its contents as new arguments to the entrypoint. You cannot insert it as part of an argument from ENTRYPOINT
.
I'd also recommend Florin's solution, that is, having a custom entrypoint. However, if you really need to, you can still do it with shell only:
from alpine
entrypoint ["/bin/sh", "-c", "exit \"$@\"", "sh"]
cmd ["42"]
This will run sh
with 4 arguments, being -c
, exit "$@"
, sh
and 42
(or your command). The last two arguments are what will be passed to the script as argv[0]
(which is the name of the shell itself) and argv[1]
, the first argument, which will be substituted into $@
.