Common Dockerfile instructions:

  • FROM: specifies an image's base image
  • RUN: runs a command in the image
  • COPY: copies a file or directory from the host to the image
  • WORKDIR: subsequent commands will take place in the specified directory within the image's file system
  • VOLUME: designates one or more folders in the image's file system as volumes, which means the contents of the folder will come from some external source while the container is running. The container may read data from here, or write to it to enable data persistence.
  • ENV: sets an environment variable in the image. This probably shouldn't be used. Instead use the -e argument with docker run, or, if using Kubernetes, defining an environment variable in a Pod or ConfigMap manifest.
  • EXPOSE: exposes a port for mapping
  • LABEL: adds metadata to an image
  • CMD: specifies a command to be run when starting the container
  • ENTRYPOINT: also specifies a command to be run when starting the container (see "CMD and ENTRYPOINT" below)

Comments can also be added to a Dockerfile by using the # character at the start of a line. Any line beginning with that character is considered a comment and is ignored. Note: Unlike in many programming languages and markups, the # character only creates a comment if it occurs at the very beginning of the line! If a line starts with some character other than a #, the whole line, including the part after the #, is used.

CMD and ENTRYPOINT

The CMD and ENTRYPOINT instructions do almost the same thing. Both use a square bracket, doublequote notation to provide a command a container will execute. For example, consider the following Dockerfiles:

Dockerfile 1:

FROM busybox:1.31.1
CMD ["echo","'Hello, World'"]

Dockerfile 2:

FROM busybox:1.31.1
ENTRYPOINT ["echo","'Hello, World'"]

(Note: both of these images are available from Docker Hub as respectively bmcase/cmd and bmcase/entrypoint)

When running containers from these images using a normal docker run, the output is identical. However, if you specify additional arguments at the end of docker run, the behavior is different. Try each of the following and notice the difference:

  • docker run bmcase/cmd ls
  • docker run bmcase/entrypoint ls

Expected output:

$ docker run bmcase/cmd ls
bin
dev
etc
home
proc
root
sys
tmp
usr
var
$ docker run bmcase/entrypoint ls
'Hello, World' ls

The CMD version completely replaced the echo command, arguments and all, with the ls command. Whereas the ENTRYPOINT version appended "ls" to the end of its command. These behaviors reflect the differing purposes of CMD and ENTRYPOINT.

  • CMD is good for containers that provide an environment in which commands are to be executed.
  • ENTRYPOINT is good for containers that run a single application, and the command invoking the application can accept arguments.

CMD and ENTRYPOINT can also be combined.

Combined CMD and ENTRYPOINT:

FROM busybox:1.31.1
ENTRYPOINT ["echo"]
CMD ["'Hello, World'"]

(This image is available from Docker Hub as bmcase/entrypoint-cmd)

Using both fixes the beginning of the command as whatever ENTRYPOINT specifies, and the default remainder of the command is specified by CMD. But CMD's part can be overridden by further arguments at the end of docker run. Observe:

$ docker run bmcase/entrypoint-cmd
'Hello, World'
$ docker run bmcase/entrypoint-cmd ls
ls
$ docker run bmcase/entrypoint-cmd Hey this isnt hello world
Hey this isnt hello world