cancel
Showing results for 
Search instead for 
Did you mean: 
Sergey
Flight Engineer Flight Engineer
Flight Engineer
  • 5,877 Views

Dockerfile: If ENTRYPOINT is specified, variables in CMD are not getting expanded

Jump to solution

An interesting behavior of docker build.

  When you run a container based on the image built from this Dockerfile, you will see 'This as a DO285 class'.

 

FROM rhel7
ENV class "/bin/echo This as a DO285 class"
#ENTRYPOINT /bin/echo
CMD $class

But a container built from the above Dockerfile with ENTRYPOINT uncommented will return nothing.

 

It looks like variable expansion in CMD is not happening if ENTRYPOINT is specified.  Why ?

Labels (1)
Tags (2)
1 Solution

Accepted Solutions
oldbenko
Moderator
Moderator
  • 5,856 Views

Hey, @Sergey!

What you're seeing is partly explained by what @Ricardo said just above, but to be a bit more precise. From Dockerfile(5):

CMD
         -- CMD has three forms:
                ...
                # the command is run in a shell - /bin/sh -c
                CMD command param1 param2

You are using the above form, so your /bin/echo is actually executed in a shell like this:

/bin/sh -c "$class"

Because Bourne shell can do variable expansion, this turns to:

/bin/sh -c "/bin/echo This as a DO285 class"

When you set ENTRYPOINT to /bin/echo, this changes. Again, from Dockerfile(5):

       ENTRYPOINT
         -- ENTRYPOINT has two forms:
                ...
                # run command in a shell - /bin/sh -c
                ENTRYPOINT command param1 param2
                ...
        Specify a plain string for the ENTRYPOINT, and it will execute in
        /bin/sh -c, like a CMD instruction
        ...
        To make this optional but default, use a CMD:
                FROM ubuntu
                CMD ["-l", "-"]
                ENTRYPOINT ["/usr/bin/wc"]

 The above literally means that you can only expect ENTRYPOINT and CMD to be merged when you use the JSON notation.

So not using the array form should actually run the startup command in a shell like this:

/bin/sh -c "${ENTRYPOINT}"

So for your use case, that would be:

/bin/sh -c "/bin/echo"

Which is what you get.

What happens in the example @Ricardo suggested is that since you passed ENTRYPOINT as JSON, it is not executed in a shell:

/bin/echo $class

Because /bin/echo can not do shell variable expansion, you see $class unexpanded.

Hope this helped.

A black cat crossing the street signifies that the animal is going somewhere.
[don't forget to kudo a helpful post or mark it as a solution!]

View solution in original post

3 Replies
Ricardo
Flight Engineer Flight Engineer
Flight Engineer
  • 5,869 Views

Try to right using array syntax: 

ENTRYPOINT ["/bin/echo"]
CMD ["$class"]

This is because if you don't enclose them, docker will encapsulate into a sh command:

/bin/sh -c "<ENTRYPOINT>"

which can have different results from what you expect.  

Sergey
Flight Engineer Flight Engineer
Flight Engineer
  • 5,862 Views

Ricardo, I am not expecting results. I am trying to understand what I see.

Your example returns '$class' unexpanded.

The question  remains: why variable expansion in CMD is NOT happening if ENTRYPOINT is specified, and does happen when ENTRYPOINT is null.

oldbenko
Moderator
Moderator
  • 5,857 Views

Hey, @Sergey!

What you're seeing is partly explained by what @Ricardo said just above, but to be a bit more precise. From Dockerfile(5):

CMD
         -- CMD has three forms:
                ...
                # the command is run in a shell - /bin/sh -c
                CMD command param1 param2

You are using the above form, so your /bin/echo is actually executed in a shell like this:

/bin/sh -c "$class"

Because Bourne shell can do variable expansion, this turns to:

/bin/sh -c "/bin/echo This as a DO285 class"

When you set ENTRYPOINT to /bin/echo, this changes. Again, from Dockerfile(5):

       ENTRYPOINT
         -- ENTRYPOINT has two forms:
                ...
                # run command in a shell - /bin/sh -c
                ENTRYPOINT command param1 param2
                ...
        Specify a plain string for the ENTRYPOINT, and it will execute in
        /bin/sh -c, like a CMD instruction
        ...
        To make this optional but default, use a CMD:
                FROM ubuntu
                CMD ["-l", "-"]
                ENTRYPOINT ["/usr/bin/wc"]

 The above literally means that you can only expect ENTRYPOINT and CMD to be merged when you use the JSON notation.

So not using the array form should actually run the startup command in a shell like this:

/bin/sh -c "${ENTRYPOINT}"

So for your use case, that would be:

/bin/sh -c "/bin/echo"

Which is what you get.

What happens in the example @Ricardo suggested is that since you passed ENTRYPOINT as JSON, it is not executed in a shell:

/bin/echo $class

Because /bin/echo can not do shell variable expansion, you see $class unexpanded.

Hope this helped.

A black cat crossing the street signifies that the animal is going somewhere.
[don't forget to kudo a helpful post or mark it as a solution!]
Join the discussion
You must log in to join this conversation.