Running OpenFaaS and MongoDB on Raspbian 64bit
Tags: openfaas, mongodb, kubernetes, arm64
Published: 2020-06-09 13:17:54

In this tutorial we’ll get a Lightweight kubernetes running on Raspberry Pi 4B/3B/3B+ as ARM64 and set up OpenFaaS with MongoDB.

#### Raspberry Pi OS (64 bit) vs Raspbian 64bit:

To avoid confusion, this article will NOT talk about [Raspberry Pi 64bit OS](https://www.raspberrypi.org/forums/viewtopic.php?f=117&t=275370) that is currently in beta. Instead, we will focus on Raspbian which is a 32bit but is capable of ALSO running 64bit applications. I assume there are plenty of people who still run Raspbian and will keep running in the foreseeable future.

We’ll use the following software:

* `raspbian-nspawn-64` package
* `k3sup` tool
* `arkade` tool
* OpenFaaS Platform
* MongoDB

And my hardware setup includes: A cluster of 10 x Raspberry Pi 4B with 4GB each.

#### Step #1: Enabling ARM64 & 64bit Userland (aka. 64bit Shell):

The default OS of Raspberry Pi (aka. Raspbian) as of now is completely 32bit, this is often abbreviated as armv7l or armhf. However, Raspberry Pi’s CPU starting from model 3B supports 64bit. In this step we will enable the 64bit kernel and setup a 64bit shell.

Thanks to the great work of [sakaki](https://github.com/sakaki-)'s this is as easy as:

`sudo apt-get update && sudo apt-get install -y raspbian-nspawn-64`

You can read more about it here:

[https://github.com/sakaki-/raspbian-nspawn-64](https://github.com/sakaki-/raspbian-nspawn-64).

Make sure you select ‘Yes’ in the dialog and reboot your Pi before proceeding to the next step.

#### Step #2: Using Docker/Containers Inside The 64bit Userland:

Since we’re use containers, we need to make some adjustments in our 64bit Userland:

In the Wiki page of the [raspbian-nspawn-64](https://github.com/sakaki-/raspbian-nspawn-64) project there’s an article with a tutorial that explains how to get there:

[https://github.com/sakaki-/raspbian-nspawn-64/wiki/Using-Docker-Inside-the-Container](https://github.com/sakaki-/raspbian-nspawn-64/wiki/Using-Docker-Inside-the-Container)

Please follow all the instructions until the ‘Installing Docker in the 64-bit Debian Buster Container’ chapter. You can go ahead and install Docker if you want, that’s optional and can be handy but it won't be used by k3s.

#### Step 3#: Installing k3s (i.e., Lightweight Kubernetes) using k3sup and OpenFaaS using arakde:

Instead of getting Kubernetes (i.e., k8s) installed on our IoT edge, we’ll use k3s. k3s is a lightweight Kubernetes distribution, which is easy to install. To automate and simplify our workflow we’ll use [k3sup](https://github.com/alexellis/k3sup) and [arkade](https://github.com/alexellis/arkade).

[Alex Ellis](https://www.alexellis.io/) who wrote those great tools also wrote an excellent tutorial on how to use ‘em to bootstrap your Kubernetes (with OpenFaaS):

[https://medium.com/@alexellisuk/walk-through-install-kubernetes-to-your-raspberry-pi-in-15-minutes-84a8492dc95a](https://medium.com/@alexellisuk/walk-through-install-kubernetes-to-your-raspberry-pi-in-15-minutes-84a8492dc95a)

To avoid confusion, in our current situation you should start from the ‘Get your CLI tools’ chapter. DO NOT flash the OS image otherwise you would lose all the progress from the previous steps.

At the end of this you should have a working k3s cluster with OpenFaaS deployed and you can verify it’s indeed ARM64 by running the following command:

`kubectl describe nodes`

Or in short:

`kubectl describe nodes | grep "Architecture"`

And confirm it’s indeed:

`Architecture:               arm64`

#### Step #4: Installing MongoDB:

Unfortunately arkade doesn't support installing MongoDB on ARM64, and as of now the helm charts are also not supporting ARM64. This means we’ll have to do some hacking.

We’re going to use MongoDB from Docker’s Official Images library:

[https://hub.docker.com/_/mongo](https://hub.docker.com/_/mongo)

That supports ARM64. We’ll base our deployment on [bitnami](https://github.com/bitnami/charts/tree/master/bitnami/mongodb)'s helm chart but make the necessary modifications as the container image is different. Copy and paste below into a `mongodb.yaml` file:

```
# Source: mongodb/templates/svc-standalone.yaml
apiVersion: v1
kind: Service
metadata:
  name: db-mongodb
  namespace: default
  labels:
    app: mongodb
    release: "db"
spec:
  type: ClusterIP
  ports:
    - name: mongodb
      port: 27017
      targetPort: mongodb
  selector:
    app: mongodb
    release: "db"
---
# Source: mongodb/templates/deployment-standalone.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: db-mongodb
  namespace: default
  labels:
    app: mongodb
    release: "db"
spec:
  strategy:
    type: RollingUpdate
  selector:
    matchLabels:
      app: mongodb
      release: "db"
  template:
    metadata:
      labels:
        app: mongodb
        release: "db"
    spec:
      containers:
        - name: db-mongodb
          image: docker.io/library/mongo:latest
          imagePullPolicy: "IfNotPresent"
          env:
            - name: MONGO_INITDB_ROOT_USERNAME
              value: "root"
            - name: MONGO_INITDB_ROOT_PASSWORD
              value: "example"
            - name: MONGODB_ENABLE_IPV6
              value: "no"
            - name: MONGODB_ENABLE_DIRECTORY_PER_DB
              value: "no"
          ports:
            - name: mongodb
              containerPort: 27017
          livenessProbe:
            exec:
              command:
                - mongo
                - --eval
                - "db.adminCommand('ping')"
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 5
            successThreshold: 1
            failureThreshold: 6
          readinessProbe:
            exec:
              command:
                - mongo
                - --eval
                - "db.adminCommand('ping')"
            initialDelaySeconds: 5
            periodSeconds: 10
            timeoutSeconds: 5
            successThreshold: 1
            failureThreshold: 6
          volumeMounts:
            - name: data
              mountPath: /data/db
              subPath:
          resources:
            {}
      volumes:
        - name: data
          emptyDir: {}
```

The `mongodb.yaml` above is not designed for production deployment. It doesn’t include persistent storage settings and has a hardcoded login and password to name a few caveats. However, it’s good enough for our proof-of-concept.

Deploying it is as easy as:

`kubectl apply -f mongodb.yaml`

And testing it (i.e., connecting to to MongoDB) is as easy as:

`kubectl run --namespace default db-mongodb-client --rm --tty -i --restart='Never' --image docker.io/library/mongo:latest --command -- mongo admin --host db-mongodb --authenticationDatabase admin -u root -p example`

The latter adopted from the NOTES.txt of bitnami’s MongoDB helm chart.

#### End-to-end Project:

We have taken all the steps above in order to finally be able to have storage for our OpenFaaS functions. Alex wrote an awesome tutorial on this topic here:

[https://www.openfaas.com/blog/get-started-with-python-mongo/](https://www.openfaas.com/blog/get-started-with-python-mongo/)

Again, to avoid confusion, you should follow the tutorial from the ‘Create the hello-python3 function’ chapter.

#### Conclusions:

In this tutorial we’ve taken multiple steps to upgrade our cluster from 32bit to 64bit, quickly setup k3s with OpenFaaS, hack a MongoDB helm chart and get to a situation where we’ve got storage for our functions.

Big thanks to Alex Ellis for reviewing & contributing to this article!