Navidrome: Prebuilt Raspberry Pi Docker images

Created on 13 Mar 2020  Â·  34Comments  Â·  Source: deluan/navidrome

I know this is already on the roadmap, but I wanted a way to vote for it, so I created this issue :)

As far as I'm concerned, either a binary or a Docker image that works on Raspberry Pi (Raspbian Buster) would be great!

All 34 comments

I did some research a while ago on how to build it for the Pi, I was planning to buy one to test it out, but if you can help testing it, I can try to work on this this week. Can you help with that?

Sure! I just got a PI 4, so I can test with that.

I tried to build it from source on the PI, but ran into what looked like a missing dependency on go-bindata:

go-bindata -fs -prefix "ui/build" -tags embed -nocompress -pkg assets -o assets/embedded_gen.go ui/build/...
/bin/sh: 1: go-bindata: not found

I haven't built anything with Go before, so I'm not familiar with the ecosystem. Is this a dependency that needs to be specified in the project somewhere?

You need to install go-bindata on your Pi system: go get -u github.com/go-bindata/go-bindata/...

Did you run the steps described in the "Build from source" section of the README? This is one of the tools installed my make setup

I was able to cross-compile Navidrome to ARM. I generated ARMv6, ARMv7 and ARM64 binaries, all should work on the Pi 4. Can you try on your system?

navidrome_v0.9.2-next_Linux_armv6.tar.gz
navidrome_v0.9.2-next_Linux_armv7.tar.gz
navidrome_v0.9.2-next_Linux_arm64.tar.gz

Let me know if they work

PS: Don't forget you still need ffmpeg on your Pi. If Raspbian does not include it, you can download from: https://johnvansickle.com/ffmpeg/

I would recommend to use docker buildx to build cross-platform images. I tried this out with github actions, works nice. I used it in my project (Golang), see this workflow as reference, may be you can go the same way

Thanks @0xERR0R , I'll surely take a look. Right now I'm using bepsays/ci-goreleaser, it has the cross-compile toolset for various platforms, but misses Arm and Linux 32bits. I was able to add the dependencies for Arm, but having a hard time with Linux 32-bits.

I think goreleaser can only build binaries, not docker images? But maybe I'm wrong.

It can, but I'm only using it to build the binaries. I use Docker Hub's automated builds to build the docker image, but I'll take a look at your solution, never used buildx before

@deluan The armv7 binary works great! Thanks for working on it.

Thanks for testing this out. I'll add the ARM binaries as part of the automated release. I'll keep this issue open to track the work on the cross-platform docker images

I can also confirm that the armv7 image is working flawlessly ♥

Please include armv8 64 bit images as well. Thanks.

I tried to build the docker image for raspberry pi3 (arm7) and had following problems:

  • Image node:13.12-alpine, which is used in Dockerfile does not exist for arm6 and arm7. I changed it to node:13-alpine3.10 -> works fine and has support for all architectures
  • ffmpeg version is hardcoded to amd64. Is there a reason to download a build from author's page and not to install it from alpine's package repository? 4.2.2 ist the version on https://johnvansickle.com/ffmpeg/, 4.2.2-r2 in alpine (https://pkgs.alpinelinux.org/package/edge/community/x86/ffmpeg)
  • tini version is hardcoded to amd64. You are using single go binary as executable, I don't think you need tini als init process. If you need it, maybe it would be better to use docker init process (https://docs.docker.com/engine/reference/run/#specify-an-init-process) and reduce dependency to tini

Hey @0xERR0R , thanks for taking a look at this. Here's the answers:

  • Node: I rather use strict versions to avoid mysterious errors popping up here and there due to version differences. That being said, the Node project takes semantic versioning very serious, so I think this is fine
  • ffmpeg: I downloaded it as a static binary, to avoid polluting the final image with apk leftovers and dynamic libraries. If we can install ffmpeg in the gobuilder image using apk, then copy just the binary into the release image, then great! If not, I think it is worth to code some logic to download the correct static binary from johnvansickle's site
  • tini: I added it when troubleshooting some zombie ffmpeg processes, don't think it is required anymore. We can remove it, and I'll keep an eye at my instance

Let me know if you encounter any more issues

I could successfully build multi-arch docker image for

  • linux/386
  • linux/amd64
  • linux/arm/v6
  • linux/arm/v7
  • linux/arm64

with this GitHub Workflow. I tested the arm/v7 image on my pi3 and it works fine. The corresponding docker image is here.

I changed the Dockerfile as described (replaced ffmpeg with apk version, removed tini and changed the image).

Awesome! I'll take a look tonight. Wanna prepare a PR?

PR is not a problem, but 2 points are still open: node version in image and ffmpeg. I saw that apk version installs a bunch of dependencies (libs) like lame etc. I don't know if all of them are necessary. I understand your point of view with "not polluting the image". But otherwise the apk version is optimized for alpine...

Same for node: Always using the same version is fine, but sometimes the fixed version will be removed from docker hub. Maybe it would be better to use always the last npm version?

Another point is the integration in your release job (setting of properly version tag in docker, ...)

I would like to help, but I do not have the big picture of your release in my head.

For Node, if you use 13-alpine3.10 as above, it will always use the latest Node 13 (right now it is 13.13-alpine3.10), so it is fine.

For the other points, I'll check later. Thanks!

Hey @0xERR0R I'm working on some pipeline improvements, and also playing with your modifications: https://github.com/deluan/navidrome-test/pull/1

I got the multiplatform docker image building working with builderx, but it is too slow and it is flaky, failing sometimes. Seems that the node build is super slow on ARM platforms.

Any ideas on how to optimize it? Maybe build the JS bundles before the docker build, as the bundles should be the same for all platforms? Thoughts?

Yes, the build takes > 1h. The docker image will be built several times (one per architecture) and node build is really heavy. Since the web client artifact is not platform dependent, it could be possible to build it once and include into target docker image, which build platform dependent go binary. But this would introduce new step into the build pipeline for docker image. The current implementation is really simple: git checkout and docker build. No need to install any build tools, docker image does install everything and builds everything from scratch.
Maybe you should create a docker image only for web client (will be build once for amd64) and use it as build image for go (per architecture)? I will try it today evening

I tried to analyze the build log, you're right:

#28 [linux/arm64 jsbuilder 6/6] RUN npm run build
...
#28 1912. Compiled successfully.
...
#28 DONE 1912.4s


#53 [linux/amd64 jsbuilder 6/6] RUN npm run build
...
#53 253.6 Compiled successfully.
...
#53 DONE 256.1s

npm build ist very slow on arm. You are already building node stuff in "binaries", step "Build UI". Would it be possible to reuse this in later docker image buld step?

That was my idea. The only downside of this is that we would use a specific Dockerfile for this, that would be used only for the pipeline. But maybe it is not a big deal, considering the optimization it will bring. I'll try this later

I tried following:

  • reduced platforms count to 3
  • removed "go test" step from Docker image (this should be already checked by ci job)
  • extracted web ui build step to stand alone Docker image (see here

Build runs now in 19 min (instead of 1h 5m)

That's great! Thanks for this. A couple considerations:

  1. I think we should use a pair of separated Dockerfiles for the pipeline, and not change the current one. I'd like to allow devs to build their own image locally, which would be the purpose of the main Dockerfile.
  2. I think we should only remove the go test if we combine the build pipeline with the `release, to be sure the change that triggered the release is always tested.
  3. I don't think we need a webui image. We can just pass it from the binaries job to the docker job using "artifacts", like I do in my test build pipeline
  1. agreed, it would be better to have a single docker file, which build everything, even if the build time is about 45 min.
  2. This with an extra image is a quick and dirty hack, if you have a better solution, this is great!

Hey @0xERR0R, using the binaries generated by goreleaser, I was able to bring down the total time to 13 mins. I need to test the Docker images on a Raspberry Pi, would you be able to test it?
The image tag is deluan/deluan:0.0.11

I also reworked the workflows, combined them into one. Let me know what you think. The commit in question is this: https://github.com/deluan/navidrome-test/commit/ebae298d1e19ce8d0ee790ddcc3e9c15e65c303d

A you sure, that the image name is deluan/deluan:0.0.11? I can't find it on docker hub...

Ops... the Docker repository was private. You can try again now :)

Works like a charm!

Nice! Will merge the changes tonight! Thanks for all the help on this issue!

@GitSchorsch Could you test it too please? ;)

@0xERR0R of course :-) Same result here (Raspbian on Raspberry Pi 4)! No problems. Fast and responsive all the time.

Fixed in #204 , thank you all for the help

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ElleshaHackett picture ElleshaHackett  Â·  6Comments

guim31 picture guim31  Â·  8Comments

delucks picture delucks  Â·  3Comments

brianpierson2020 picture brianpierson2020  Â·  4Comments

BobWs picture BobWs  Â·  3Comments