Saturday, June 10, 2017

Stuffing Angular into a Tiny Docker Container (< 2 MB)

I’ve been doing a lot of work with Angular and Docker lately. In one of my workshops I demonstrate how to take an Angular app and related services then package them as containers and leverage Docker Compose to spin them up with a single command. You can read about a more involved example at Build and Deploy a MongoDB Angular NodeJS App using nginx in Three Steps with Docker.

Using the nginx container, my Angular images average several hundred megabytes in size (click to view full size).

bigimages

Microservices have transformed the way modern apps are architected. For example, Angular can produce a highly optimized production distribution of its assets as static files. The website for Angular can be incredibly simple because it relies on separate services and APIs to do the heavy lifting, and any browser-based logic is encapsulated in the JavaScript libraries that are included.

Therefore, standing up the front end should be a lot easier! In fact, even with a minimal web server, containers are easy to spin up and scale out, so load doesn’t necessarily have to be a concern of the web server now when it can be managed by the orchestrator. As an experiment, I set out to see how small I can make an Angular app.

If you have Docker installed, you can run the tiny Angular app yourself. Instructions are available at this link.

In searching for a solution I came across BusyBox, a set of Unix commands in an extremely small container that is around a megabyte in size. BusyBox contains httpd, an HTTP daemon. Let’s see how small we can make our Angular app!

The app we’ll target is the simple Angular app I built for Music City Code. You can clone the repo from GitHub here. When you build the app, it creates a simple interactive fractal app using a bifurcation diagram.

Let’s build an optimized distribution of our Angular app. This generates about 400kb of assets.

ngbuild

Next, create a Dockerfile with these contents:

from busybox:latest
run mkdir /www
copy /dist /www
expose 80
cmd ["httpd", "-f", "-p", "80", "-h", "/www"]

The steps are straightforward. It pulls down the latest busybox image, creates a directory, copies the Angular assets into the directory, exposes the web port and instructs the container to run the httpd daemon on startup.

Add a .dockerignore and ignore the src, e2e, and node_modules directories.

Let’s build our container:

dockerbuild

To see the image that was built, you can type:

docker images | grep "tinyng"

(Replace grep with find on Windows machines) and on my machine it is 1.57 MB.

Running it and browsing to localhost proves it is working:

docker run –d –p 80:80 jlikness/tinyng

So I push to Docker Hub, and confirm the size there:

dockerhub

The experiment is finished. Success! Of course now we have to try it under load and scale, but it’s good to know there is a path to optimize the size of your containers!