ObjectNameDisplay
ObjectNameDisplay

Reputation: 493

How do I Run Docker cmds Exactly Like in a Dockerfile

There seems to be a difference between how Docker runs commands in a Dockerfile versus running commands manually after starting a container. This seems to be due to the kind of shells you can start, a (I assume) non-interactive shell with a Dockerfile vs an interactive one when running something like docker run -it <some-img-id>.

How can I debug running commands in a Docker container so that it runs exactly like the commands are run from a Dockerfile? Would just adding /bin/bash --noprofile to the run cmd suffice? Or is there anything else different about the environment when started from a Dockerfile?

Upvotes: 0

Views: 1252

Answers (2)

Tarun Lalwani
Tarun Lalwani

Reputation: 146630

What you are experiencing is the behavior because of the shell. Most of us are used to using the bash shell. So generally we would attempt to run the commands in the below fashion

For new container

docker run -it <imageid> bash

For existing container

docker exec -it <containerid> bash

But when we specify some command using RUN directive inside a Dockerfile

RUN echo Testing

Then it is equivalent to running /bin/sh -c 'echo Testing'. So you can expect certain differences as both the shells are different.

In Docker 1.12 or higher you have a Dockerfile directive named SHELL this allows you to override the default SHELL

SHELL ["/bin/bash", "-c"]
RUN echo Testing

This would make the RUN command be executed as bash -c 'echo Testing'. You can learn more about the SHELL directive here

Upvotes: 1

Luk&#225;š Doležal
Luk&#225;š Doležal

Reputation: 289

Short answer 1:

If Dockerfile don't use USER and SHELL commands, then this:

docker --entrypoint "/bin/sh -c" -u root <image> cmd

Short answer 2:

If you don't squash or compress image after the build, Docker creates images layers for each of the Dockerfile commands. You can see them in the output of docker build at the end of each step with --->:

Step 2/8 : WORKDIR /usr/src/app
  ---> 5a5964bed25d # <== THIS IS IMAGE ID OF STEP 2
Removing intermediate container b2bc9558e499
Step 3/8 : RUN something
  ---> f6e90f0a06e2 # <== THIS IS IMAGE ID OF STEP 3
Removing intermediate container b2bc9558e499

Look for the image id just before the RUN step you want to debug (for example you want to debug step 3 on above, take the step 2 image id). Then just run the command in that image:

docker run -it 5a5964bed25d cmd

Long answer 1:

When you run docker run [image] cmd Docker in fact starts the cmd in this way:

  • Executes the default entrypoint of the image with the cmd as its argument. Entrypoint is stored in the image on build by ENTRYPOINT command in Dockerfile. Ie if cmd is my-app and entrypoint is /bin/sh -c, it executes /bin/sh -c my-app.
  • Starts it with default user id of the image, which is defined by the last USER command in Dockerfile
  • Starts it with the environment variables from all ENV commands from image's Dockerfile commulative

When docker build runs the Dockerfile RUN, it does exatly the same, only with the values present at that time (line) of the Dockerfile.

So to be exact, you have to take the value of ENVs and last USER command before your RUN line, and use those in the docker run command.

Most common images have /bin/sh -c or /bin/bash -c as entrypoint and most likely the build operates with root user. Therefore docker --entrypoint "/bin/bash -c" -u root <image> cmd should be sufficient

Upvotes: 1

Related Questions