Let’s assume we are containerising an Angular application & we created Dockerfile at project’s root directory
FROM nginx:1.17.1-alpineCOPY nginx.conf /etc/nginx/nginx.confCOPY /dist/my-app /usr/share/nginx/html
Lets build our Angular project first
> ng build --prod
After build, project directory looks like below
Lets build the Docker image now
> docker build -t my-img .Sending build context to Docker daemon 378.9MBStep 1/3 : FROM nginx:1.17.1-alpine---> ea1193fd3ddeStep 2/3 : COPY nginx.conf /etc/nginx/nginx.conf---> 7c915599a748Step 3/3 : COPY /dist/my-app /usr/share/nginx/html---> 1db9733be99bSuccessfully built 1db9733be99bSuccessfully tagged my-img:latest
The docker build
command approximately took 53 seconds to run 😱
On side note, you can calculate 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 for building 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 Build Context
In docker build -t my-img .
command, you could have noticed .(dot) at the end which implies
- Dockerfile resides in the current directory
- Build context is set in the current directory
Docker build command will first compress and create a tar file of everything inside Build Context’s directory. Then that tar file will be sent to the Docker Daemon for building Docker image
Since we kept Dockerfile in the project root directory, build command is creating tar file of entire root directory of the project (including node_modules folder 😱)
Thats why we are seeing Sending build context to Docker daemon 378.9MB in output, meaning 378.9 MB transferred to Docker daemon for building the docker image by the build command
Note, Docker Daemon could be running either in our local system or in remote server. If its in remote, we will be sending 378 MB data to Docker Daemon in remote server for every single build command
How to avoid this ?
Don’t create Dockerfile in project root directory ! Always create Dockerfile or docker-compose file inside Docker folder
Whats the catch with this solution ?
Dockerfile can only refer to files/folders available in its current or its subdirectories
E.g. — Angular/NodeJS Application
We need contents of dist folder to build our Docker image. The dist folder usually gets generated in root directory by ng build
command
If we moved Dockerfile to Docker folder, we can’t refer dist folder from Dockerfile
How to fix this ?
Go to angular.json file & change the “outputPath”: “dist/my-app” to “outputPath”: “Docker/dist/my-app”
This will ensure the dist folder getting generated inside Docker folder all the time
After doing above step, Lets run docker build
from inside Docker folder
> ng build --prod> cd Docker > docker build -t my-img .Sending build context to Docker daemon 273.4kBStep 1/3 : FROM nginx:1.17.1-alpine---> ea1193fd3ddeStep 2/3 : COPY nginx.conf /etc/nginx/nginx.conf---> Using cache---> 7c915599a748Step 3/3 : COPY /dist/my-app /usr/share/nginx/html---> Using cache---> 1db9733be99bSuccessfully built 1db9733be99bSuccessfully tagged my-img:latest
Note :
- Only 273.4kB sent to Docker daemon from Build Context
- Build completed in just 1.079 seconds 🔥🔥🔥
E.g — Spring Boot Application
Consider a Spring Boot app with Dockerfile created in project root directory
FROM openjdk:8-jdk-alpine
COPY target/EmpApp.jar EmpApp.jar
EXPOSE 8080
CMD ["java", "-jar", "EmpApp.jar"]
Project structure looks like below
Let’s build the Docker image
> mvn clean package> docker build -t emp-img .Sending build context to Docker daemon 81.33MBStep 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
---> 4b1e9218d37cSuccessfully built 4b1e9218d37c
Successfully tagged emp-img:latest
Build command is sending nearly 81 MB tar file (including src, target & even .idea folder) to Docker daemon and entire build took approximately 12 seconds to run
Now let’s move the Dockerfile to Docker folder. Remember, we still need the JAR file from target folder to build Docker image
So lets configure the spring-boot-maven-plugin to create JAR file inside Docker folder instead of target folder
In pom.xml
<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>
Now mvn clean package
will create EmpApp.jar file inside Docker folder
Lets run the docker build
command again & see the results
> mvn clean package> cd Docker> docker build -t emp-img .Sending build context to Docker daemon 40.5MBStep 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
---> 83a17ced023aSuccessfully built 83a17ced023a
Successfully tagged emp-img:latest
Now Docker build only sends 40 MB (size of EmpApp.jar) to Docker Daemon & the entire build took only 4.49 seconds
Thats all folks !!!