Home > front end >  Docker: can a cmdline argument be appended to a shell built-in command args?
Docker: can a cmdline argument be appended to a shell built-in command args?

Time:03-01

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 $@.

  • Related