moby: `ARG` and `ENTRYPOINT` don't play nice.

Description of problem:

Previously defined variable with ARG is not substituted in ENTRYPOINT.

Environment details: physical, gentoo, zfs storage, zsh

$ docker version
Client:
 Version:      1.9.0
 API version:  1.21
 Go version:   go1.4.2
 Git commit:   76d6bc9
 Built:        
 OS/Arch:      linux/amd64

Server:
 Version:      1.9.0
 API version:  1.21
 Go version:   go1.4.2
 Git commit:   76d6bc9
 Built:        
 OS/Arch:      linux/amd64

$ docker info
Containers: 60
Images: 830
Server Version: 1.9.0
Storage Driver: zfs
 Zpool: data
 Zpool Health: ONLINE
 Parent Dataset: data/docker
 Space Used By Parent: 103388532736
 Space Available: 805944717312
 Parent Quota: no
 Compression: off
Execution Driver: native-0.2
Logging Driver: json-file
Kernel Version: 4.0.9-stable
Operating System: Gentoo/Linux
CPUs: 4
Total Memory: 15.59 GiB
Name: tecknack-corin
ID: JXJV:BP5E:T547:PZTF:4JSO:6SV5:B7EO:XA3U:EPV7:7Z5H:BS2Y:SAV7

$ uname -a
Linux tecknack-corin 4.0.9-stable #19 SMP Tue Oct 20 19:16:00 AEDT 2015 x86_64 Intel(R) Core(TM) i7-5500U CPU @ 2.40GHz GenuineIntel GNU/Linux

Steps to Reproduce:

How reproducible: Always

  1. Create Dockerfile

    FROM tianon/true # anything will do
    ARG type
    COPY entrypoint.sh /$type # again anything will do, e.g. `exec sh`
    ENTRYPOINT /$type
    
  2. Build: docker build --build-arg type=test -t test .

  3. Inspect: docker inspect '--format={{.Config.Entrypoint}}' test

  4. Run: docker run test

Actual Results:

  1. {[/bin/sh -c /$type]}
  2. /bin/sh: 1: /: Permission denied

Expected Results:

  1. {[/bin/sh -c /test]}
  2. Whatever is defined by entrypoint.sh.

Additional info:

COPY produces the expected result (i.e. the file /test exists).

Oddly enough the following work-around seems to work but inspect still reports /$type.

Work-around:

Dockerfile:

FROM tianon/true
ARG type
COPY entrypoint.sh /$type
ENV type $type
ENTRYPOINT /$type

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 5
  • Comments: 17 (6 by maintainers)

Commits related to this issue

Most upvoted comments

okay, not to get laughed off of here, but:

RUN ln -s ./${NAME} executable
ENTRYPOINT ["./executable"]

obviously the pattern can quickly devolve, but this just happens to be all i needed, personally

@tstibbs as explained above, the entrypoint is evaluated at runtime.

Yes, I think we all know that ENTRYPOINT is evaluated at runtime. However, a major potential of ARG is to reduce the need for templating solutions to generate Dockerfiles.

When docker build is executed, there’s no reason that ENTRYPOINT can’t be updated to reflect the hard-coded insertion of ARG, during build time.

For example:

ARG MY_CMD=whoami
SHELL ["/bin/bash", "-c"]
ENTRYPOINT ${MY_CMD}

Current behavior: docker inspect my_image | grep -A5 Entrypoint

"Entrypoint": [
    "/bin/bash",
    "-c",
    "${MY_CMD}"
],

Desired behavior: docker inspect my_image | grep -A5 Entrypoint

"Entrypoint": [
    "/bin/bash",
    "-c",
    "whoami"
],

This doesn’t seem that conceptually challenging to me.

I appreciate that ARG does not apply at runtime, however I expected that ENTRYPOINT would behave in the same fashion as RUN, in this regard. It just appears to be inconsistent behaviour to me… I thought that ENTRYPOINT was a build time setting. I mean if I wanted to execute a script that lived in an environment variable wouldn’t I just write that in the entrypoint.sh file??

This issue showed up first for me when googling “dockerfile use arg in entrypoint”, so it’s a shame it doesn’t explain why this is by design. Being able to use an ARG in the ENTRYPOINT seems like a useful feature to me, so it would be really useful to understand why that’s a bad idea before I start trying to work around it.

At the top I specify:

ARG PROJECT_NAME=MyAPI

Going through various multi-stage builds (build, test, publish, runtime) I use ${PROJECT_NAME} erverywhere to reference the project name.

How is it invalid to use the following, to be able to keep the same variable value everywhere in our Dockerfile ? …

ENTRYPOINT ["dotnet", "${PROJECT_NAME}.exe"]

This belongs to a templating tool? What?

Seems to me like this legacy issue is forcing folks to pass basic commands to sh -c just to get variable substitution.

Given this is working as designed I’m going to close the issue. If you think there’s something we may need to revisit go ahead and reopen it, or keep the chat going.

If you need something to pre-process Dockerfiles, I think that’s out of scope for the core functionality provided by the builder, and more something to a templating tool

Of course, in DevOps it’s never enough to use just one tool. Let me guess, the tool that I use for templating, I should run that tool within Docker? That way, I can Docker my Docker while I’m Dockerizing my Dockerfile templating Docker.

ARG instruct the build variables, and ENV instruct the environment variables in container running. I don’t think ARG var will take effect in container running time.

Changing that would be a huge breaking change, take for example;

ENTRYPOINT ["/bin/bash", "-c", "echo $FOOBAR"]

Running such an image with;

docker run -e FOOBAR=hello my-image

Should expand $FOOBAR at runtime, not baked into the image. If you need something to pre-process Dockerfiles, I think that’s out of scope for the core functionality provided by the builder, and more something to a templating tool

DevOps Mantra #12: If at first you don’t succeed, try a templating tool.

I want to follow DRY principle. To do so I would like to store a script name in ARG to generate the script with RUN echo 'content' > ${script_name} and then use the very same name in ENTRYPOINT ["${script_name}"]. In current Docker design I will have to create an extra envvar to work around Docker’s limitation to read ARGs at runtime in ENTRYPOINT instruction. This could be improved.

Its important to understand how env vars are set when we process a RUN. We don’t touch any $xxx on the RUN command directly, we just pass it on to the shell and its the shell that will convert $xxx into whatever value xxx may have. Note that if you used the JSON format of RUN then $xxx would not have any env var substitution processing done at all because there’s no shell. Its the equivalent of:

FOO=bar sh -c "/bin/some-command"

While CMD and ENTRYPOINT are parsed at build-time, they are not executed at build-time. So, since ARG only sets a build-time env var, when CMD and ENTRYPOINT are actually executed (at image runtime) the value of any ARG env var is no longer present.