10

How to Make Docker Build Run Faster

 3 years ago
source link: https://dzone.com/articles/how-to-make-docker-build-run-faster
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

How to Make Docker Build Run Faster

A simple tip to optimize build time in Docker.

Dec. 31, 20 · Cloud Zone · Tutorial

Join the DZone community and get the full member experience.

Join For Free

In this article, let's discuss how to run a Docker build faster with a simple tip.

Let’s assume we are containerizing an Angular application. We created a Dockerfile in the project’s root directory:

Dockerfile
FROM nginx:1.17.1-alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY /dist/my-app /usr/share/nginx/html

Let's build our Angular project first.

Shell
xxxxxxxxxx
> ng build --prod

After the build, the project directory looks like:

Dockerfile and dist in project root dir

Let's build the Docker image now.

Dockerfile
xxxxxxxxxx
> docker build -t my-img .
Sending build context to Docker daemon  378.9MB
Step 1/3 : FROM nginx:1.17.1-alpine
---> ea1193fd3dde
Step 2/3 : COPY nginx.conf /etc/nginx/nginx.conf
---> 7c915599a748
Step 3/3 : COPY /dist/my-app /usr/share/nginx/html
---> 1db9733be99b
Successfully built 1db9733be99b
Successfully tagged my-img:latest

The docker build command took approximately 53 seconds to run.

On a side note, you can calculate the time taken to run any command in Linux/Mac by appending the word time before your command

> time docker build -t my-img .

The Nginx image we used to build our Docker image is just 20.6MB in size. Why is it taking 53 seconds to build such a small Docker image?

The culprit here is the build context.

Understanding the Build Context

In the docker build -t my-img . command, you might have noticed the . (dot) at the end, which implies:

  • The Dockerfile resides in the current directory
  • The build context is set in the current directory

The Docker build command will first compress and create a TAR file of everything inside Build Context’s directory. Then that file will be sent to the Docker daemon to build the image.

Since we kept the Dockerfile in the project root directory, the build command is creating a TAR file of the entire root directory of the project (including the node_modules folder).

That's why we are seeing "Sending build context to Docker daemon 378.9MB" in the output, meaning 378.9MB are transferred to the Docker daemon to build the Docker image.

Note: The Docker daemon could be running either in our local system or on a remote server. If it's remote, we will be sending 378 MB data to the Docker daemon on a remote server for every single build command.

How to Avoid This

Don’t create the Dockerfile in the project root directory! Always create the Dockerfile or docker-compose file inside the Docker folder.

What's the Catch With This Solution?

Dockerfile can only refer to files/folders available in its current directory or its subdirectories.

In our Angular Application, we need content from the dist folder to build our Docker image. The dist folder usually gets generated in the root directory by the ng build command.

If we moved the Dockerfile to the Docker folder, we can’t refer to the dist folder from Dockerfile.

How to Fix This

In the angular.json file, change "outputPath": "dist/my-app" to "outputPath": "Docker/dist/my-app"

This will ensure the dist folder gets generated inside the Docker folder all the time.

After, let's run docker build from inside the Docker folder:

Shell
xxxxxxxxxx
> ng build --prod
> cd Docker 
> docker build -t my-img .
Sending build context to Docker daemon  273.4kB
Step 1/3 : FROM nginx:1.17.1-alpine
---> ea1193fd3dde
Step 2/3 : COPY nginx.conf /etc/nginx/nginx.conf
---> Using cache
---> 7c915599a748
Step 3/3 : COPY /dist/my-app /usr/share/nginx/html
---> Using cache
---> 1db9733be99b
Successfully built 1db9733be99b
Successfully tagged my-img:latest

Note:

  • Only 273.4KB are sent to the Docker daemon from the build context
  • Build completed in just 1.079 seconds

This same technique can be applied for Spring boot applications as well.

Spring Boot Application

In a Spring Boot application, let's start by creating a Dockerfile in the root directory.

Dockerfile:

Dockerfile
xxxxxxxxxx
FROM openjdk:8-jdk-alpine
COPY target/EmpApp.jar EmpApp.jar
EXPOSE 8080
CMD ["java", "-jar", "EmpApp.jar"]

After a mvn clean package, let's try building our docker image:

Shell
xxxxxxxxxx
> mvn clean package
> docker build -t emp-img .
Sending build context to Docker daemon  81.33MB
Step 1/4 : FROM openjdk:8-jdk-alpine
 ---> a3562aa0b991
Step 2/4 : COPY target/EmpApp.jar EmpApp.jar
 ---> 13f2e0c2b88f
Step 3/4 : EXPOSE 8080
 ---> Running in 3062c4ae9244
Removing intermediate container 3062c4ae9244
 ---> 30c5ad3077e2
Step 4/4 : CMD ["java", "-jar", "EmpApp.jar"]
 ---> Running in 6fb88cbdcf04
Removing intermediate container 6fb88cbdcf04
 ---> 4b1e9218d37c
Successfully built 4b1e9218d37c
Successfully tagged emp-img:latest

As you can see, the docker build command sent 81 MB from the build context to the Docker daemon, and the build took nearly 12 seconds to complete.

Now let's move the Dockerfile to a separate folder, say Docker. Instead of manually copy-pasting the JAR/WAR file from the target folder to the Docker folder, we tweaked the spring-boot-maven-plugin a little.

In pom.xml:

x
<plugins>
  <plugin>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-maven-plugin</artifactId>
     <executions>
        <execution>
           <goals>
             <goal>repackage</goal>
           </goals>
           <configuration>                 
              <outputDirectory>${project.basedir}/Docker
              </outputDirectory>
             <finalName>EmpApp</finalName>
           </configuration>
         </execution>
      </executions>
   </plugin>
</plugins>

After the mvn clean package command, our folder structure will look something like:

Dockerfile and JAR inside Docker folder

Now run the Docker build command from inside the Docker folder:

Shell
x
> cd Docker
> docker build -t emp-img .
Sending build context to Docker daemon   40.5MB
Step 1/4 : FROM openjdk:8-jdk-alpine
 ---> a3562aa0b991
Step 2/4 : COPY EmpApp.jar EmpApp.jar
 ---> ea534aea1444
Step 3/4 : EXPOSE 8080
 ---> Running in 29eb70ec1691
Removing intermediate container 29eb70ec1691
 ---> 7abfcf1d18ff
Step 4/4 : CMD ["java", "-jar", "EmpApp.jar"]
 ---> Running in fdf9316244dd
Removing intermediate container fdf9316244dd
 ---> 83a17ced023a
Successfully built 83a17ced023a
Successfully tagged emp-img:latest

Now the Docker build only sends 40 MB (size of EmpApp.jar) to the Docker daemon and the entire build took only 4.49 seconds.

That's all folks!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK