Pages

Tuesday, June 16, 2020

Docker : Understanding Build Context

Context refers to the source directory used when building the image for a container. Whenever we build an image, we run the build command passing the Dockerfile. The Dockerfile contains instructions for building the image of which ADD, COPY etc will copy or upload files to the image. In order for the files to be uploaded or copied to the final image, we need to pass the files to the docker engine while building. This is called passing the context.

What this means is , while building the image the current directory is passed to the docker engine as context or build context. The build context contains all the files in the current directory. Based on the instructions defined in the Dockerfile, docker engine will identify files that need to be uploaded or copied to the final build image from the Build context.

Why BuildContext?
The idea behind Docker build context is to share the current directory to docker engine while building images. Docker provides a facility to run docker command on a host and have the docker engine run on different host. In this case,the build command will go to the docker engine running on a different host which doesn't have the files that need to be copied or uploaded. So when we run the docker build, the current directory is moved to the docker engine where it is running and build happens over there.

Increasing Build Time
We already knew that we can use .dockerignore to ignore files that are not needed or secure files that are not to be added. But .dockerignore can also be used to ignore large files. Let's say i have 100mb files in my current directory along with Dockerfile, if i try to build it now it takes more time because the context contains 100mb of file. So it is very important to ignore large files while building the image.

It is always advisable to ignore .git directories along with dependencies that are downloaded/built within the image such as node_modules.These are never used by the application running within the Docker Container and just add overhead to the build process.

Building a Image without Docker Build Context
Docker provides a Way to build a Image without providing a Build Context. We can run the build process as,
[root@ip-172-31-40-44 testing]# docker image build -t mytestimage - < Dockerfile

This makes sure the Docker build context is not passed to the Docker engine. There is a drawback with this approach as the current directory will not be send to the docker engine as build context and hence engine dont know how to add files. If i run the same above Dockerfile as below,
[root@ip-172-31-40-44 testing]# docker image build -t mytestimage - < Dockerfile
Sending build context to Docker daemon 2.048 kB
Step 1/4 : FROM alpine
 ---> a24bb4013296
Step 2/4 : ADD . /app
 ---> 42cdc87f30a2
Removing intermediate container 2b864d39d223
Step 3/4 : COPY test.sh /test.sh
lstat test.sh: no such file or directory
We can see the files are not available and hence build fails. So our Dockerfile needs to be written in such a way to download from the internet rather than uploaded from the current directory. This way the build context will  not be shared and the build process will be faster.

3 Different Ways to provide Docker build Context
Traditional Way : The traditional way is the most used way to pass the build context to the docker engine. Run the build process as,
[root@ip-172-31-40-44 testing]# docker build -t noignore .

This way the whole current directory is passed on fly to the Docker engine and build process completes

Git Way : Docker also supports passing the Context from the Git location as below,
[root@ip-172-31-40-44 testing]# docker build -t gitimage https://github.com/jagadish12/hellonode.git
Sending build context to Docker daemon 94.21 kB
Step 1/5 : FROM node:7-onbuild
Trying to pull repository docker.io/library/node ...
7-onbuild: Pulling from docker.io/library/node
Step 1/1 : ARG NODE_ENV
 ---> Running in 69ced8152b97
Step 1/1 : ENV NODE_ENV $NODE_ENV
 ---> Running in 4024e3b9a752
Step 1/1 : COPY package.json /usr/src/app/
Step 1/1 : RUN npm install && npm cache clean --force
 ---> Running in 5fece08d292e
*******
Step 1/1 : COPY . /usr/src/app
 ---> 3012df4023cd
Removing intermediate container 7cf9a7b2e561
Removing intermediate container 69ced8152b97
Removing intermediate container 4024e3b9a752
Removing intermediate container 30401b0d6c1f
Removing intermediate container 5fece08d292e
Step 2/5 : LABEL maintainer "jagadish.manchala@gmail.com"
 ---> Running in fd6478f09223
 ---> 67303c186c0e
Removing intermediate container fd6478f09223
Step 3/5 : HEALTHCHECK --interval=5s --timeout=5s CMD curl -f http://127.0.0.1:8000 || exit 1
 ---> Running in f10b60da636c
 ---> 587f67798add
Removing intermediate container f10b60da636c
Step 4/5 : USER 1001
 ---> Running in 6e8df2259141
 ---> 3f874c99e3fc
Removing intermediate container 6e8df2259141
Step 5/5 : EXPOSE 8000
 ---> Running in 06bedd422c05
 ---> 350f01446bb3
Removing intermediate container 06bedd422c05
Successfully built 350f01446bb3
In the above case, the Build happened by checking out the source code and building the image using the Dockerfile available on the root location of the source code.

Tar Way : The build context can also be passed from the gzip file as below,
[root@ip-172-31-40-44]: docker build -t hellonode http://host.com/hellonode.tar.gz

Hope this helps in understanding the Build Context. More to Come.

No comments :

Post a Comment