.. _deploy_boss: Deploying BOSS in Production ============================ .. image:: ../../static/deploy_boss_scheme.svg :width: 70% :alt: BOSS monitoring stack used in this tutorial. In the :ref:`getting_started_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 :ref:`getting_started_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 :ref:`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 .. code-block:: bash uv run hero-monitor --realm my_realm or by specifying the ``realm`` keyword when interfacing HEROS in code, like .. code-block:: python 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: .. tab-set:: .. tab-item:: Docker Compose .. code-block:: yaml :caption: 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: .. code-block:: bash docker compose up -d couchdb .. tab-item:: Docker Run .. code-block:: bash 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: .. tab-set:: .. tab-item:: CouchDB GUI 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 .. tab-item:: CLI .. code-block:: bash 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: .. tab-set:: .. tab-item:: CouchDB GUI 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: .. code-block:: json { "_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 } 5. Click "Create Document" to save .. tab-item:: CLI .. code-block:: bash 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 :external:ref:`json-head`. .. _tutorial-boss-advanced-couch-views: 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: .. tab-set:: .. tab-item:: CouchDB GUI 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: .. code-block:: 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" } 7. Click "Create Document" to save the design document .. tab-item:: CLI Save the design document to a file ``machine_filter_view.json``: .. code-block:: json :caption: 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: .. code-block:: bash 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: .. code-block:: bash # 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 :external:ref:`couchdb-head`. 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. .. tab-set:: .. tab-item:: Docker Compose Create a ``docker-compose.yml`` file: .. code-block:: yaml :caption: 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: .. code-block:: bash docker compose up -d .. tab-item:: Docker Run Run BOSS directly with docker run: .. code-block:: bash 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 :external:ref:`heros-conf`. .. 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 :ref:`views defined above ` to filter devices per machine: Here's how to start BOSS instances on different machines: .. tab-set:: .. tab-item:: Machine 1 (Docker Compose) .. code-block:: yaml :caption: 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 .. code-block:: bash docker compose -f docker-compose-machine1.yml up -d .. tab-item:: Machine 1 (Docker Run) .. code-block:: bash 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 .. tab-set:: .. tab-item:: Machine 2 (Docker Compose) .. code-block:: yaml :caption: 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 .. code-block:: bash docker compose -f docker-compose-machine2.yml up -d .. tab-item:: Machine 2 (Docker Run) .. code-block:: bash 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 :ref:`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: .. tab-set:: .. tab-item:: CouchDB GUI 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: .. code-block:: json { "_id": "statemachine", "classname": "herostools.actor.statemachine.HERODatasourceStateMachine", "arguments": { "loop": "@_boss_loop", "http_port": 9099, "bind_address": "0.0.0.0" }, "active": true } 5. Click "Create Document" to save .. tab-item:: CLI .. code-block:: bash 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 :external:ref:`Setup`. Configuring Prometheus ^^^^^^^^^^^^^^^^^^^^^^ Create a ``prometheus_config/prometheus.yml`` configuration file: .. code-block:: yaml :caption: 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: .. tab-set:: .. tab-item:: Docker Compose Add to your docker-compose.yml (see :ref:`tutorial-boss-advanced-monitor-compose` for full working compose file): .. code-block:: yaml # 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: .. code-block:: bash docker compose up -d prometheus .. tab-item:: Docker Run .. code-block:: bash 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 :ref:`tutorial-boss-advanced-monitor-compose` for full working compose file): .. tab-set:: .. tab-item:: Docker Compose Add to your docker-compose.yml: .. code-block:: yaml :caption: 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: .. code-block:: bash docker compose up -d grafana .. tab-item:: Docker Run .. code-block:: bash 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. .. _tutorial-boss-advanced-monitor-compose: Putting It All Together ----------------------- Here's a complete ``docker-compose.yml`` example that ties everything together: .. code-block:: yaml :caption: 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: .. code-block:: bash 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 --------- - Learn more about :external:ref:`BOSS JSON configuration ` - Explore :external:ref:`HEROS realms configuration ` - Check out `herostools documentation `_ for more monitoring and flow tools - Read about :repo-doc-link:`herosdevices` for real device drivers - For advanced event handling patterns, see :external:ref:`sec-events` .. tip:: For complex deployments, consider using environment-specific CouchDB databases (e.g., ``boss-configs-dev``, ``boss-configs-prod``) to separate configurations.