Let's build a small node.js single page application (SPA) using the multi stage builds feature from docker to optimize the image size
With multi stage builds (a feature announced in the docker con last week) we can create a tiny image that get's pulled and pushed faster to the docker repository.
A Single Page Applications (SPA's) is a convenient use case to test the power of multi stage build easily in the node.js world.
Let's start with this.
Easy, go to https://www.docker.com/community-edition#/download Choose your platform AND, because we need multi stage builds and its still on the edge channel we need to choose that instead of the stable channel. Download, install.
A single page application is just a static web page that can be served through any traditional web server.
For this example, let's pick a boilerplate SPA like create-react-app.
npm install -g create-react-app create-react-app my-app cd my-app/ npm start # if you want to test it and check the browser for it
All right now the important thing, let's take a look at a candidate Dockerfile
# buildtime FROM node AS nodebase LABEL maintainer "firstname.lastname@example.org" ADD . /usr/src/app WORKDIR /usr/src/app RUN npm i && npm run build # runtime FROM nginx:alpine COPY --from=nodebase /usr/src/app/build /usr/share/nginx/html
So let's see.
We start with a node:latest image, no problem with the image size because now we have multi stage builds.
The LABEL maintainer, that's recent too, no more MAINTAINER special instruction, now it's a label.
We add the current directory to the appropiate location and set the working directory to it.
Install, build... and that's all that we need to generate our artifacts in our build folder.
So after that, we take for the runtime the small nginx:alpine image and we just copy the build folder to the right place.
So now, let's build the image
docker build -t my-app .
And now let's look it's size
All right! less than 16 MB! With the whole thing, linux, nginx and our app!
That's great. Just the node_modules folder size after installation is around 130 MB... so this is a BIG win.
Let's try it
docker run -d --rm -p 8000:80 --name my-app my-app
Open chrome in localhost:8000 and enjoy.
Multi stage builds are great, it let's you easily build whatever you want and then create a thin self-sufficient pack with exactly what you need to let the user run your application.
By making this clear distinction between different stages, docker let's you think in a more organized way about the Dockerfile.
With multi stage builds the LAST stage is the one that is used on your final image. Don't forget that. For example, the ONBUILD instruction on a previous stage wont have any effect because it will be overwritten with the last stage of the Dockerfile.
As a side note, it is important to say that this may be a trigger to massively use webpack or some kind of bundler for standalone node.js applications. The node_modules folder get's really big very quickly.