Records of Some Usage and Best Practices of Dockerfile
Record some usage and best practices encountered during the use of Dockerfile.
Differences between COPY and ADD Commands
Both COPY
and ADD
are Dockerfile instructions that can copy files or directories from the host to the Docker image. However, there are some differences between them:
Function: The
COPY
instruction copies new files or directories from the build context and adds them to the specified path in the image’s file system. TheADD
instruction has a similar function, but it has two additional features. First, if the source file is a tar file,ADD
will automatically extract this tar file. Second, theADD
instruction supports using a URL as the source file and will automatically download the file pointed to by this URL.Usage Recommendation: Since the
ADD
instruction has more functions, its behavior is more complex and less predictable. Docker officially recommends using theADD
instruction only when you actually need the additional features it provides. Otherwise, use theCOPY
instruction by default. This makes the Dockerfile more understandable and maintainable.Examples:
- Using the
COPY
instruction:
1
COPY test.txt /data/
This copies the
test.txt
file in the current directory to the/data/
directory in the image.- Using the
ADD
instruction:
1
ADD https://example.com/test.txt /data/
This downloads the remote
test.txt
file and copies it to the/data/
directory in the image.- Using the
Multi-stage Builds
Multi-stage compilation in Dockerfile is a new feature introduced after Docker version 17.05. It allows you to use multiple FROM
instructions in one Dockerfile. Each FROM
instruction can use a different base image and starts a new build stage. Each stage is completely independent and can be regarded as a temporary intermediate image.
There are two main advantages of multi-stage builds: one is to prevent the final production Docker image from becoming too large; the other is to avoid leaving unnecessary tools and dependencies in the image during the build process.
Here is an example of using multi-stage builds. It first uses the golang
image to compile a Go application, and then in a new stage, uses a smaller Alpine-based image to run the application:
1 | # Stage 1: Build the Go binary |
In this example, first, a build stage named builder
is defined. It starts from the golang:1.14.2
image, copies the source code into the image, and then compiles the Go application.
Then, the second build stage starts. It starts from the smaller alpine:latest
image and copies the compiled Go application from the builder
stage to the new image.
In this way, the final image only contains the compiled Go application, without additional tools and dependencies such as the Go compiler used for compilation, making the image more lightweight.
What are the Differences between CMD and ENTRYPOINT
CMD
sets the default command to be executed by the container and can have parameters. If other commands are specified when running Docker (that is, the docker run
command), the CMD command will be ignored.
ENTRYPOINT
configures the command to be run when the container starts, allowing the container to run as an application or service. Different from CMD, it will not be overridden by the command-line parameters of docker run
.
Precisely for this reason, generally, it is recommended to use ENTRYPOINT
and write all the commands to be executed into a script. This can reduce problems caused by parameter passing during the deployment process.
How to Obtain the SHA256 of a Docker Image
1 | docker inspect --format='{{index .RepoDigests 0}}' <docker image> | cut -d ':' -f 2 |
Docker Compose
Docker Compose is a tool for defining and running multi-container Docker applications. It allows users to configure the container services, networks, volumes, and other related settings of the entire application through a YAML file (usually named docker-compose.yml
). Docker Compose is an orchestration tool officially provided by Docker, mainly used to simplify the process of running multiple Docker containers on a single machine.
From my practical work experience, there are two main benefits of Docker Compose: dependency management and environment switching.
Docker Compose can manage the dependency relationships between services, ensuring that services start and stop in the correct order.
It can also write different docker-compose.yml
files for different environments (such as development, testing, production) and specify to load different configuration files through the -f
parameter.
Here is a case and explanation.
1 | version: '3.9' |
In this example:
- There is a service named
db
, which is a container based on the Postgres database image. - The
backend
service depends on thedb
service, which means thebackend
service will start after thedb
service is started and ready. Thedepends_on
keyword is used to express this dependency relationship. - The
backend
service needs to connect to thedb
service, so it setsDB_HOST
todb
because in the same Docker Compose network, services can access each other through the service name. - The
frontend
service also depends on thebackend
service. Thefrontend
service will only start when thebackend
is fully started. - The
volumes
section defines a persistent data volumedb_data
for storing the data of thedb
service, ensuring that the data will not be lost when the container restarts. - Finally, all services are assigned to the default network
my_app_net
so that they can communicate with each other.