Writing a Dockerfile its fundamentals and optimizing it.
There are certain concepts of writing a dockerfile to make it secure , in this blog i will be showcasing how to write a docker file what things you should consider and how you could write a dockerfile more secured
Lets get started -
I am currently writing a dockerfile for my nodejs application
FROM ubuntu:22.04
RUN apt update
RUN apt install nodejs npm -y
COPY . .
RUN npm install
EXPOSE 3000
CMD ["npm","run","dev"]
Lets go through the Dockerfile above -
FROM <image-name>:<image:tag> - using base image as ubuntu
RUN - This used to install the required packages and dependencies
COPY <source> <destination> - to copy the source code from host to image
EXPOSE - Description of where the application is listening on
CMD - This defines the commands to run when to run a container using this image
if i run this Dockerfile lets see the output and how we can optimize the dockerfile -
Lets run the image on container with port 3000 and see the output
docker build . -d -p 3000:3000 my-nodejs-app
Lets see the image size -
The image size is significantly large and we can reduce it if we optimize the dockerfile and create a new image with required dependency
Optimization of Docker image -
- From our previous dockerfile we run multiple RUN commands to update packages and install packages,Each RUN command creates a new layer which increases the image size we can eliminate this by combine it-
RUN apt update && apt install nodejs npm -y
There could be a significant improvement to the size of the docker image if i used the only the required dependencies to run the application.So, instead of using ubuntu as image we can use node docker image which is bundled with npm package manager which is needed to run the application.(we are using node:22.6.0-alpine as it is one of the lightweight image)
we copy package.json and package-lock.json file first instead of whole source code.
RUN npm install to run the dependencies and then we copy the source code -
FROM node:22.6.0-alpine
COPY package*.json .
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm","run","dev"]
Lets create the new updated dockerimage -
As you can see the significant difference in the size of the image
Lets make the Dockerfile for production environment-
We specify work directory by using WORKDIR this makes it more organised where the application source code is used instead of root directory
You need to put Environmental variable in some application and for that ENV is used here in the following Dockerfile i have used ENV to set NODE_ENV to production
Instead of running as root user we can specify a user and for this image there is node user we have specified it in the dockerfile
we created node user so we also need to give user ownership to the directory so it could read the application source code we can achieve this with
--chown=node:node
FROM node:22.6.0-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json .
RUN npm install
USER node
COPY --chown=node:node . .
EXPOSE 3000
CMD ["node","index.js"]
The difference between the images -
you can also write .dockerignore file where you can specify which dir/files you don't want to copy while creating the image further reducing the size of the image
That's it for this Blog.
Thanks for reading
GIthub repo - https://github.com/iamabhijeet20/my-docker-knowledge
Subscribe to my newsletter
Read articles from Abhijeet directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Abhijeet
Abhijeet
I am Abhijeet, a Computer Science Master's Degree holder. with an A+ grade, specializing in AWS, Azure, Docker, Kubernetes, Terraform, and DevOps tools.