简体   繁体   中英

'docker run' ignores first command appended to ENTRYPOINT ["/bin/bash", "-c", ". foo.sh"] but not ["bash", "foo.sh"]

I am trying to run a docker image which executes a bash script and passes run-time arguments to that bash script. I have found that when I build the image using the recommended ENTRYPOINT ["/bin/bash", "-c", ". foo.sh"] entrypoint, the first argument appended to the docker run command doesn't get picked up by my script, but when I build the image with ENTRYPOINT ["bash", "foo.sh"] , it does.

A toy version of the shell script looks like this:

#!/bin/bash

echo you got "$#" args
ARG1=${1:-foo}
ARG2=${2:-bar}
ARG3=${3:-1}
ARG4=${4:-$(date)}

echo "$ARG1"
echo "$ARG2"
echo "$ARG3"
echo "$ARG4"

so basically the script expects up to 4 command line arguments that each have default values.

The original Dockerfile I tried looks like this:

FROM ubuntu

COPY foo.sh foo.sh

ENTRYPOINT ["/bin/bash", "-c", ". foo.sh"]

and was based on a number of resources I found for how to properly execute a shell script using the exec form of ENTRYPOINT recommended by docker .

After building this image with docker build -t foo . , I run it with docker run -it foo first second third fourth and I get the following output:

you got 3 args
second
third
fourth
Tue Jul  2 13:14:52 UTC 2019

so clearly the first argument appended to the docker run command is dropped somewhere along the line, and the only arguments that get ingested by the shell command are the second, third, and fourth.

I spent ages trying to diagnose the issue, and so far haven't figured out why this is happening. The best I've come up with is somewhat of a hacky workaround, after discovering that changing the entrypoint to simply ENTRYPOINT ["bash", "pilates.sh"] produces the desired results.

I would love to know the following: 1. Why does the original entrypoint drop the first run-time argument? 2. Why does the second entrypoint work any differently than the first?

When you run bash -c 'something' foo bar baz , "foo" becomes the zero'th parameter (ie $0 )

You need to insert a dummy param in there, perhaps

ENTRYPOINT ["/bin/bash", "-c", ". foo.sh", "bash"]

This is documented in the bash man page, in the description of the -c option.

A Docker container runs a single process, specified in your case by the ENTRYPOINT setting; when that process exits the container exits. Here this means that there's no surrounding shell environment you need to update, so there's no need to run your script using the . built-in; and once you're just running a simple command, there's also no need to wrap your command in a sh -c wrapper.

That yields a Dockerfile like

FROM ubuntu
COPY foo.sh foo.sh
RUN chmod +x foo.sh # if it’s not executable already
ENTRYPOINT ["./foo.sh"]

This also avoids the issue with sh -c consuming its first argument noted in @GlennJackman's answer.

I needed to access environment variables in container startup command. This works since Docker 1.12 1

SHELL [ "/bin/sh", "-c", "exec my_app \"$@\"" ]
ENTRYPOINT

The blank ENTRYPOINT will become $0 and all other arguments will be passed as-is.

Example

FROM busybox
ENV MY_VAR=foobar
SHELL [ "/bin/sh", "-c", "printf '[%s]\n' \"${MY_VAR}\" \"$@\"" ]
ENTRYPOINT
docker run foo/bar a b c

[foobar]
[a]
[b]
[c]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM