Dockerfile

Main commands of Dockerfile

  • FROM defines base image of this image
  • ADD copies from source (local file, url, tar) to destination directory
  • ARG declares build-time variable
  • CMD executes command at the container running state
  • COPY copies from source directory to destination directory
  • ENTRYPOINT configures a container that will run as an executable
  • ENV sets the environment variable
  • EXPOSE informs Docker that the container listens on the specified network ports at runtime
  • LABEL adds metadata to an image
  • RUN executes command at the image building state, it is often used for installing software packages
  • USER sets the user name (or UID) and optionally the user group (or GID) to use when running the image and for any RUN, CMD and ENTRYPOINT
  • VOLUME creates a mount point with the specified name and marks it as holding externally mounted volumes from native host or other containers
  • WORKDIR sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile

Command FROM

# FROM <image> [AS <name>]
# FROM <image>[:<tag>] [AS <name>]
# FROM <image>[@<digest>] [AS <name>]
FROM java:8-jre-alpine

Initializes a new build stage and sets the Base Image for subsequent instructions. A valid Dockerfile must start with a FROM instruction. Image will be pulled if necessary.

FROM can appear multiple times within a single Dockerfile to create multiple images or use one build stage as a dependency for another. Each FROM instruction clears any state created by previous instructions.

tag, digest and 'AS name' are optional.

Command ARG

# ARG <name>[=<default value>]
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER v1.0.0
RUN echo $CONT_IMG_VER

ARG  CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD  /code/run-app

Arguments passed in command line

docker build --build-arg CONT_IMG_VER=v2.0.1 .

Commands ADD and COPY

Both commands make copy to destination directory. But ADD allow copy from url or extract a local tar file.

# ADD [--chown=<user>:<group>] <src>... <dest>
# ADD [--chown=<user>:<group>] ["<src>",... "<dest>"] (used when paths containing whitespace)
# COPY [--chown=<user>:<group>] <src>... <dest>
# COPY [--chown=<user>:<group>] ["<src>",... "<dest>"] (used when paths containing whitespace)

ADD hom* /mydir/         # adds all files starting with "hom"
COPY hom* /mydir/      # adds all files starting with "hom"
ADD hom?.txt /mydir/   # ? is replaced with any single character, e.g., "home.txt"
ADD test relativeDir/     # adds "test" to `WORKDIR`/relativeDir/
ADD test /absoluteDir/ # adds "test" to /absoluteDir/
ADD rootfs.tar.gz /. 

Commands CMD, ENTRYPOINT

# ENTRYPOINT ["executable", "param1", "param2"] (exec form, preferred)
# ENTRYPOINT command param1 param2 (shell form)
ENTRYPOINT java -Dspring.profiles.active=production -jar ${JAR_FILE}

# CMD ["executable","param1","param2"] (exec form, this is the preferred form)
# CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
# CMD command param1 param2 (shell form)
CMD echo "Hello world"

# same ENTRYPOINT ["ping", "socode4.com"]
ENTRYPOINT ["ping"]
CMD ["socode4.com"]

ENV myvar MyValue
# result will be "myvar = MyValue"
ENTRYPOINT echo "myvar = $myvar"
# result will be "myvar = $myvar"
ENTRYPOINT ["/bin/echo", "myvar = $myvar"]

You must have one ENTRYPOINT or CMD command for running container.

If ENTRYPOINT use shell form, then the CMD command will be ignored, otherwise parameters of CMD will be append to ENTRYPOINT.

If the docker file contains only one of these two commands the result will be the same. Just CMD can be overwritten from command line when docker container runs. And ENTRYPOINT defines executable container.

In exec form you can't use environment variables like $PATH.

Commands will be executed from current working directory (see WORKDIR)

Command RUN

# RUN <command> (shell form, the command is run in a shell, which 
#     by default is /bin/sh -c on Linux or cmd /S /C on Windows)
# RUN ["executable", "param1", "param2"] (exec form)
RUN apt-get install python3
# long command line
RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'

# Every RUN command will be executed from current working directory. 
# So first ls and last ls will show different results.
RUN cd app && ls # show /app
RUN cd app
RUN ls # show /

Command WORKDIR

# WORKDIR /path/to/workdir
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd  # output will be /a/b/c.

ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd # will be /path/$DIRNAME

Default workdir is root ("/") directory.
You can not use directory of volume as working directory, even if volume defined on a start container command or in .yml file.

Command EXPOSE

# EXPOSE  [/...]
EXPOSE 8080
EXPOSE 80/tcp
EXPOSE 80/udp

Docker doesn’t publish exposed ports by itself. Because there is no way to guarantee that the port will be available on the host machine where you run the image. So exposed ports not accessible from outside Docker. But can be accessible from inside other Docker containers which connected to the same container's network. It is good for inter-container communication.

To make a port available to services outside of Docker, or to Docker containers which are not connected to the container's network, use the --publish or -p flag. If you provide the -P option when running your container, it will bind each exposed port to a random ports of the host.

# here map container port 27017 to port 27017 of host machine
docker run --name mongo -d -p 27017:27017 -v ~/data:/data/db mongo

Command LABEL

# LABEL = = = ...
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."

LABEL multi.label1="value1" multi.label2="value2" other="value3"

LABEL multi.label1="value1" \
      multi.label2="value2" \
      other="value3"

LABEL maintainer="[email protected]"

Command ENV

# ENV <key> <value>
# ENV <key>=<value> ...
ENV myName="John Doe" myDog=Rex\ The\ Dog \
    myCat=fluffy

ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy

You can override value from command line

docker run --env <key>=<value> ... 

Command USER

# USER <user>[:] or
# USER [:]

# On Windows, the user must be created first if it’s not a built-in account. 
# This can be done with the net user command called as part of a Dockerfile
FROM microsoft/windowsservercore
RUN net user /add patrick # create windows user in the container
USER patrick

Command VOLUME

# VOLUME ["/data"]
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol

It is recommended not to use this command. Better define volumes when starting a container or in .yml file.
You can not use directory of volume as working directory, even if volume defined on a start container command or in .yml file.