Deploying BOSS in Production

BOSS monitoring stack used in this tutorial.

In the Getting Started with HEROS tutorial, we learned how to set up individual HEROs and interact with them. This tutorial builds upon that foundation and shows you how to deploy HEROS and BOSS in production environments. We’ll cover containerized deployment, database-backed configuration, monitoring, and multi-instance setups.

Prerequisites

Before starting this tutorial, ensure you have:

  • Completed the Getting Started with HEROS tutorial

  • Basic Docker knowledge: Understanding of containers, images, docker run, and docker-compose commands

  • Familiarity with CouchDB concepts (databases, documents, views)

  • A working HEROS environment

Tip

For managing Docker containers and compose files from a web interface, you can use Arcane. It provides a user-friendly GUI for Docker management, which can be helpful for visualizing and controlling your containerized HEROS deployment.

Using Realms

To isolate groups of HERO objects from other groups the concept of realms exists in HEROS. You can think of it as a namespace where objects in the same namespace can talk to each other while communication across realms/namespaces is not possible.

Warning

Note that this is solely a management feature, not a security feature. By default, all realms share the same zenoh network and can thus talk to each other on a low level. We recommend changing this behavior by the HEROS_SEP_MULTICAST environment variable, which will also be the default in the future.

For a production setup, we strongly recommend to not use the default realm (called heros), but set the realm of all your devices to a descriptive name, like the name of your experiment. In this tutorial we will use the realm my_realm.

This is done by setting the --realm command line argument of all cli tools using HEROS like boss or the atomiq_master, like

uv run hero-monitor --realm my_realm

or by specifying the realm keyword when interfacing HEROS in code, like

my_hero = RemoteHERO("my_hero", realm="realm")

Setting up CouchDB for BOSS Configuration

CouchDB provides a robust way to store and manage your BOSS device configurations centrally. This allows you to modify configurations without restarting services and enables multi-system deployments.

Installing CouchDB

For production use, we recommend running CouchDB in a Docker container:

docker-compose.yml
# couchdb service
version: '3.8'
services:
  couchdb:
    image: couchdb:latest
    environment:
      COUCHDB_USER: admin
      COUCHDB_PASSWORD: yourpassword
    ports:
      - "5984:5984"
    volumes:
      - couchdb_data:/opt/couchdb/data
    restart: always

Start with:

docker compose up -d couchdb
docker run -d \
  --name couchdb \
  -p 5984:5984 \
  -e COUCHDB_USER=admin \
  -e COUCHDB_PASSWORD=yourpassword \
  -v couchdb_data:/opt/couchdb/data \
  couchdb:latest

Create a database for your BOSS configurations:

  1. Open the CouchDB web interface at http://localhost:5984/_utils and login

  2. Click “Create Database” and enter boss-configs as a name and confirm

curl -X PUT http://admin:yourpassword@localhost:5984/boss-configs

Creating Device Configurations

Now let’s create a device configuration document. This is similar to the JSON file we used in the getting started tutorial, but stored in CouchDB:

  1. Open the CouchDB web interface at http://localhost:5984/_utils

  2. Select the boss-configs database

  3. Click “Create Document”

  4. Enter the following configuration:

{
  "_id": "production_camera",
  "classname": "herosdevices.hardware.dummy.camera.CameraDummy",
  "arguments": {
    "config_dict": {
      "default": {
        "height": 1024,
        "width": 1280,
        "frame_count": -1,
        "auto_trigger": false
      }
    }
  },
  "active": true
}
  1. Click “Create Document” to save

curl -X PUT http://admin:yourpassword@localhost:5984/boss-configs/production_camera \
  -H "Content-Type: application/json" \
  -d '{"classname": "herosdevices.hardware.dummy.camera.CameraDummy", "arguments": {"config_dict": {"default": {"height": 1024, "width": 1280, "frame_count": -1, "auto_trigger": false}}}, "active": true}'

Note

The active field allows you to enable/disable devices without deleting them. The _id field sets the document ID which will be used as the HERO name.

For more information about BOSS JSON configuration syntax, see JSON Configuration Format.

Creating Views for Device Filtering

Views allow you to filter which devices should be started by BOSS. Here’s a complete example for machine-specific filtering:

  1. Open the CouchDB web interface

  2. Select the boss-configs database

  3. Click the “+” at “Design Documents” in the left sidebar

  4. Click “New Doc”

  5. In the editor, enter the following views:

{
  "_id": "_design/machine_filter",
  "views": {
    "machine1": {
      "map": "function(doc) { if(doc.active && doc.machine === 'machine1') { emit(doc._id, null); } }"
    },
    "machine2": {
      "map": "function(doc) { if(doc.active && doc.machine === 'machine2') { emit(doc._id, null); } }"
    },
    "all_active": {
      "map": "function(doc) { if(doc.active) { emit(doc._id, null); } }"
    }
  },
  "language": "javascript"
}
  1. Click “Create Document” to save the design document

Save the design document to a file machine_filter_view.json:

machine_filter_view.json
{
  "_id": "_design/machine_filter",
  "views": {
    "machine1": {
      "map": "function(doc) { if(doc.active && doc.machine === 'machine1') { emit(doc._id, null); } }"
    },
    "machine2": {
      "map": "function(doc) { if(doc.active && doc.machine === 'machine2') { emit(doc._id, null); } }"
    },
    "all_active": {
      "map": "function(doc) { if(doc.active) { emit(doc._id, null); } }"
    }
  },
  "language": "javascript"
}

Then create the design document:

curl -X PUT http://admin:yourpassword@localhost:5984/boss-configs/_design/machine_filter \
  -H "Content-Type: application/json" \
  -d '@machine_filter_view.json'

This creates multiple views:

  • machine1: Only devices with machine: "machine1" and active: true

  • machine2: Only devices with machine: "machine2" and active: true

  • all_active: All devices with active: true (regardless of machine)

You can then use these views in your BOSS commands:

# Start only machine1 devices
uv run boss -u http://admin:pw@couchdb:5984/boss-configs/_design/machine_filter/_view/machine1?include_docs=true

For advanced CouchDB usage patterns with BOSS, refer to CouchDB for BOSS.

Containerized BOSS Deployment

Running BOSS in containers provides isolation, easier deployment, and better resource management. We provide pre-built Docker images for all components, so you don’t need to create your own Dockerfiles.

The recommended approach is to use our official pre-built images from our GitLab registry. We provide images for herostools (registry.gitlab.com/atomiq-project/herostools:latest), herosdevices (registry.gitlab.com/atomiq-project/herostools:latest) or standalone boss (registry.gitlab.com/atomiq-project/boss:latest) if you don’t need anything from the herostools or herosdevices extensions.

Create a docker-compose.yml file:

docker-compose.yml
version: '3.8'

services:
  boss-production:
    image: registry.gitlab.com/atomiq-project/herostools:latest
    restart: always
    network_mode: host
    command: python -m boss.starter -u http://admin:yourpassword@couchdb:5984/boss-configs/_design/active_devices/_view/active?include_docs=true --expose --name BOSS-production --realm my_realm

Start the service:

docker compose up -d

Run BOSS directly with docker run:

docker run -d \
  --name boss-production \
  --network host \
  registry.gitlab.com/atomiq-project/herostools:latest \
  python -m boss.starter -u http://admin:yourpassword@couchdb:5984/boss-configs/_design/active_devices/_view/active?include_docs=true --expose --name BOSS-production --realm my_realm

Important

The network_mode: host (or --network host) is required for proper HEROS discovery. HEROS uses multicast for service discovery, which doesn’t work with Docker’s default bridge networking.

For more details on HEROS realms and network configuration, see Configuring HEROS.

Note

The --expose flag makes the BOSS instance discoverable in the network, and --name sets a custom name for this BOSS instance.

Running Multiple Instances of BOSS

You can run multiple BOSS instances to:

  • Distribute devices across multiple machines

  • Group devices logically (e.g., by subsystem)

  • Update configurations independently without disrupting all services

Multi-Machine Deployment

To deploy BOSS on multiple systems from the same CouchDB you can use the views defined above to filter devices per machine: Here’s how to start BOSS instances on different machines:

docker-compose.yml
version: '3.8'

services:
  boss-machine1:
    image: registry.gitlab.com/atomiq-project/herostools:latest
    restart: always
    network_mode: host
    command: python -m boss.starter -u http://admin:yourpassword@couchdb:5984/boss-configs/_design/machine_filter/_view/machine1?include_docs=true --expose --name BOSS-machine1 --realm my_realm
docker compose -f docker-compose-machine1.yml up -d
docker run -d \
  --name boss-machine1 \
  --network host \
  registry.gitlab.com/atomiq-project/herostools:latest \
  python -m boss.starter -u http://admin:yourpassword@couchdb:5984/boss-configs/_design/machine_filter/_view/machine1?include_docs=true --expose --name BOSS-machine1 --realm my_realm
docker-compose-machine2.yml
version: '3.8'

services:
  boss-machine2:
    image: registry.gitlab.com/atomiq-project/herostools:latest
    restart: always
    network_mode: host
    command: python -m boss.starter -u http://admin:yourpassword@couchdb:5984/boss-configs/_design/machine_filter/_view/machine2?include_docs=true --expose --name BOSS-machine2 --realm my_realm
docker compose -f docker-compose-machine2.yml up -d
docker run -d \
  --name boss-machine2 \
  --network host \
  registry.gitlab.com/atomiq-project/herostools:latest \
  python -m boss.starter -u http://admin:yourpassword@couchdb:5984/boss-configs/_design/machine_filter/_view/machine2?include_docs=true --expose --name BOSS-machine2 --realm my_realm

Monitoring with Prometheus and Grafana

Monitoring your HERO datasources is crucial for a modern lab. We’ll use Prometheus for metrics collection and Grafana for visualization in this tutorial. Other backends are supported or easily implementable.

Setting up the StateMachine

Add the HERODatasourceStateMachine to your CouchDB configuration:

  1. Open the CouchDB web interface at http://localhost:5984/_utils

  2. Select the boss-configs database from the dropdown

  3. Click “Create Document” and then “New Doc”

  4. Enter the following configuration:

{
  "_id": "statemachine",
  "classname": "herostools.actor.statemachine.HERODatasourceStateMachine",
  "arguments": {
    "loop": "@_boss_loop",
    "http_port": 9099,
    "bind_address": "0.0.0.0"
  },
  "active": true
}
  1. Click “Create Document” to save

curl -X PUT http://admin:yourpassword@localhost:5984/boss-configs/statemachine \
  -H "Content-Type: application/json" \
  -d '{"classname": "herostools.actor.statemachine.HERODatasourceStateMachine", "arguments": {"loop": "@_boss_loop", "http_port": 9099, "bind_address": "0.0.0.0"}, "active": true}'

This will expose metrics on port 9099 that Prometheus can scrape.

For more information about the HERODatasourceStateMachine and its configuration options, see Setup.

Configuring Prometheus

Create a prometheus_config/prometheus.yml configuration file:

prometheus_config/prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
   - job_name: 'heros-datasources'
       scrape_interval: 5s
       metrics_path: /metrics
       static_configs:
       - targets: ['172.17.0.1:9099']
           labels:
           group: 'heros'

Note

The target IP 172.17.0.1 given here targets the docker host, which is required since the aggregator (statemachine) runs in the host network.

Run Prometheus in a container:

Add to your docker-compose.yml (see Putting It All Together for full working compose file):

# prometheus service
prometheus:
  image: prom/prometheus:latest
  ports:
    - "9090:9090"
  command:
    - --config.file=/etc/prometheus/prometheus.yml
    - --storage.tsdb.retention.time=10y
  volumes:
    - prometheus_data:/prometheus
    - ./prometheus_config:/etc/prometheus
  restart: always

Then start with:

docker compose up -d prometheus
docker run -d \
  --name prometheus \
  -p 9090:9090 \
  -v $(pwd)/prometheus_config:/etc/prometheus \
  prom/prometheus --config.file=/etc/prometheus/prometheus.yml --storage.tsdb.retention.time=10y

Setting up Grafana

Run Grafana and connect it to Prometheus (see Putting It All Together for full working compose file):

Add to your docker-compose.yml:

docker-compose.yml
# grafana service
grafana:
  image: grafana/grafana:latest
  ports:
    - "3000:3000"
  depends_on:
    - prometheus
  volumes:
    - grafana_data:/var/lib/grafana
  restart: always

Then start with:

docker compose up -d grafana
docker run -d \
  --name grafana \
  -p 3000:3000 \
  -v grafana_data:/var/lib/grafana \
  grafana/grafana

Access Grafana at http://localhost:3000 (default credentials: admin/admin) and:

  1. Add Prometheus as a data source (URL: http://prometheus:9090)

  2. Create dashboards to visualize your HERO metrics

Tip

The metrics exposed by HERODatasourceStateMachine include device status, observable values, and other useful information for monitoring your system health.

Putting It All Together

Here’s a complete docker-compose.yml example that ties everything together:

docker-compose.yml
version: '3.8'

services:
  couchdb:
    image: couchdb:latest
    environment:
      COUCHDB_USER: admin
      COUCHDB_PASSWORD: yourpassword
    ports:
      - "5984:5984"
    volumes:
      - couchdb_data:/opt/couchdb/data
    restart: always

  boss:
    image: registry.gitlab.com/atomiq-project/herostools:latest
    depends_on:
      - couchdb
    network_mode: host
    command: python -m boss.starter -u http://admin:yourpassword@couchdb:5984/boss-configs/_design/active_devices/_view/active?include_docs=true --expose --name BOSS-production --realm my_realm
    restart: always

  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    command:
      - --config.file=/etc/prometheus/prometheus.yml
      - --storage.tsdb.retention.time=10y
    volumes:
      - prometheus_data:/prometheus
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    restart: always

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    depends_on:
      - prometheus
    volumes:
      - grafana_data:/var/lib/grafana
    restart: always

volumes:
  couchdb_data:
  prometheus_data:
  grafana_data:

To start everything:

docker-compose up -d

Note

Remember that the BOSS service uses network_mode: host for proper multicast discovery, while other services can use the default bridge networking.

Resources

Tip

For complex deployments, consider using environment-specific CouchDB databases (e.g., boss-configs-dev, boss-configs-prod) to separate configurations.