Reducing nodejs Docker images size by %50 using multi-stage builds and Zeit pkg.

Written by marcosnils | Published 2017/05/02
Tech Story Tags: docker | devops

TLDRvia the TL;DR App

Update: You might want to try the interactive tutorial I wrote for this blogpost: http://training.play-with-docker.com/node-zeit-pkg/

A week ago Zeit announced a new project called pkg (https://github.com/zeit/pkg) which allows to bundle nodejs applications and all it’s dependencies (even the node runtime) in a single dynamically linked binary that can be easily shipped to different environments. This is very useful because it makes packaging, deploying and running your app extremely simple by handling just one binary instead of dealing with different dependencies and node runtimes.

If you’re currently using nodejs + docker in your project, it’s most likely that you’re relying on any of different official nodejs (https://hub.docker.com/_/node/) images. As you may already know, these images are not usually lightweight as they need the node runtime and also include other tools like npm which results in 200+MB images starting from the slim alternatives.

At the same time, Docker announced a new feature called multi-stage builds (https://blog.docker.com/2017/04/dockercon-2017-day-1-highlights/) which helps to build docker images that usually have a different build and prod context.

multi-stage build feature is only available in latest Docker 17.05-rc’s for the moment. Make sure to have a proper Docker version before trying the examples below or you’ll get some errors.

I’ll show you now, how combining both these features you can build and ship extremely small and optimized nodejs docker images.

First, we’ll create a small nodejs project, let’s start with a simple index.js and package.json

index.js:

console.log('Hello, pkg!');

package.json:

{"name": "pkg-sample","bin": "index.js"}

We’ll create our Dockerfile that uses pkg and multi-stage builds now:

Dockerfile:

FROM node:boron

RUN npm install -g pkg pkg-fetch

ENV NODE node6ENV PLATFORM linuxENV ARCH x64

RUN /usr/local/bin/pkg-fetch ${NODE} ${PLATFORM} ${ARCH}

COPY . /app

WORKDIR /app

RUN /usr/local/bin/pkg --targets ${NODE}-${PLATFORM}-${ARCH} index.js

FROM debian:jessie-slim

COPY --from=0 /app/index /

CMD ["/index"]

In this particular case as you can see in the Dockerfile, we’re targeting a node6, linux and x86_64 runtime. You have several options you can combine depending on the runtime you need, for example you can just the standard alpine platform instead of linux if you wish. Refer to the pkg documentation for more details.

Now, you can build your app image as before with docker build -t myapp . . Once your image is built you’ll notice it’s size will be only a couple of megs and you’ll be able to run it just like any other docker container with docker run myapp

Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising & sponsorship opportunities.

To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.

If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!


Published by HackerNoon on 2017/05/02