funmaker / Hybooru

Hydrus-based booru-styled imageboard in React
https://booru.funmaker.moe/
MIT License
100 stars 17 forks source link

Optimize Docker image size #5

Closed geraldwuhoo closed 3 years ago

geraldwuhoo commented 3 years ago

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:

RUN npm install && \
    npm run build:prod && \
    mv dist /app && \
    npm prune --production && \
    mv node_modules /app && \
    rm -rf /build

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, 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.

funmaker commented 3 years ago

Hi @98WuG, thank you for the PR.

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.