Dockerfile is a text document containing instructions for combining images, and Docker automatically generates images by reading the instructions in Dockerfile. Dockerfile is a text document containing instructions for combining images, and Docker automatically generates images by reading the instructions in Dockerfile.
#Part 1 first introduces the three most commonly used instructions in Dockerfile:
RUN
Executes commands and creates new mirror layers, RUN
often used to install packages.
For example, install curl in the Docker image of Alpine Linux
FROM alpine:latest
RUN apk add --update curl && rm -rf /var/cache/apk/*
CMD
Set the command and its parameters that are executed by default after the container starts, but CMD
can be docker run
replaced by the following command line parameters.
FROM alpine:latest
RUN apk add --update curl && rm -rf /var/cache/apk/*
CMD ["curl"]
ENTRYPOINT
Configure the command to run when the container starts, and cannot be replaced by default parameters.
FROM alpine:latest
RUN apk add --update curl && rm -rf /var/cache/apk/*
ENTRYPOINT ["curl"]
It seems that the two commands are almost duplicate instructions. In fact, users can override the default command provided by the CMD command through the command line parameters; using the ENTRYPOINT command, the parameters added on the command line will be appended to the parameter list of the curl command.
Create a curl directory, save the above code into the Dockerfile in the curl directory, then enter the curl directory to build a mirror and start a container:
mkdir curl && cd curl
cat > Dockerfile <<EOF
FROM alpine:latest
RUN apk add --update curl && rm -rf /var/cache/apk/*
ENTRYPOINT ["curl"]
EOF
docker build -t curl .
docker run --rm curl http://www.baidu.com
The output is:
Good job! Everything works fine.
The image is only 7.73MB, as shown below:
In this example, we use the ENTRYPOINT directive as the "entry" to the container. As for the CMD command, the official definition is the default executable of a container:
The main purpose of aCMD
is to provide defaults for an executing container.These defaults can include an executable, or they can omit the executable, in which case you must specify anENTRYPOINT
instruction as well.
Both of these instructions are used to specify the command to run when the container starts, and using one of them alone can achieve most use cases. But Docker provides them at the same time. In order not to confuse them in use, this article tries to clarify their usage. Without further ado, let's take a look at the detailed introduction of Part 2.
#Part 2 The essential difference between CMD and ENTRYPOINT
CMD and ENTRYPOINT instructions have fundamental differences in how they work, and they suit different applications, environments, and scenarios.
When there are parameters in the CLI command docker run
,
- The daemon will ignore CMD instructions defined in the Dockerfile.
- ENTRYPOINT is not ignored and arguments on the command line are appended to the argument list for the command specified by ENTRYPOINT.
Next, let's take a closer look at these two directives.
Docker CMD
Provides a default command to execute for the container.
A Dockerfile can have one or more CMD instructions, in case of multiple CMD instructions, all but the last one will be ignored.
For example:
mkdir cmd && cd cmd
cat > Dockerfile <<EOF
FROM ubuntu
CMD ["/bin/echo", "1"]
CMD ["/bin/echo", "2"]
EOF
docker build -t cmd .
docker run --rm cmd
The output is:
If we docker run
add parameters to the command, it will override the default CMD command, the syntax is:
docker run IMAGE [COMMAND] [ARG...]
For example:
docker run cmd hostname
The output is:
Therefore, the best time to use the CMD command is:
Provides the container with a default command to execute when the user enters no arguments on the command line.
This directive ensures that the container is running by starting the application as soon as the container image is running. The reason for this is that the CMD command loads the base image as soon as the container starts.
Docker ENTRYPOINT
In a Dockerfile, the ENTRYPOINT directive is used to set an executable to always run when starting a container. Unlike the CMD command, the ENTRYPOINT command cannot be ignored or rewritten (accurately speaking, the docker run
following command line parameters will not override the ENTRYPOINT command; docker run
it --entrypoint
can override the command set by ENTRYPOINT in the Dockerfile), even if the command line parameter is declared when the container is running .
The Docker ENTRYPOINT command supports two modes of writing: shell and exec:
- Exec mode:
ENTRYPOINT ["executable", "parameter1", "parameter2"]
- Shell mode:
ENTRYPOINT command parameter1 parameter2
First an example:
mkdir entrypoint && cd entrypoint
cat > Dockerfile <<EOF
FROM ubuntu
ENTRYPOINT ["/bin/echo"]
EOF
docker build -t entrypoint .
docker run --rm entrypoint
The output is:
Empty, nothing, which is what we expect since no echo
arguments are passed to the command.
Run a new container, adding parameters $HOME
:
docker run --rm entrypoint $HOME
The output is:
Conclusion: When the ENTRYPOINT command is in exec mode, the parameters specified on the command line will be added as parameters to the parameter list of the command specified by ENTRYPOINT.
So, when the ENTRYPOINT command is in shell mode, what happens to the command-line arguments?
Modify the Dockerfile, create the image and run the container:
cat > Dockerfile <<EOF
FROM ubuntu
ENTRYPOINT /bin/echo
EOF
docker build -t entrypoint .
docker run --rm entrypoint
The output is empty when no parameters are added:
Add parameters $HOME
:
docker run --rm entrypoint $HOME
The output is still empty:
In shell mode, pass parameters through CMD, can the ENTRYPOINT command be received, let’s try again:
cat > Dockerfile <<EOF
FROM ubuntu
ENTRYPOINT /bin/echo
CMD $HOME
EOF
docker build -t entrypoint .
docker run --rm entrypoint
The output is still empty:
Conclusion: When the ENTRYPOINT command is in shell mode, the command line and CMD parameters are ignored.
Generally, we will use the exec mode of ENTRYPOINT as the default execution command after the docker container is started. It contains the invariant part and requires other parameters, which can be added to the command line when docker run
running the container.
Using CMD and ENTRYPOINT at the same time
CMD and ENTRYPOINT are two instructions with similar functions, and some cases may need to use their combined instructions in the Dockerfile. Commands can be defined using the ENTRYPOINT directive, while parameters can be defined using the CMD.
example:
mkdir cmd-entrypoint && cd cmd-entrypoint
cat > Dockerfile <<EOF
FROM ubuntu
ENTRYPOINT ["echo", "Hello"]
CMD ["Darwin"]
EOF
docker build -t cmd-entrypoint .
docker run --rm cmd-entrypoint
The output is:
Appending a command with an argument such as Hawking will override the CMD command and execute only the ENTRYPOINT command with the CLI parameter as an argument. For example:
docker run --rm cmd-entrypoint Hawking
The output is:
This is because the ENTRYPOINT directive cannot be ignored, and when using CMD, command line arguments override this directive.
Use ENTRYPOINT or CMD
Both ENTRYPOINT and CMD are essential for building and running Dockerfiles, it all depends on the usage scenario, in general:
- Use the RUN command to install applications and software packages and build images.
- Always need to execute a command to build an executable Docker image, choose the ENTRYPOINT command.
- The CMD command is best suited as an additional set of parameters to the default command, while allowing
docker run
the command line to replace the default parameters.
Also note that in the Dockerfile:
- If there are multiple ENTRYPOINT directives, the last one overrides the previous ones
- If there are multiple CMD commands, the last one will override the previous ones
- At least one ENTRYPOINT instruction or CMD instruction
#Part 3 Shell mode and exec mode
First, we need to understand how the Docker daemon processes instructions after they have been delivered.
All Docker command commands either belong to shell mode or exec mode. We understand the commands in these two modes through a simple Dockerfile example:
1 Shell mode
As the name suggests, commands in the shell form start processes running in the shell, which are equivalent to /bin/sh -c "task command"
executing task commands in the same way.
The syntax is:
<instruction><command>
See the example below:
FROM ubuntu
CMD top
Create the shell-command-form directory, save the above code into the Dockerfile in the shell-command-form directory, build the image, and start a container:
mkdir shell-command-form && cd shell-command-form
cat > Dockerfile <<EOF
FROM ubuntu
CMD top
EOF
docker build -t shell-command-form .
docker run -itd --name shell-command-form-test shell-command-form
Then look at the process ID in the container:
docker exec shell-command-form-test ps aux
The command executed by process 1 is unexpectedly , and the process ID of the command /bin/sh -c top
we specified is 7. top
The reason why Docker is arranged in this way is to allow the commands or scripts we execute to get the environment variables .
By running docker ps
the command, it can also be seen that Docker first runs /bin/sh -c top
:
Define environment variables in Dockerfile
The syntax is:
ENV <key> <value>
Define an environment variable whose key is name:
ENV name Darwin
CMD /bin/echo "Welcome, $name"
Based on the examples above, build the image and start a container:
docker build -t darwin .
docker run --rm darwin
The output is:
This form of command validates before returning results, often causing performance bottlenecks. Therefore, shell mode is generally not the preferred mode unless there is a specific need for command/environment validation.
2 Executable mode
Different from the Shell mode, the commands written in the Executable command mode directly run the executable script without being verified and processed by the shell.
The syntax is as follows:
<instruction>[“executable”, “parameter 1”, “parameter 2”, …]
example:
RUN ["yum", "-y", "update"]
CMD ["yum", "install", "-y", "ebtables"]
Execute commands with environment variables in exec mode:
cat > Dockerfile <<EOF
FROM ubuntu
ENV name Darwin
CMD ["/bin/echo", "Welcome, \$name"]
EOF
docker build -t executable-command-form .
docker run --rm executable-command-form
The output is:
This proves that Docker did not replace the user-defined environment variables with the corresponding values during the running process.
Will the environment variables of the system be output in exec mode? We print the HOSTNAME in the Linux system environment variable through the CMD command in exec mode:
cat > Dockerfile <<EOF
FROM ubuntu
CMD ["/bin/echo", "\$HOSTNAME"]
EOF
docker build -t executable-command-form .
docker run --rm executable-command-form
The output is:
So far, the following conclusions have been drawn:
In exec mode, related commands will not be executed through the shell, so system environment variables like $HOSTNAME cannot be obtained.
Then in exec mode, what should I do if I want to output custom environment variables and system environment variables?
It is to execute the shell in this mode to obtain environment variables:
cat > Dockerfile <<EOF
FROM ubuntu
ENV name Darwin
CMD ["/bin/sh", "-c", "echo \$name && echo \$HOSTNAME"]
EOF
docker build -t executable-command-form .
docker run --rm executable-command-form
The output is:
So far, the values of custom environment variables and system environment variables have been perfectly obtained.
Using exec mode and shell mode, the difference between executing ENTRYPOINT and CMD
reference:
Dockerfile referencedocs.docker.com/engine/reference/builder/#cmdEdit
Dockerfile referencedocs.docker.com/engine/reference/builder/#entrypointEdit