- Published on
Dieting NodeJS Docker Containers
- Authors
- Name
- Yair Mark
- @yairmark
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.
For example node:10.17.0
becomes node:10.17.0-alpine
.
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"]
This will:
- install the build tools you need.
yarn
ornpm install
.- 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.