Shrink your App with Alpine Linux

Alpine Linux is the second Linux distribution that we maintain across all resin.io device types.

Small. Simple. Secure.
Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox.

Alpine Linux

We've had our eye on Alpine Linux for some time now. The "5MB" OS impressed us; size, after all, is profoundly important in the IoT context where networks are unpredictable and constrained.

Clearly we weren't the only one's impressed -- we've had countless user requests in recent months.

So we went ahead and constructed a comprehensive collection of Alpine Docker images for embedded devices all of which are available on now DockerHub.

How will Alpine Linux benefit Resin devices?

size matters

As we mentioned, Alpine Linux is extremely small, this provides several benefits for embedded applications.

By far the biggest benefit is the bandwidth and time saved. It will take less time to download, install and run your application. Using smaller images also makes a download less vulnerable to choppy networks.

Secondly it uses less disk space. This lends more leeway when storing data on constrained devices. Security and performance are also improved. You can find more info about Alpine's security policies here.

To figure out just how big the benefits are we put together a side by side comparison of our current Debian images and the new Alpine images.

Note: Debian based and Alpine Linux based images are not exactly identical in terms of installed packages since the package name and package content are different between 2 distros. We'll choose to neglect this in favour of a quick and dirty comparison.

Image Type Debian Alpine Linux
bare-bones 110.2 MB resin/armv7hf-debian:latest 3.9 MB armhf/alpine:latest
Architecture-based 114.6 MB resin/armv7hf-systemd:latest 14.4 MB resin/armhf-alpine:latest
Device-based 154.8 MB resin/raspberrypi2-debian:latest 29.9 MB resin/raspberrypi2-alpine:latest
Buildpack-deps 415.2 MB resin/raspberrypi2-buildpack-deps:latest 308.8 MB resin/raspberrypi2-alpine-buildpack-deps:latest
Node.JS 193.9 MB resin/raspberrypi2-node:slim 66.1 MB resin/raspberrypi2-alpine-node:slim
Python 257 MB resin/raspberrypi2-python:slim 177.4 MB resin/raspberrypi2-alpine-python:slim
Go 481.3 MB resin/raspberrypi2-golang:slim 345.1 MB resin/raspberrypi2-alpine-golang:slim

(All image sizes are the virtual size displayed in docker images command)

You can tell at a glance that Alpine is a clear winner in terms of size. Take a look at the node image: there is a 66% reduction in size. Some quick maths indicates that on average you'll save 111.62mb by choosing a resin Alpine image over one of their Debian counterparts.

That's that's over 10 seconds you'll save on a 10mb/s network. This may not sound like much but it's an order of magnitude better when downloads are streamed over something slower, like GPRS.

Under the hood

The resin Alpine Linux base images are built on top of official Alpine base images.

In order to smooth the transition from our Debian base images to Alpine Linux, resin Alpine Linux base images follow the same structure (base images tree) as Debian images.

The root is a bare-bones Alpine Linux image for a specific architecture. From there we add device specific stuff (firmware, etc.) to build up the Alpine Linux image for each device. Finally, we have language specific base images built on top device image with preinstalled libs and tools. Basically, we still have buildpack-deps, Python, NodeJS and Golang Alpine base images, each with their own variants.

The OpenRC init system

Alpine Linux uses OpenRC for its init system. We have followed suit and added it as the init system in our Alpine Linux base images over systemd. This change allows the containers to seem more like fully fledged Linux environments.

Currently, OpenRC doesn't start by default. It can be triggered by an environment variable - INITSYSTEM like what we do with systemd in Debian base images. For example:

FROM resin/raspberrypi2-alpine-python:latest  
# Enable OpenRC
ENV INITSYSTEM on  
# Your code goes here

Alternatively, you can set INITSYSTEM in your dashboard and toggle it on and off from there.

By setting INITSYSTEM on, the system will wrap user instructions in a shell script and launch it as an OpenRC service (named resin). That service will be added to default runlevel. Core services like dbus are added by default to runlevel and will start automatically with the resin service. Resin init script can be found in /etc/init.d/.

Now you can enjoy the beauties of OpenRC in your container. But more than that, OpenRC will keep your container alive after your code has crashed or finished running. This is really great for exploring and debugging your container during development as it allows you to ssh in or use the web-terminal and run simple commands in the container or inspect system logs from your crashed process.

Give it a try

The naming scheme for the new images is simple -- just append alpine to the current name. For example: resin/raspberrypi2-alpine, resin/raspberrypi2-alpine-buildpack-deps, resin/raspberrypi2-alpine-node and so on.

They are available on Dockerhub so you can use our images in any Docker-based project. If you encounter anything unexpected or you just want a bit of clarification, please reach out to us on our community chat.

comments powered by Disqus
Terms of Service | Privacy Statement | Master agreement | Copyright 2019 Balena | All Rights Reserved