Building Node Docker images for Raspberry Pi Zero
Tags: docker, rpizero, node, armv6
Published: 2018-12-03 21:49:59

---
title: Building Node Docker images for  Raspberry Pi Zero
published: true
tags: docker,rpizero,nodejs,armv6
canonical_url: https://jonnev.se/building-node-images-for-docker-on-raspberry-pi-zero/
---

While developing a web app for my [Raspberry Pi Zero SMS gateway](https://dev.to/joenas/raspberry-pi-zero-as-sms-gateway-4ihl-temp-slug-4032545) I ran into trouble. I wanted to be able to run the app in Docker but building an image from a Dockerfile on the RPi0 was incredibly slow and I didn't manage to complete it because my Pi ran out of memory.

I thought about creating the image locally and pushing it to Docker Hub but it felt a bit overkill for small, personal apps. After some thinking and googling I realised that you can [save](https://docs.docker.com/engine/reference/commandline/save/) docker images and then [load](https://docs.docker.com/engine/reference/commandline/load/) them on another computer.

There are 2 ways to go about this:

1. Install `npm` on your computer, fetch all dependencies (`node_modules`) and copy them together with the code into the `armv6` image.
2. Run `npm` in a container with a [multistage build](https://docs.docker.com/develop/develop-images/multistage-build/) and then copy the files to image.

### With local NPM

This is more useful and faster with an app you're developing yourself, since you probably have `npm` installed.

Fetch the deps as usual with `npm install` then add a `Dockerfile` (and possibly a `.dockerignore`).

```
# Check for your version: https://hub.docker.com/r/arm32v6/node/tags/
FROM arm32v6/node:8.14.0-alpine
RUN mkdir /app
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH

# Either be specific with what to add, docker caches every step
ADD package.json /app/package.json
ADD package-lock.json /app/package-lock.json
ADD node_modules /app/node_modules
ADD app.js /app/app.js

# Or add the whole dir, I always use a .dockerignore file when doing that
ADD . /app

ENV PORT=5000
EXPOSE 5000
CMD ["npm", "start"]

```

### Multistage build

This is useful when you want to make an image of someone elses project and/or don't want to install `npm` on your machine.

Since you can't run the `arm32v6/node` on your computer, you need to first use a working node image to fetch/build your project.

```
# Fetch node_modules for backend, nothing here except 
# the node_modules dir ends up in the final image
FROM node:8.14.0-alpine as builder
RUN mkdir /app
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json /app/package.json
RUN npm install

# Add the files to arm image
FROM arm32v6/node:8.14.0-alpine
RUN mkdir /app
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH

# Same as earlier, be specific or copy everything
ADD package.json /app/package.json
ADD package-lock.json /app/package-lock.json
ADD . /app

COPY --from=builder /app/node_modules /app/node_modules

ENV PORT=5000
EXPOSE 5000
CMD ["npm", "start"]

```

### Building

Then you can build and save your image...

```
docker build -t my-app -f Dockerfile .
docker save -o my-app.tar my-app
ls
# my-app.tar

```

... transfer it to your RPi (with `scp` or whatever) and load it!

```
# On RPi
docker load -i my-app.tar
docker run --rm -p 5000:5000 my-app

```

## Automation

Doing this can get tedious if you make a lot of changes to your app, so I created a simple bash script that you can use: [https://github.com/joenas/node-docker-raspberry-zero](https://github.com/joenas/node-docker-raspberry-zero)

**Note** : In my repo I've named the file `Dockerfile.armv6` because I already have a `Dockerfile` for running the app on other architectures that doesn't require a specific docker image. I also tag the image with the suffix `:armv6`. The commands above would then be like this:

```
# Build & save
docker build -t my-app:armv6 -f Dockerfile.armv6 .
docker save -o my-app.tar my-app:armv6

# Load & run
docker load -i my-app.tar
docker run --rm -p 5000:5000 my-app:armv6

```

### Sample .dockerignore

Here's a sample `.dockerignore` file you can use to not include all the files in your image.

```
/.git/
.gitignore

docker-compose.yml
Dockerfile*
LICENSE
README.md
*.tar

```

## Sharing is caring

I hope you have any use for this and I'd love to see more stuff for the RPi0/1 so please comment below if you create something! 🙏