cd ..
DOCKER

All Dockerfile Instructions and the Difference Between ENTRYPOINT and CMD

All Dockerfile Instructions and the Difference Between ENTRYPOINT and CMD

In the previous part, we built a simple image using FROM, RUN, EXPOSE, and CMD. The Dockerfile has several other instructions — each solving a specific problem related to how the image is assembled and how the container behaves upon startup.

Instruction Reference Guide

InstructionWhat it does
FROMindicates which image will be used as the base. Must be the first line of the Dockerfile
RUNexecutes a command in a new layer on top of the image and “commits” the change, available for subsequent instructions
COPYcopies new files and directories from the build context and adds them to the container’s filesystem
ADDcopies files, directories, TAR archives, or remote files (URLs) to the container’s filesystem — more powerful than COPY, but also less predictable
CMDdefines the default command executed when the container starts. Unlike RUN, which runs during the build, CMD only runs at runtime
ENTRYPOINTconfigures the container to run as a fixed executable. When this executable terminates, the container also terminates
ENVdefines environment variables available inside the container
EXPOSEinforms which port the container will be listening on (documentation — doesn’t publish the port by itself)
LABELadds metadata to the image, such as version, description, and author
MAINTAINERdefines the author of the image (old instruction, now replaced by LABEL)
USERdetermines which user will be used when running the image. By default it’s root
VOLUMEcreates a mount point in the container, marking that path as persistent data
WORKDIRchanges from the root directory (/) to the specified directory

ENTRYPOINT vs CMD

This is the point that causes the most confusion, so it’s worth breaking it down carefully.

The important detail appears when both are together in the same Dockerfile: in this case, CMD ceases to be a command and instead only provides the parameters for the ENTRYPOINT.

ENTRYPOINT ["/usr/sbin/apachectl"]
CMD ["-D", "FOREGROUND"]

This is useful because CMD can still be overridden when running the container (docker run my-image -D BACKGROUND, for example), while ENTRYPOINT remains guaranteed — the container will always run Apache; only the parameters change.

A more everyday example, with Nginx:

ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]

Here, ENTRYPOINT definitively turns the container into “an Nginx”. The daemon off; in CMD ensures that Nginx runs in the foreground — without it, the process would move to the background, and the container, lacking any foreground process to keep track of, would terminate immediately.

Passing build variables to the container with ARG and ENV

ARG defines a variable available only during the build. For it to also be accessible inside the container at runtime, it needs to be “promoted” to an ENV:

ARG GIROPOPS
ENV GIROPOPS=$GIROPOPS

Inspecting the result

After building the image, you can check everything that was configured — Entrypoint, Cmd, Env, ExposedPorts — with:

docker container inspect meu-nginx

Conclusion

With these instructions, a Dockerfile is no longer just “installing a package and running a command” and truly begins to describe how an application should behave inside the container: which user to use, which variables to inject, which data to persist, and which process is, in fact, the owner of the container.

If the goal is to reduce the final image size — for example, when the application needs build tools that shouldn’t go into production —, it’s worth complementing this reading with the post on multi-stage builds, which separates the build stage from the execution stage within the same Dockerfile.

In the next part of the series, we’ll teach Docker to be wary of its own container with HEALTHCHECK.

References

What did you think?