Detailed explanation of Docker's build context

Yesterday I wrote about using Dockerfile to customize the image. Among them, the construction context is not written. Today, I will write this separately.

Docker image build

Simply talk about the steps to build a mirror:

  1. cd the directory where the Dockerfile is located;

  2. Execute docker build build command:

    docker build -t imageName:imageTag .

Through the above workflow, it is easy to form such misunderstandings:

  1. The. behind docker build is the directory where the Dockerfile is located;
  2. Dockerfile file name must be Dockerfile;

In fact, the above understanding is wrong. To understand its meaning accurately, we first need to understand the Docker architecture and the working principle of docker build.

Docker architecture

Docker uses a C/S (client/server) architecture. The Docker client communicates with the Docker daemon, and the Docker daemon is responsible for building, running and distributing Docker containers. The Docker client and daemon can run on the same system, or you can connect the Docker client to a remote Docker daemon. The Docker client and daemon use REST APIs to communicate through UNIX sockets or network interfaces.

https://docs.docker.com/engine/images/architecture.svg

How docker build works

  1. Client side executes docker build. command;
  2. The Docker client will package and send all files under the path (.) specified after the build command to the Docker server;
  3. The Docker server receives the package sent by the client, then decompresses it, and builds the image in layers according to the instructions in the Dockerfile;

Image construction context (Context)

When we are building a mirror, not all customization will be done through the RUN instruction. It is often necessary to copy some local files into the mirror, such as through the COPY instruction, ADD instruction, etc. The docker build command builds an image, in fact, it is not built locally, but on the server side, which is the Docker engine. So in this client/server architecture, how can the server get local files?

This introduces the concept of context. When building, the user will specify the path to build the image context. After the docker build command knows this path, it will package all the content under the path and upload it to the Docker engine. In this way, after the Docker engine receives the context package, it will get all the files needed to build the image. If you write this in the Dockerfile:

COPY ./package.json /app/

This is not to copy package.json in the directory where the docker build command is executed, nor is it to copy package.json in the directory where the Dockerfile is located, but to copy package.json in the context directory.

Therefore, the source file path in the COPY instruction is a relative path. This is also the reason why COPY ../package.json /app or COPY /opt/xxxx /app cannot work, which is often asked by beginners, because these paths are beyond the scope of the context, and the Docker engine cannot obtain files in these locations. If those files are really needed, they should be copied to the context directory.

Example 1:

[root@192 test]# ls
Dockerfile
[root@192 test]# cat Dockerfile
FROM alpine:latest
ADD  /root/mydocker/apache-tomcat-9.0.27.tar.gz /data/soft
[root@192 test]# ls /root/mydocker/apache-tomcat-9.0.27.tar.gz
/root/mydocker/apache-tomcat-9.0.27.tar.gz
[root@192 test]# docker build  .
Sending build context to Docker daemon  3.072kB
Step 1/2 : FROM alpine:latest
 ---> 965ea09ff2eb
Step 2/2 : ADD /root/mydocker/apache-tomcat-9.0.27.tar.gz /data/soft
ADD failed: stat /var/lib/docker/tmp/docker-builder904012777/root/mydocker/apache-tomcat-9.0.27.tar.gz: no such file or directory

As can be seen:

  1. The image build context path is not the path where the Dockerfile file is located;
  2. The working directory of the instruction in the Dockerfile is the path where the server decompresses the client transmission package, because the ADD instruction fails, which means that there is no apache-tomcat file in the current directory;

Understanding the build context is very important for image builds to avoid making mistakes that shouldn't be made. For example, some beginners found that COPY /opt/xxxx /app did not work, so they simply put the Dockerfile in the root directory of the hard disk to build, and found that after the docker build was executed, sending a tens of GB of things was extremely slow and easy The build failed. That's because this approach is to let docker build package the entire hard drive, which is obviously a misuse.

Generally speaking, the Dockerfile should be placed in an empty directory, or in the project root directory. If there is no required file in this directory, you should copy the required file. If something in the directory really does not want to be passed to the Docker engine during build, you can write a .dockerignore in the same syntax as .gitignore. This file is used to eliminate the need to pass to the Docker engine as a context.

So why would anyone mistakenly think. Is the directory where the Dockerfile is specified? This is because by default, if the Dockerfile is not additionally specified, the file named Dockerfile in the context directory will be used as the Dockerfile.

This is just the default behavior. In fact, the file name of the Dockerfile does not need to be a Dockerfile, and it does not need to be in the context directory. For example, you can use the -f ../Dockerfile.php parameter to specify a file as a Dockerfile.

Of course, people usually use the default file name Dockerfile and place it in the image build context directory.

Example 2

[root@192 test]# docker images
REPOSITORY                         TAG                         IMAGE ID            CREATED             SIZE
tomcat                             jdk8-adoptopenjdk-hotspot   1a2bfb3e6eee        15 hours ago        318MB
openjdk                            8-jre-slim                  d0cfe439ce3d        13 days ago         184MB
btnguyen2k/oraclejdk8_jre-alpine   latest                      fab475620d00        4 years ago         208MB
[root@192 test]# cat ../mynginx/test
FROM alpine:latest
[root@192 test]# ls
apache-tomcat-9.0.27.tar.gz
[root@192 test]#  docker build -f ../mynginx/test  -t test:v1 .
Sending build context to Docker daemon  10.99MB
Step 1/1 : FROM alpine:latest
latest: Pulling from library/alpine
89d9c30c1d48: Already exists
Digest: sha256:c19173c5ada610a5989151111163d28a67368362762534d8a8121ce95cf2bd5a
Status: Downloaded newer image for alpine:latest
 ---> 965ea09ff2eb
Successfully built 965ea09ff2eb
Successfully tagged test:v1
[root@192 test]# docker images
REPOSITORY                         TAG                         IMAGE ID            CREATED             SIZE
tomcat                             jdk8-adoptopenjdk-hotspot   1a2bfb3e6eee        15 hours ago        318MB
alpine                             latest                      965ea09ff2eb        11 days ago         5.55MB
test                               v1                          965ea09ff2eb        11 days ago         5.55MB
openjdk                            8-jre-slim                  d0cfe439ce3d        13 days ago         184MB
btnguyen2k/oraclejdk8_jre-alpine   latest                      fab475620d00        4 years ago         208MB     

As can be seen:

The file name of the Dockerfile is not required to be a Dockerfile, and it is not required to be in the context directory. For example, you can specify a file as a Dockerfile with the -f ../mynginx/test parameter.

Guess you like

Origin blog.csdn.net/qq_45534034/article/details/112567761