CREB Installation

Documentation and Guides

This page contains a collection of guides. Use the menu on the left to navigate between topics. On smaller screens, the menu becomes a mobile drawer. The dark mode button switches the whole page theme.

Download CREB-Toolkit from Codeberg
Introduction

Getting Started

This guide is made to help you install and configure the following:

Purpose

This guide will help you to overcome the problems with the parallel configuration of different low-level runtimes and their cli-management-tools and save A LOT OF TIME! It is also a guide for using the CREB Tool that I made to benchmark different low-level runtimes that they are using different isolation mechanisms. Is the security, coming with a b1g performance drawback or not? 😊

Very important to 📝 (n0tice)

This page is still under construction and is going to be edited multiple times.

Configuration ❗

I followed this steps in between 2025 and 2026 for the installation and configuration of those specific low-level runtimes (runc, crun, runsc, kata-qemu & kata-fc). For using them and configure them I used different cli-management-tools such as: Docker, Podman & Nerdctl Depending on the year that you are reading this, there is a possibility that somethings changed or need further/different configuration. Consider that, before you START!

Setup NVMe on Pi

Installation OS on Pi

1) First go and download the Raspberry Pi Imager, then choose the sd card to flash the operating system!

Download Raspberry Pi Imager here: Raspberry Pi Imager

Over the installation steps, consider to enable ssh

CREB setup overview

2) After installing the selected operating system, you need to edit the firmware folder of the rasppery pi operating system.

sudo nano /boot/firmware/config.txt

3) To enable PCI-Express for the NVMe-drive you need to add the following:

[all]
        dtparam=nvme
        dtparam=pciex1_gen=3

4) Reboot the system...

sudo reboot

5) Check after reboot, if the PC-Express is activated:

CREB setup overview

6) Show all the drivers

lsblk
CREB setup overview

6) Format the NVME with fdisk tool.

sudo fdisk /dev/nvme0n1
CREB setup overview

7) After that run again the same command to check if the disk is formmated lsblk.

CREB setup overview

8) There is a possibility to install somethings that are needed in specific distros (e.g Ubuntu Server)

sudo apt-get install raspi-config

9) There is a high possibility that the menu is not shown in different flavours or variations of the operating system. Then we need to edit the boot order manually over some commands. This was my case with the official ubuntu 22.04-server-cli edition. So the first step is to update the eeprom!

sudo rpi-eeprom-update

10) The next step is to check if the bootloader is up2date...

BCM2711 detected
VL805 firmware in bootloader EEPROM
BOOTLOADER: up to date

⚠️ In case when eeprom is not installed we do the following steps:

sudo apt update
sudo apt install rpi-eeprom -y
sudo rpi-eeprom-update -asudo apt update
sudo apt install rpi-eeprom -y
sudo rpi-eeprom-update -a

After this we reboot.

sudo reboot

We edit the Bootorder to include the NVME/Usb.

sudo -E rpi-eeprom-config --edit
CREB setup overview

Then we edit the BOOT_ORDER as following:

CREB setup overview

⚠️ WE DONT RESTART THE RASPERRY PI! ⚠️

We use dd to flash the content (operating system) from sd-card into nvme ssd disk.

sudo dd if=/dev/mmcblk0 of=/dev/nvme0n1 bs=4MB status=progress

It will probably take like 10 Minutes depending on the copy speed.

CREB setup overview

Then we restart and use lsblk to check if the operating system is flashed into nvme.

sudo rpi-eeprom-update -a
sudo reboot

After reboot we check with lsblk:

lsblk
CREB setup overview

Usefull links, that could help:

More information: Install raspi-config on Ubuntu 22.04.1 LTS

Install Docker

Install Docker

More information: Install Docker on Debian

# Add Docker's official GPG key:
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

sudo apt update

After doing the first step then you need to install the following:

sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

To test if anything is working you can start the hello-world container!

sudo docker run hello-world

Also to check Dockerversion and installed runtime:

docker --version
Install gVisor

Install gVisor

Use this section to install and configure gVisor (runsc).

First of all create a folder and acess it:

mkdir install_gvisor
cd install_gvisor

Create a script with vim or nano and copy the following code:

sudo nano install_gvisor.sh
(
  set -e
  ARCH=$(uname -m)
  URL=https://storage.googleapis.com/gvisor/releases/release/latest/${ARCH}
  wget ${URL}/runsc ${URL}/runsc.sha512 \
    ${URL}/containerd-shim-runsc-v1 ${URL}/containerd-shim-runsc-v1.sha512
  sha512sum -c runsc.sha512 \
    -c containerd-shim-runsc-v1.sha512
  rm -f *.sha512
  chmod a+rx runsc containerd-shim-runsc-v1
  sudo mv runsc containerd-shim-runsc-v1 /usr/local/bin
)

To run the script you need to give the needed rights:

chmod +x  install_gvisor.sh

To install gVisor as a Docker runtime, run the following commands:

/usr/local/bin/runsc install
sudo systemctl reload docker

To check if the runtime was properly intalled and works with docker, you can run the following commadn:

docker run --rm --runtime=runsc hello-world

Also to check the installed version of gVisor/runsc, you can do the follow:

runsc --version

Okay, because sometimes nothing works out of the box or as you planned, the following steps needed to be made in the following order to run gVisor on the rasperry pi!

⚠️ Consider to follow the steps, only if you are using the rasperry pi! ⚠️

In order for the new low-level runtime to work, we need to edit the following file:

sudo nano /boot/firmware/cmdline.txt

** On some distros, it might be `/boot/cmdline.txt` — check which one exists.

Inside it, will have the following line:

cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1

But we need to edit and write the following in a single line:

console=serial0,115200 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1

Then we need to restart:

sudo reboot

Check if everything works with the following commands:

ls /sys/fs/cgroup/memory/
cat /proc/cgroups | grep memory
sudo docker info | grep -i cgroup
Install Podman

Install Podman

We start by installing podman with the following command:

sudo apt-get -y install podman

To check if Podman works and is properly installed:

sudo podman run --rm hello-world

Check Podmansversion:

podman --version

Okay, in some cases ofc, because life is not easy, the crun is not installed and Podman is going to use the default installed, most of the time runc as main runtime.

To overcome this problem we are going to install also crun, to be sure for 3v3ryth1n...

sudo apt update
sudo apt install -y crun

To check that everything is installed:

which crun
crun --version

Then it returns:

/usr/bin/crun

We can check if Podman sees the runtime without any further problems:

podman info | grep -A20 "ociRuntime"

or with:

podman info

If it is not listed, we need probably to add it manually...

sudo nano /etc/containers/containers.conf

Then we edit the file and we add the following:

[engine.runtimes]
crun = ["/usr/bin/crun"]
runc = ["/usr/bin/runc"]
runsc = ["/usr/bin/runsc"]

Then we can do some tests and try to start containers with different low-level runtimes:

podman run --runtime=crun --rm hello-world
podman run --runtime=runc --rm hello-world
podman run --runtime=runsc --rm hello-world

After the containers are started we can inspect them likeso:

sudo podman inspect <container_name> | grep -i runtime

Or you can make a script like:

sudo nano show_runtime_podman.sh
for cid in $(podman ps -q); do
  echo "▶ Container: $cid"
  echo "Runtime: $(podman inspect --format '{{.OCIRuntime}}' $cid)"
  echo "Environment:"
  podman inspect --format '{{range .Config.Env}}{{println .}}{{end}}' $cid
  echo "--------------------------------------"
done

Give the rights...

sudo chmod +x show_runtime_podman.sh

And just run it:

./show_runtime_podman.sh
CREB setup overview

To stop all the test running containers:

podman stop $(podman ps -q)
Install Nerdctl

Install Nerdctl

More information: Install Kata-Runtime

The first step is to download the following script with wget:

wget https://raw.githubusercontent.com/kata-containers/kata-containers/main/utils/kata-manager.sh

When: containerd is already installed!

chmod +x kata-manager.sh -o 

Or install kata with nerdctl:

chmod +x kata-manager.sh -N 

Okay, lets test it:

sudo nerdctl run --rm -it --runtime=io.containerd.kata.v2 alpine sh

Also some usefull commands:

./kata-manager.sh -L # (Lists all Runtime-Environments)

./kata-manager.sh -S # (sets Runtime-Environment)

./kata-manager.sh -T # (Runs the Tests for the Environment!)

The next step is to configure kata to be compatible with Firecracker, which is a minimal virtual machine monitor to create microVMS.

More information: Install Firecraker

The first step is to generate a shell script and run the following commands:

mkdir install_fc
cd install_fc
sudo nano install_fc_jail.sh
release_url="https://github.com/firecracker-microvm/firecracker/releases"
version=$(yq read /versions.yaml assets.hypervisor.firecracker.version)
arch=`uname -m`
curl ${release_url}/download/${version}/firecracker-${version}-${arch} -o firecracker
curl ${release_url}/download/${version}/jailer-${version}-${arch} -o jailer
chmod +x jailer firecracker

And then:

sudo chmod +x install_fc_jail.sh
./install_fc_jail.sh

The next step is to make the binaries available to PATH

sudo ln -s $(pwd)/firecracker /usr/local/bin
sudo ln -s $(pwd)/jailer /usr/local/bin

The next step is to configure the devmapper!

if we run the command we will receive most of the time the following result.

sudo ctr plugins ls |grep devmapper
CREB setup overview

To overcome this we need to setup the devmapper for this device.

Note: The following scripts assume a 100G sparse file for storing container images, a 10G sparse file for the thin-provisioning pool and 10G base image files for any sandboxed container created. This means that we will need at least 10GB free space.

#!/bin/bash
set -ex

DATA_DIR=/var/lib/containerd/devmapper
POOL_NAME=devpool

mkdir -p ${DATA_DIR}

# Create data file
sudo touch "${DATA_DIR}/data"
sudo truncate -s 100G "${DATA_DIR}/data"

# Create metadata file
sudo touch "${DATA_DIR}/meta"
sudo truncate -s 10G "${DATA_DIR}/meta"

# Allocate loop devices
DATA_DEV=$(sudo losetup --find --show "${DATA_DIR}/data")
META_DEV=$(sudo losetup --find --show "${DATA_DIR}/meta")

# Define thin-pool parameters.
# See https://www.kernel.org/doc/Documentation/device-mapper/thin-provisioning.txt for details.
SECTOR_SIZE=512
DATA_SIZE="$(sudo blockdev --getsize64 -q ${DATA_DEV})"
LENGTH_IN_SECTORS=$(bc <<< "${DATA_SIZE}/${SECTOR_SIZE}")
DATA_BLOCK_SIZE=128
LOW_WATER_MARK=32768

# Create a thin-pool device
sudo dmsetup create "${POOL_NAME}" \
    --table "0 ${LENGTH_IN_SECTORS} thin-pool ${META_DEV} ${DATA_DEV} ${DATA_BLOCK_SIZE} ${LOW_WATER_MARK}"

cat << EOF
#
# Add this to your config.toml configuration file and restart containerd daemon
#
[plugins]
  [plugins.devmapper]
    pool_name = "${POOL_NAME}"
    root_path = "${DATA_DIR}"
    base_image_size = "10GB"
    discard_blocks = true
EOF

We restart the containterd !

sudo systemctl restart containerd

And then we edit the following config.toml file!

sudo nano /etc/containerd/config.toml
[plugins]
  [plugins.devmapper]
    pool_name = "devpool"
    root_path = "/var/lib/containerd/devmapper"
    base_image_size = "10GB"
    discard_blocks = true

Then we restart again the containerd!

sudo systemctl restart containerd

We can use `dmsetup` to verify that the thin-pool was created successfully.

sudo dmsetup ls

We should also check that `devmapper` is registered and running:

sudo ctr plugins ls | grep devmapper
CREB setup overview

This script needs to be run only once, while setting up the `devmapper` `snapshotter` for `containerd`. Afterwards, make sure that on each reboot, the thin-pool is initialized from the same data directory. Otherwise, all the fetched containers (or the ones that you have created) will be re-initialized. A simple script that re-creates the thin-pool from the same data directory is shown below:

sudo nano reload.sh
sudo cmod +x reload.sh
sudo pwd # gives me /home/stergios/install_firecracker/
#!/bin/bash
set -ex

DATA_DIR=/var/lib/containerd/devmapper
POOL_NAME=devpool

# Allocate loop devices
DATA_DEV=$(sudo losetup --find --show "${DATA_DIR}/data")
META_DEV=$(sudo losetup --find --show "${DATA_DIR}/meta")

# Define thin-pool parameters.
# See https://www.kernel.org/doc/Documentation/device-mapper/thin-provisioning.txt for details.
SECTOR_SIZE=512
DATA_SIZE="$(sudo blockdev --getsize64 -q ${DATA_DEV})"
LENGTH_IN_SECTORS=$(bc <<< "${DATA_SIZE}/${SECTOR_SIZE}")
DATA_BLOCK_SIZE=128
LOW_WATER_MARK=32768

# Create a thin-pool device
sudo dmsetup create "${POOL_NAME}" \
    --table "0 ${LENGTH_IN_SECTORS} thin-pool ${META_DEV} ${DATA_DEV} ${DATA_BLOCK_SIZE} ${LOW_WATER_MARK}"

We can create a systemd service to run the above script on each reboot:

sudo nano /lib/systemd/system/devmapper_reload.service

The service file:

[Unit]
Description=Devmapper reload script

[Service]
ExecStart=/home/stergios/install_firecracker/reload.sh

[Install]
WantedBy=multi-user.target

Enable the newly created service:

sudo systemctl daemon-reload
sudo systemctl enable devmapper_reload.service
sudo systemctl start devmapper_reload.service

⚠️ alternative start, this example refered to a total of 32 GB disk, that I tried in an VM inside my proxmox appliance and worked.

#!/bin/bash
set -ex

DATA_DIR=/var/lib/containerd/devmapper
POOL_NAME=devpool
CONFIG_FILE="/etc/containerd/config.toml"

# Create devmapper storage files (safe for 32GB total disk)
mkdir -p "${DATA_DIR}"

sudo touch "${DATA_DIR}/data"
sudo truncate -s 15G "${DATA_DIR}/data"

sudo touch "${DATA_DIR}/meta"
sudo truncate -s 1G "${DATA_DIR}/meta"

# Allocate loop devices
DATA_DEV=$(sudo losetup --find --show "${DATA_DIR}/data")
META_DEV=$(sudo losetup --find --show "${DATA_DIR}/meta")

# Thin pool settings
SECTOR_SIZE=512
DATA_SIZE="$(sudo blockdev --getsize64 -q ${DATA_DEV})"
LENGTH_IN_SECTORS=$(bc <<< "${DATA_SIZE}/${SECTOR_SIZE}")
DATA_BLOCK_SIZE=128
LOW_WATER_MARK=32768

# Create thin-pool device
sudo dmsetup create "${POOL_NAME}" \
  --table "0 ${LENGTH_IN_SECTORS} thin-pool ${META_DEV} ${DATA_DEV} ${DATA_BLOCK_SIZE} ${LOW_WATER_MARK}"

# Ensure config.toml exists
if [ ! -f "$CONFIG_FILE" ]; then
    sudo containerd config default | sudo tee "$CONFIG_FILE" > /dev/null
fi

# Backup original config
sudo cp "$CONFIG_FILE" "${CONFIG_FILE}.bak.$(date +%s)"

# Inject devmapper settings (replace/add plugins.devmapper block)
sudo sed -i '/\[plugins\.devmapper\]/,/^$/d' "$CONFIG_FILE"
cat << EOF | sudo tee -a "$CONFIG_FILE" > /dev/null

[plugins."io.containerd.snapshotter.v1.devmapper"]
  pool_name = "${POOL_NAME}"
  root_path = "${DATA_DIR}"
  base_image_size = "2GB"
  discard_blocks = true
EOF

# Restart containerd
sudo systemctl restart containerd

echo "Devmapper setup complete and containerd configured."

creates the thin_pool for only once, this creates also the thin_pool for the 32GB disk

#!/bin/bash
set -ex

DATA_DIR=/var/lib/containerd/devmapper
POOL_NAME=devpool

# Ensure devmapper files exist and are correctly sized
mkdir -p "${DATA_DIR}"

# Create or resize data file to 15G
sudo touch "${DATA_DIR}/data"
sudo truncate -s 15G "${DATA_DIR}/data"

# Create or resize metadata file to 1G
sudo touch "${DATA_DIR}/meta"
sudo truncate -s 1G "${DATA_DIR}/meta"

# Allocate loop devices
DATA_DEV=$(sudo losetup --find --show "${DATA_DIR}/data")
META_DEV=$(sudo losetup --find --show "${DATA_DIR}/meta")

# Define thin-pool parameters
SECTOR_SIZE=512
DATA_SIZE="$(sudo blockdev --getsize64 -q ${DATA_DEV})"
LENGTH_IN_SECTORS=$(bc <<< "${DATA_SIZE}/${SECTOR_SIZE}")
DATA_BLOCK_SIZE=128
LOW_WATER_MARK=32768

# Create a thin-pool device
sudo dmsetup create "${POOL_NAME}" \
  --table "0 ${LENGTH_IN_SECTORS} thin-pool ${META_DEV} ${DATA_DEV} ${DATA_BLOCK_SIZE} ${LOW_WATER_MARK}"

echo "Thin pool '${POOL_NAME}' created successfully using ${DATA_DEV} and ${META_DEV}."

Create script for auto mounting the devmapper:

Save this file as `/usr/local/bin/setup-devmapper-pool.sh`:

#!/bin/bash
set -e

DATA_DIR=/var/lib/containerd/devmapper
POOL_NAME=devpool

# Reattach loop devices if not already attached
[ -b /dev/loop0 ] || sudo losetup -f "${DATA_DIR}/data"
[ -b /dev/loop1 ] || sudo losetup -f "${DATA_DIR}/meta"

# Find actual loop device names
DATA_DEV=$(losetup -j "${DATA_DIR}/data" | cut -d: -f1)
META_DEV=$(losetup -j "${DATA_DIR}/meta" | cut -d: -f1)

# Recreate thin-pool
SECTOR_SIZE=512
DATA_SIZE="$(blockdev --getsize64 -q ${DATA_DEV})"
LENGTH_IN_SECTORS=$(bc <<< "${DATA_SIZE}/${SECTOR_SIZE}")
DATA_BLOCK_SIZE=128
LOW_WATER_MARK=32768

# Only create if not already present
if ! dmsetup status "${POOL_NAME}" &>/dev/null; then
  dmsetup create "${POOL_NAME}" \
    --table "0 ${LENGTH_IN_SECTORS} thin-pool ${META_DEV} ${DATA_DEV} ${DATA_BLOCK_SIZE} ${LOW_WATER_MARK}"
fi
sudo chmod +x /usr/local/bin/setup-devmapper-pool.sh

Create a file at:

sudo nano /etc/systemd/system/devmapper-pool.service
[Unit]
Description=Setup devmapper thin-pool for containerd
DefaultDependencies=no
After=local-fs.target
Before=containerd.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/setup-devmapper-pool.sh
RemainAfterExit=true

[Install]
WantedBy=multi-user.target
enable and start the script
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable devmapper-pool.service
sudo systemctl start devmapper-pool.service

Test if it Works...

sudo dmsetup status
sudo losetup -a

❗ Configure Kata Containers with AWS Firecracker ❗

Do the following steps:

sudo find / -name "configuration-fc.toml" 2>/dev/null

If I found the file e.g under:

/opt/kata/share/defaults/kata-containers/configuration-fc.toml
#!/bin/bash
KATA_CONF_FILE=/opt/kata/share/defaults/kata-containers/configuration-fc.toml /usr/bin/containerd-shim-kata-v2 $@
>
sudo cp /usr/share/defaults/kata-containers/configuration-fc.toml /etc/kata-containers/configuration.toml
sudo ln -sf /usr/share/defaults/kata-containers/configuration-fc.toml /etc/kata-containers/configuration.toml

Test it as following:

kata-runtime --version

❗ Configure Containerd ❗

Next, we need to configure containerd. Add a file in your path (e.g. /usr/local/bin/containerd-shim-kata-fc-v2) with the following contents:

/usr/bin/containerd-shim-kata-fc-v2
```
#!/bin/bash
KATA_CONF_FILE=/etc/kata-containers/configuration-fc.toml /usr/bin/containerd-shim-kata-v2 $@

Note: You may need to edit the paths of the configuration file and the containerd-shim-kata-v2 to correspond to your setup.

Make it executable:

/usr/local/bin/containerd-shim-kata-fc-v2
sudo chmod +x /usr/local/bin/containerd-shim-kata-fc-v2

Lastly, edit the /etc/containerd/config.toml

[plugins]
  [plugins."io.containerd.grpc.v1.cri"]
    [plugins."io.containerd.grpc.v1.cri".containerd]
      default_runtime_name = "kata"
      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata]
          runtime_type = "io.containerd.kata.v2"
          privileged_without_host_devices = true
        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata-fc]
                runtime_type = "io.containerd.kata-fc.v2"

  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata.options]
    ConfigPath = "/opt/kata/share/defaults/kata-containers/configuration.>
        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata-clh]
          runtime_type = "io.containerd.kata-clh.v2"
  privileged_without_host_devices = true
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata-clh.optio>
    ConfigPath = "/opt/kata/share/defaults/kata-containers/configuration->


[plugins.devmapper]
  pool_name = "devpool"
  root_path = "/var/lib/containerd/devmapper"
  base_image_size = "2GB"
  discard_blocks = true

Run Kata with Firecraker:

sudo nerdctl run --rm -it --snapshotter devmapper --runtime io.containerd.run.kata-fc.v2  alpine sh

Run Kata with QEMU:

sudo nerdctl run --rm -it --snapshotter devmapper --runtime=io.containerd.kata.v2  alpine sh

(but only if the kata-manager.sh is configured to work with -S fc)

Check the Runtime with nerdctl:

for c in $(nerdctl ps -q); do
  echo "Container: $c"
  nerdctl inspect $c | grep -i runtime
  echo
done
Configure and run CREB

Benchmark Execution

Configure and run CREB demonstration

This guide can explain how benchmark scenarios are executed, which parameters are used, and how results are collected.

Configure Benchmark-Server

Benchmark-Server

In order for the complete benchmark environment to work as intended, a second machine is used to host several supporting containers. These containers are required for collecting measurement data, forwarding MQTT messages, storing time-series data, visualizing the results, and running specific benchmark scenarios.

The data flow follows a common monitoring pipeline: the Tasmota smart plug sends MQTT messages to the Mosquitto broker, Node-RED subscribes to the MQTT topics and processes the messages, InfluxDB stores the measurements as time-series data, and Grafana visualizes the stored values in dashboards.

Tasmota Smart Plug Mosquitto MQTT Broker Node-RED InfluxDB v1.8 Grafana

The required containers are the following:

Exposed Ports

Tool Purpose Exposed Port Access Example
Mosquitto MQTT Broker Receives MQTT messages from the Tasmota smart plug. 1883/tcp
9001/tcp optional WebSocket
mqtt://SERVER-IP:1883
ws://SERVER-IP:9001
Node-RED Subscribes to MQTT topics, processes the messages, and forwards the data to InfluxDB. 1880/tcp http://SERVER-IP:1880
InfluxDB v1.8 Stores benchmark and power-consumption values as time-series measurements. 8086/tcp http://SERVER-IP:8086
Grafana Visualizes the measurement data stored in InfluxDB. 3000/tcp http://SERVER-IP:3000
iperf3 Acts as the server endpoint for TCP and UDP network benchmark scenarios. 5201/tcp
5201/udp
SERVER-IP:5201
Portainer Provides a web interface for managing Docker containers, images, volumes, and networks. 9443/tcp https://SERVER-IP:9443

Install Docker Engine

Before the supporting services can be started, Docker Engine must be installed on the second machine. The following commands install Docker on an Ubuntu-based system.

sudo apt-get update
sudo apt-get install -y ca-certificates curl

sudo install -m 0755 -d /etc/apt/keyrings

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
  -o /etc/apt/keyrings/docker.asc

sudo chmod a+r /etc/apt/keyrings/docker.asc

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update

sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

sudo systemctl enable docker
sudo systemctl start docker

The Docker installation can be checked with:

sudo docker run hello-world

Optionally, the current user can be added to the Docker group so that Docker commands can be executed without sudo.

sudo usermod -aG docker $USER
newgrp docker

docker run hello-world

Create a Docker Network

A dedicated Docker network is created so that the containers can communicate with each other by using their container names.

docker network create benchmark-net

Install and Run Mosquitto MQTT Broker

Mosquitto is used as the MQTT broker. The normal MQTT listener runs on port 1883. Port 9001 is included as an optional WebSocket listener.

Note: With newer Mosquitto versions, it is better to create an explicit configuration file. Otherwise, external clients may not be able to connect correctly from another machine in the network.
mkdir -p ~/mosquitto/config

cat > ~/mosquitto/config/mosquitto.conf <<'EOF'
listener 1883
protocol mqtt

listener 9001
protocol websockets

allow_anonymous true

persistence true
persistence_location /mosquitto/data/

log_dest stdout
EOF

docker volume create mosquitto_data
docker volume create mosquitto_log

docker run -d \
  --name mosquitto-server \
  --restart unless-stopped \
  --network benchmark-net \
  -p 1883:1883 \
  -p 9001:9001 \
  -v ~/mosquitto/config:/mosquitto/config \
  -v mosquitto_data:/mosquitto/data \
  -v mosquitto_log:/mosquitto/log \
  eclipse-mosquitto:2

Check whether Mosquitto is running:

docker ps
docker logs mosquitto-server

Exposed ports:

1883/tcp
9001/tcp

Install and Run Node-RED

Node-RED is used to subscribe to the MQTT topics from Mosquitto, process the incoming messages, and forward the measurement values to InfluxDB.

docker volume create node_red_data

docker run -d \
  --name node-red \
  --restart unless-stopped \
  --network benchmark-net \
  -p 1880:1880 \
  -v node_red_data:/data \
  nodered/node-red:latest

Check whether Node-RED is running:

docker ps
docker logs node-red

Exposed port:

1880/tcp

Node-RED can be opened in the browser at:

http://SERVER-IP:1880

Inside Node-RED, the MQTT broker address can be configured as:

mosquitto-server:1883

Install and Run InfluxDB v1.8

InfluxDB v1.8 is used as the time-series database. The database name in this example is rasp.

docker volume create influxdb_data

docker run -d \
  --name influxdb \
  --restart unless-stopped \
  --network benchmark-net \
  -p 8086:8086 \
  -v influxdb_data:/var/lib/influxdb \
  -e INFLUXDB_DB=rasp \
  -e INFLUXDB_HTTP_AUTH_ENABLED=false \
  influxdb:1.8

Check whether InfluxDB is running:

docker ps
docker logs influxdb

Exposed port:

8086/tcp

Other containers in the same Docker network can reach InfluxDB by using:

http://influxdb:8086

To open the InfluxDB command-line interface inside the container, use:

docker exec -it influxdb influx

To create the database manually, if it does not already exist, use:

CREATE DATABASE rasp;
CREB setup overview

Install and Run Grafana

Grafana is used to create dashboards for visualizing the benchmark and power-consumption data stored in InfluxDB.

docker volume create grafana_storage

docker run -d \
  --name grafana \
  --restart unless-stopped \
  --network benchmark-net \
  -p 3000:3000 \
  -v grafana_storage:/var/lib/grafana \
  grafana/grafana:latest

Check whether Grafana is running:

docker ps
docker logs grafana

Exposed port:

3000/tcp

Grafana can be opened in the browser at:

http://SERVER-IP:3000

The default login is usually:

Username: admin
Password: admin

When adding InfluxDB as a data source in Grafana, use the container name as the database URL:

http://influxdb:8086

The database name is:

rasp

After installing all the needed containers, the following video can help you with their configuration, so they can communicate:

Also a very helpfull tool for exploring the exposed values

MQTT-Explorer

Install and Run iperf3 Server

iperf3 is used as the server component for the network benchmark scenario. Both TCP and UDP traffic are exposed on port 5201.

docker run -d \
  --name iperf3-server \
  --restart unless-stopped \
  --network benchmark-net \
  -p 5201:5201/tcp \
  -p 5201:5201/udp \
  networkstatic/iperf3 \
  -s

Check whether iperf3 is running:

docker ps
docker logs iperf3-server

Exposed ports:

5201/tcp
5201/udp

Example TCP client command from another machine:

iperf3 -c SERVER-IP -p 5201

Example UDP client command from another machine:

iperf3 -c SERVER-IP -p 5201 -u -b 1G -l 1400

Install and Run Portainer

Portainer provides a web-based interface for managing Docker containers, images, volumes, and networks.

docker volume create portainer_data

docker run -d \
  --name portainer \
  --restart unless-stopped \
  -p 9443:9443 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:lts

Check whether Portainer is running:

docker ps
docker logs portainer

Exposed port:

9443/tcp

Portainer can be opened in the browser at:

https://SERVER-IP:9443

Configure the Tasmota Smart Plug

On the Tasmota device, MQTT must be enabled and the IP address of the machine running the Mosquitto container must be entered as the MQTT server.

MQTT host: SERVER-IP
MQTT port: 1883
MQTT user: empty, if anonymous access is enabled
MQTT password: empty, if anonymous access is enabled

Check All Running Containers

After starting all containers, the running services can be checked with:

docker ps

The expected containers are:

mosquitto-server
node-red
influxdb
grafana
iperf3-server
portainer

Expected Result

After the setup is complete, the second machine provides all supporting services required for the benchmark environment. The Tasmota smart plug sends MQTT messages to Mosquitto. Node-RED receives and processes these messages, InfluxDB stores the resulting time-series measurements, and Grafana visualizes the data in dashboards. In addition, iperf3 is available for network measurements, while Portainer can be used to manage the Docker environment through a web interface.

FAQ

FAQ

I am going also to provide you with a dedicated E-Mail, if you want to ask somethings about the CREB-Toolkit and how to set it up. Please dont spam or abuse the E-Mail, if I dont answer probably the time is against me...