While developing a web app for my Raspberry Pi Zero SMS gateway 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 docker images and then load them on another computer.
There are 2 ways to go about this:
npmon your computer, fetch all dependencies (
node_modules) and copy them together with the code into the
npmin a container with a 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
Fetch the deps as usual with
npm install then add a
Dockerfile (and possibly a
# 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" ]
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" ]
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
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
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
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! 🙏