This PR optimizes the Docker build process to shrink the final image size from 1.29GB to 159MB.
The following optimizations were performed:
Optimized layer building
Since Docker caches the image layers after each layer completion, running rm -rf on a separate RUN layer does not decrease the size of the final image. For example, the following would still produce a 1GB docker image, because the first RUN layer's 1GB file is cached in the build layers:
RUN dd if=/dev/urandom of=file bs=1024M count=1
RUN rm -f file
All RUN layers were combined into a single layer to optimize the layer size:
Switching the base image from the default tag to the alpine tag greatly reduces the initial base size. However, since alpine is a very minimal base, it no longer includes python3, a necessary build dependency. The following RUN layer was added to add python3 into the image.
RUN apk add --update --no-cache python3 make g++ && \
rm -rf /var/cache/apk/*
This reduced the size from 1.29GB to 706MB.
Combining both alpine and optimized layer building reduced the Docker image size from 1.29GB to 450MB.
Multi-stage builds
Docker allows users to build in one base container, and then move the final artifacts to another base container. This allows us to build the node dist and node_modules in the initial Alpine container stage with build dependencies, and then move the final artifacts to a clean base image.
This reduced the size from 450MB to 159MB.
Preliminary testing on my end shows that the final optimized image still works the same as the original. However, as I do not know the fine details of this program, I would recommend testing this newly optimized image extensively before merging.
I am most wary about not including Python 3 in the final stage image, as I am unsure if it's a true build dependency or some component in the code requires Python 3 at runtime. This however, is an easy enough addition to the Dockerfile if necessary.
Python is not used anywhere in the app, I'm pretty sure it's just used during npm install for some dependencies. I've tested it and it seems to be working without any issue.
This PR optimizes the Docker build process to shrink the final image size from 1.29GB to 159MB.
The following optimizations were performed:
Optimized layer building
Since Docker caches the image layers after each layer completion, running
rm -rf
on a separateRUN
layer does not decrease the size of the final image. For example, the following would still produce a 1GB docker image, because the firstRUN
layer's 1GB file is cached in the build layers:All
RUN
layers were combined into a single layer to optimize the layer size:This decreased the size from 1.29GB to 1.03GB.
Using alpine
Switching the base image from the default tag to the
alpine
tag greatly reduces the initial base size. However, sincealpine
is a very minimal base, it no longer includespython3
, a necessary build dependency. The followingRUN
layer was added to addpython3
into the image.This reduced the size from 1.29GB to 706MB.
Combining both alpine and optimized layer building reduced the Docker image size from 1.29GB to 450MB.
Multi-stage builds
Docker allows users to build in one base container, and then move the final artifacts to another base container. This allows us to build the node
dist
andnode_modules
in the initial Alpine container stage with build dependencies, and then move the final artifacts to a clean base image.This reduced the size from 450MB to 159MB.
Preliminary testing on my end shows that the final optimized image still works the same as the original. However, as I do not know the fine details of this program, I would recommend testing this newly optimized image extensively before merging.
I am most wary about not including Python 3 in the final stage image, as I am unsure if it's a true build dependency or some component in the code requires Python 3 at runtime. This however, is an easy enough addition to the Dockerfile if necessary.