Day 3/40 - Multi Stage Docker Build

Table of contents
Multi-stage Docker Builds
In Docker, a Multi-stage build is a way to create Docker images that are smaller and more secure. It achieves this by separating the build process into multiple stages, each with a specific purpose.
Imagine building an application that needs to be compiled. A typical single-stage build would involve:
Installing all the build dependencies (compilers, libraries etc.)
Copying your source code
Compiling the code into an executable
(Optional) Running tests
The final image would include all of these elements, even though only the executable is actually needed to run the application.
A Multi-stage build addresses this by creating separate stages:
Build stage: This stage uses a base image with all the build dependencies. You would copy your source code, compile it and (optionally) run tests in this stage.
Runtime stage: This stage uses a minimal base image, often the empty
scratch
image. You would copy only the final executable (and any other required files) from the build stage to this final image.
By separating the build environment from the final runtime environment, you get a smaller image that's easier to manage and more secure because it doesn't contain unnecessary components.
Here are some benefits of using Multi-stage builds:
Smaller image size: Less storage space used and faster transfer times.
Improved security: Reduced attack surface by eliminating unnecessary components.
Faster builds: Build context is smaller in subsequent builds.
If you're working with Docker and want to create optimized images, Multi-stage builds are a valuable technique to consider.
Get started
- Clone the below sample repository, or you can use any web application that you have
git clone https://github.com/piyushsachdeva/todoapp-docker.git
- cd into the directory
cd todoapp-docker/
- Create an empty file with the name Dockerfile
touch Dockerfile
- Using the text editor of your choice, paste the below content: Note: Details about the below Dockerfile have already been shared in the video
FROM node:18-alpine AS installer
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:latest AS deployer
COPY --from=installer /app/build /usr/share/nginx/html
The provided code snippet defines a Dockerfile using a Multi-stage build process. Here's a breakdown of what each line does:
1. FROM node:18-alpine AS installer
This line defines the first stage named "installer".
It uses the
node:18-alpine
image as the base. This image includes the Node.js version 18 runtime environment built on top of the Alpine Linux distribution (known for being lightweight).The
AS installer
part assigns the name "installer" to this stage for future reference.
2. WORKDIR /app
- This line sets the working directory within the "installer" stage to
/app
. This is where subsequent commands will be executed unless otherwise specified.
3. COPY package.json ./*
- This line copies all files with names starting with "package" and ending with ".json" (likely
package.json
and potentially others) from the build context (your local directory where the Dockerfile resides) to the current working directory (/app
) within the "installer" stage.
4. RUN npm install
- This line executes the command
npm install
within the "installer" stage. This assumes there's apackage.json
file present (copied in the previous step) and it will download and install all the dependencies listed in that file using the npm package manager.
5. COPY . .
- This line copies all files and folders from the build context (.) to the current working directory (.) within the "installer" stage. This likely copies your entire application codebase alongside the installed dependencies.
6. RUN npm run build
- This line executes the command
npm run build
within the "installer" stage. This assumes you have a script named "build" defined in yourpackage.json
file that performs actions like compiling your application code into a production-ready format.
7. FROM nginx:latest AS deployer
This line defines a second stage named "deployer".
It uses the
nginx:latest
image as the base. This image includes the latest version of the Nginx web server.Similar to before,
AS deployer
assigns the name "deployer" to this stage.
8. COPY --from=installer /app/build /usr/share/nginx/html
This line uses the
COPY --from
instruction. Here,--from=installer
specifies that we're copying from the "installer" stage we defined earlier./app/build
is the source path within the "installer" stage. This likely points to the compiled application code generated by thenpm run build
command./usr/share/nginx/html
is the destination path within the "deployer" stage. This is the default directory where Nginx serves web content.
Build the docker image using the application code and Dockerfile
docker build -t todoapp-docker .
- Verify the image has been created and stored locally using the below command:
docker images
- To start the docker container, use the below command
docker run -dp 3000:3000 todoapp-docker
Verify your app. If you have followed the above steps correctly, your app should be listening on localhost:3000
To enter(exec) into the container, use the below command
docker exec -it containername sh
or
docker exec -it containerid sh
- To view docker logs
docker logs containername
or
docker logs containerid
- To view the content of Docker container
docker inspect
- Cleanup the old docker images from local repo using below command:
docker image rm image-id
Key Learnings:
Basic Git Operations: Cloning a repository and navigating directories.
Dockerfile Creation and Multi-stage Builds: Efficiently building Docker images by splitting the build process into multiple stages.
Building Docker Images: Using
docker build
to create a Docker image from a Dockerfile.Managing Docker Images and Containers: Viewing, tagging, pushing, pulling, running, accessing, and cleaning up Docker images and containers.
Docker Hub: Creating repositories and pushing/pulling images to/from Docker Hub.
Application Deployment with Docker: Deploying a web application using Docker and Nginx.
Thank you for reading this article. If you liked it, please follow.
Reference:
Subscribe to my newsletter
Read articles from Praful Dhawale directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Praful Dhawale
Praful Dhawale
DevOps Engineer has to investigate and resolve technical issues, provide level 2 technical support, perform root cause analysis for production errors, build tools to improve customer experience, and develop software to integrate with internal back-end systems