- Yair Mark
An environment I am working in is locked down. As a result, I use a docker container that is pre-bundled with everything I need to get deployments in that environment done. This particular container uses NodeJS internally to do its thing.
Unfortunately getting this container to the environment involves saving it locally:
# build the container locally docker build -t anOrg/my-container:0.1 -f ./path/to/Dockerfile # saving the built container to a folder called build (this is saved as a tar file) mkdir -p build docker save -o build/my-container-0.1 anOrg/my-container:0.1
This saves the built container as a tar file. But being a NodeJS app this weights in (in my case) at 1.5GB. This is a problem as I have to copy this container to the target server every time I need to make a change.
As a result of this, I started looking at ways to cut this image size down. The best approaches to take are from the top to the bottom.
Cut Down Your node_modules Folders
Source: Reddit - ProgrammerHumour
Anyone who has worked with Node will have a good chuckle on seeing this meme. When working with Node apps, the
node_modules folder is generally the heaviest piece in your app's directory.
There are a few ways to lighten this:
- Remove unneeded dependencies.
- Move dependencies to dev dependencies
- These are the dependencies that are only used in tests and during builds
Once you have done these two steps you can tell npm/yarn do build excluding dev dependencies:
# in yarn yarn --prod # npm npm run build --prod
Switch to the Node Alpine Container
This is seemingly easy, simply append
-alpine to the end of one of the official node images you are using.
The problem is this alpine container does not have the build tools you need to build the node image. You will need to use a dockerfile similar to the below:
FROM node:10.17.0-alpine WORKDIR /root/build COPY . . RUN apk --no-cache add yarn python make g++ RUN yarn --prod && yarn run build RUN apk --no-cache del yarn python make g++ ENTRYPOINT ["yarn","start"]
- install the build tools you need.
- run any build scripts you need.
Use Multistage Builds
In my case, the run script behaved strangely when using multi-stage builds. But this should work in general for other apps. The above dockerfile will change as follows:
FROM node:10.17.0-alpine as builder WORKDIR /root/build COPY . . RUN apk --no-cache add yarn python make g++ RUN yarn --prod && yarn run build FROM node:10.17.0-alpine as runner WORKDIR /home/root COPY /root/build /home/root/ ENTRYPOINT ["yarn", "start"]
This final step gives you an even lighter run container that only has the bare minimum needed to run NodeJS applications.