How to run farmerbot on a Raspberry Pi

Inquiring minds want to know: can you run the ThreeFold famerbot on a Raspberry Pi? The answer is, yes, you can, with a few tweaks from the normal instructions. This method should work with Pi 2, 3, and 4, although I’ve only tested on my Pi 4 so far. Supporting Pi 1 and Zero would be just a bit of extra work, as far as I can see, so drop me a line if you have interest in using one of those models and I’ll see about making it happen.

The tricky part about working with the Pi is that the binary executables we release for Intel and AMD x64 based systems aren’t natively compatible with the ARM based processor in the Pi. To overcome this, we’ll use a combination of recompiled binaries and using an emulator to run the existing binaries, to provide a suitable mix of running services that support a working farmerbot.

For now, I am providing a set of ARM compatible containers hosted in my personal Docker Hub repository. I’ll be working with the dev team to incorporate this into our normal build cycle and our official repositories. If you’d like to see the Docker files that generated these images in the meantime, just let me know.

Prerequisites

To follow this tutorial, you’ll need the following:

  • ARM based computer, with at least ARMv7 or higher chip (Pi 2 and later)
  • 512mb total RAM (~200mb of free RAM is required to run Docker and farmerbot)
  • 1-2gb free storage space
  • Debian based operating system like Raspbian/RPi OS or Ubuntu (I tested on 32 bit “Buster” and 64 bit “Bullseye”)

You can use a different OS if you want to, but the needed packages might have different names and there could be some other quirks to account for. We don’t need a desktop, so the using a “lite” or “server” OS image is okay.

Update: There are now two paths to choose from below, the first is the original option, which works on any of the devices and operating systems mentioned above. If you’re not sure, this is the way to go.

The second option is for 64 bit Pis (3 and 4) running a 64 bit operating system. Note that the default Raspberry Pi OS images are 32 bit. You can check by running uname -m in a terminal. The output on a 64 bit OS will be aarch64. In that case, you can skip to the 64 bit section below for a bit simpler setup.

Let’s go

I won’t cover the farmerbot setup in detail here. Check the link at the top of the post for written instructions or see my video. The changes necessary to run on a Pi include installing a couple extra packages and making a few changes in the docker-compose.yaml file. You can follow the normal instructions and come back here to complete the rest just before you run docker compose up.

Install Docker

While the version of Docker included in the repositories might work, I like to get the latest version using Docker’s install script:

wget -O docker.sh get.docker.com
sudo sh docker.sh

32 Bit OS

The following instructions are especially for 32 bit operating systems, but they will work on a 64 bit OS too. If you do have a 64 bit OS running on your Pi, you can skip to the 64 bit instructions below.

Install QEMU

We’re also going to install QEMU for emulation support inside Docker. This is needed because one component that makes farmerbot work, rmb-peer, won’t compile natively for 32 bit ARM systems:

sudo apt update
sudo apt install qemu-user-static

While this was not necessary in my own testing, one user reported needing to install binfmt-support manually as well. You can check if it’s working properly with:

ls /proc/sys/fs/binfmt_misc/

There should be many entries starting with qemu-. If not, try this:

sudo apt install binfmt-support

Tweaking image paths

Next, we’ll replace a couple of the container images with the versions I built for ARM. Inside the docker-compose.yaml file, there are four services. Here’s the breakdown on what happens with each:

  • farmerbot - replace with native ARM container
  • rmb-peer - specify that the image is for the amd64 platform. Docker will emulate with QEMU even if we don’t do this, but doing so will suppress a warning message
  • grid3_client - replace with native ARM container
  • redis - do nothing, native container already available under same tag

For farmerbot and grid3_client, the name and tag for the image will be the same, we’ll just replace the path to point to my personal Docker Hub repository where I’ve uploaded the ARM compatible images.

Here’s the full docker-compose.yaml with the changed image lines and the added platform tag:

services:
  farmerbot:
    image: scottyeager/farmerbot:0.1.0
    restart: always
    depends_on:
      redis:
        condition: service_healthy
      rmbpeer:
        condition: service_started
      grid3_client:
        condition: service_healthy
    volumes:
      - ./config:/farmerbot
    command: -c /farmerbot/ --grid3 "http://grid3_client:3000" --redis "redis:6379" --debug --output /farmerbot/farmerbot.log

  rmbpeer:
    image: ghcr.io/threefoldtech/rmb-peer:v1.0.4
    platform: amd64
    restart: always
    depends_on:
      redis:
        condition: service_healthy
    entrypoint: /bin/sh -c
    command: ["/usr/sbin/rmb-peer --redis redis://redis:6379 --mnemonics \"$SECRET\" --relay \"$RELAY\" --substrate \"$SUBSTRATE\" -d"]

  grid3_client:
    image: scottyeager/grid_http_server:2.0.0-rc8
    restart: always
    depends_on:
      redis:
        condition: service_healthy
    entrypoint: /bin/sh -c
    command: ["echo \"{\\\"network\\\":\\\"$NETWORK\\\",\\\"mnemonic\\\":\\\"$SECRET\\\",\\\"rmb_proxy\\\":false,\\\"storeSecret\\\":\\\"secret\\\",\\\"keypairType\\\":\\\"sr25519\\\"}\" > ~/config.json && yarn grid_http_server -c ~/config.json" ]
    ports:
      - '3000'
    healthcheck:
      test: ["CMD-SHELL", "curl --fail -X POST -H \"Content-Type: application/json\" http://127.0.0.1:3000/ping || exit 1"]
      interval: 10s
      timeout: 3s
      retries: 30

  redis:
    image: redis:7.0.8-alpine
    restart: always
    ports:
      - '6379'
    command: --save 20 1
    volumes: 
      - db:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 1s
      timeout: 3s
      retries: 30

volumes:
  db:
    driver: local

64 Bit OS

On a 64 bit OS, all that’s needed is to replace the container paths with the paths to my ARM container builds. Here’s the complete docker-compose.yaml:

services:
  farmerbot:
    image: scottyeager/farmerbot:0.1.0
    restart: always
    depends_on:
      redis:
        condition: service_healthy
      rmbpeer:
        condition: service_started
      grid3_client:
        condition: service_healthy
    volumes:
      - ./config:/farmerbot
    command: -c /farmerbot/ --grid3 "http://grid3_client:3000" --redis "redis:6379" --debug --output /farmerbot/farmerbot.log

  rmbpeer:
    image: scottyeager/rmb-peer:1.0.4
    restart: always
    depends_on:
      redis:
        condition: service_healthy
    entrypoint: /bin/sh -c
    command: ["/usr/sbin/rmb-peer --redis redis://redis:6379 --mnemonics \"$SECRET\" --relay \"$RELAY\" --substrate \"$SUBSTRATE\" -d"]

  grid3_client:
    image: scottyeager/grid_http_server:2.0.0-rc8
    restart: always
    depends_on:
      redis:
        condition: service_healthy
    entrypoint: /bin/sh -c
    command: ["echo \"{\\\"network\\\":\\\"$NETWORK\\\",\\\"mnemonic\\\":\\\"$SECRET\\\",\\\"rmb_proxy\\\":false,\\\"storeSecret\\\":\\\"secret\\\",\\\"keypairType\\\":\\\"sr25519\\\"}\" > ~/config.json && yarn grid_http_server -c ~/config.json" ]
    ports:
      - '3000'
    healthcheck:
      test: ["CMD-SHELL", "curl --fail -X POST -H \"Content-Type: application/json\" http://127.0.0.1:3000/ping || exit 1"]
      interval: 10s
      timeout: 3s
      retries: 30

  redis:
    image: redis:7.0.8-alpine
    restart: always
    ports:
      - '6379'
    command: --save 20 1
    volumes: 
      - db:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 1s
      timeout: 3s
      retries: 30

volumes:
  db:
    driver: local

Run it

Alright that’s it. Now we can run docker compose up and Docker will take care of the rest.

Wrapping up

While I did my best not to pack this post with details about the problem and process of porting software from one platform to another, there’s more to say on that for anyone who’s curious, and I’m keeping my thoughts on that as a draft for now to maybe add to this post later :slight_smile:

Please drop a reply here with any questions and your experience running farmerbot on a Rpi or other ARM based computer. It would be great to generate a collection of reports about what works and try to troubleshoot what doesn’t.

6 Likes

WE WANT THE DETAILS!

We want the details!

Thanks Scott. Nice post :slight_smile:

Amazing ! i was looking for a small NUC or so, but with this new i will just use my sleeping Pi3 ! Thank you !

2 Likes

Absolutely, and glad to hear it! It’s nice to know that some farmers can dust off a Pi they have around and put it to work for this :slight_smile:

1 Like

Today I’ve released the ARM builds for farmerbot v0.1.0. Check the original post for the updated docker-compose.yaml file. Don’t forget to change MNEMONIC to SECRET in your .env file!

While I did some basic sanity checks that the new versions run, I didn’t do any extensive testing. I’d recommend keeping a backup in case you need to roll back.

1 Like

! rmbpeer The requested image’s platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested.

Tried adding platform: armhf in the redis section, but that didn’t work either.

Any ideas?

Scott now has a native 64bit image for use with arm, just replace the image listed under rmbpeer section of docker-compose.yaml with scottyeager/rmb-peer:1.0.3

Thanks @TheCaptain. I’ll update the guide to include this.

It seems to be a common confusion that does not match the detected host platform is actually not an error. This is just how Docker is telling you that it will use QEMU to emulate the container (assuming QEMU is available). I’ll add a note on this too.

@sharpharp, did you get it working?

Nope - didn’t fix the issue. I edited rmb-peer as per TheCaptions comments. i then do compose up -d and it says created started. but nodes still not shutting down unfortunately