Deployment & CI/CD

JOSHUA provides a comprehensive deployment infrastructure that supports cross-platform builds, Docker containerization, and automated continuous integration. This page covers every aspect of building, testing, and deploying the JOSHUA framework across multiple architectures and operating system versions.

Overview

JOSHUA targets cross-platform deployment across both AMD64 and ARM64 architectures. The framework uses Docker for environment isolation and reproducibility, Bazel for hermetic builds, and GitHub Actions for continuous integration and automated testing.

Key Design Principles The deployment system is built around three core principles: (1) hermetic, reproducible builds via Bazel so that artifacts are identical regardless of the host; (2) multi-platform Docker images that encapsulate all ROS2 and system dependencies; and (3) automated CI pipelines that validate every pull request before merge.

The deployment stack consists of the following layers:

Docker Containers

JOSHUA uses Docker Compose to define a multi-service container topology. The docker-compose.yml file defines five services covering production, experimental, ARM64, and UI workloads. A separate docker-compose.dev.yml file provides development-specific overrides.

Service Definitions

The five services defined in docker-compose.yml are:

Service Base Image ROS2 Python Architecture Role
joshua-u22 Ubuntu 22.04 Humble 3.10 AMD64 Production
joshua-u24 Ubuntu 24.04 Jazzy 3.12 AMD64 Experimental
joshua-u22-arm64 Ubuntu 22.04 Humble 3.10 ARM64 Jetson Orin Nano
joshua-u24-arm64 Ubuntu 24.04 Jazzy 3.12 ARM64 ARM64 Experimental
joshua-ui nginx AMD64 React Web UI (port 3000)

Development Containers

All development containers (joshua-u22, joshua-u24, and the ARM64 variants) share a common configuration profile optimized for robotics development:

# Example: Start the production development container
docker compose up -d joshua-u22

# Example: Start with development overrides
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d joshua-u22

# Example: Start the web UI container
docker compose up -d joshua-ui
# Accessible at http://localhost:3000

Web UI Container

The joshua-ui service runs the React web interface inside an nginx container. It serves the production build of the web UI on port 3000 and proxies WebSocket connections to the Zenoh bridge for real-time ROS2 topic streaming.

Development Compose File

The docker-compose.dev.yml file extends the base configuration with development-specific settings such as source code bind mounts, additional environment variables for debugging, and X11 forwarding for GUI applications (Qt6 control panel, MuJoCo visualization).

Cross-Compilation

JOSHUA supports cross-compilation for ARM64 targets, primarily the NVIDIA Jetson Orin Nano edge computing platform used for on-robot inference. The cross-compilation infrastructure is built on Bazel's platform system and conditional compilation features.

Bazel Platforms

Three Bazel platform definitions are provided for targeting different architectures:

Platform CPU Architecture OS Target Use Case
jetson_orin_nano ARM64 (aarch64) Linux NVIDIA Jetson Orin Nano edge device
cpu_x86_64 AMD64 (x86_64) Linux Standard desktop/server workstation
cpu_aarch64 ARM64 (aarch64) Linux Generic ARM64 Linux target

Conditional Compilation

The .bazelrc file defines config settings that enable conditional compilation based on the target platform. This allows architecture-specific code paths (e.g., NEON SIMD on ARM64, AVX on x86_64) to be selected at build time:

# Build for Jetson Orin Nano
bazel build --config=jetson //joshua/robot:all

# Build for standard AMD64
bazel build --config=u22 //joshua/robot:all

Pre-Built Distribution Tarballs

For environments where building from source is impractical, JOSHUA provides pre-built distribution tarballs in the dist/ directory:

Tip: Jetson Deployment For deploying to the NVIDIA Jetson Orin Nano, use the pre-built ARM64 tarballs from dist/u22/arm64/ or build from source inside the joshua-u22-arm64 Docker container. The Jetson platform definition automatically configures CUDA and TensorRT paths for the Orin Nano's GPU.

Build System (Bazel)

JOSHUA uses Bazel 8.3.1 (managed via Bazelisk) as its primary build system. Bazel provides hermetic, reproducible builds with built-in support for cross-compilation, remote caching, and multi-language projects (C++, Python, Protocol Buffers).

MODULE.bazel and Dependencies

The MODULE.bazel file declares all external dependencies using Bazel's Bzlmod system. All dependencies are resolved hermetially — they are downloaded and built from source at pinned versions, ensuring reproducibility across machines:

Dependency Purpose
abseil-cpp Core C++ utilities (strings, containers, synchronization)
protobuf Protocol Buffers serialization for configuration and messages
gtest Google Test framework for C++ unit testing
pybind11 C++/Python interop for AI inference bridge
boost.asio Asynchronous I/O for serial communication (servo controllers)
gflags Command-line flag parsing
glog Google logging library

Bazel Rule Sets

JOSHUA uses the following Bazel rule sets to build different target types:

Hermetic Python Toolchain

Bazel manages two hermetic Python toolchains to match the target Ubuntu versions:

The Python toolchains are downloaded and managed by Bazel, ensuring that the correct interpreter version is always used regardless of what is installed on the host system.

OS-Specific Configurations

The .bazelrc file provides OS-specific build configurations that set the correct compiler flags, Python version, and ROS2 distribution paths:

# Ubuntu 22.04 with ROS2 Humble
bazel build --config=u22 //joshua/...

# Ubuntu 24.04 with ROS2 Jazzy
bazel build --config=u24 //joshua/...

# Run all tests
bazel test --config=u22 //...

C++ Standard and Compiler

All C++ targets are compiled with the C++17 standard using the system GCC compiler. The .bazelrc file sets --cxxopt=-std=c++17 globally. The system GCC is used (rather than a hermetic toolchain) to ensure ABI compatibility with system-installed ROS2 libraries.

CI/CD Pipeline

JOSHUA uses GitHub Actions for continuous integration. The pipeline is defined in .github/workflows/ci.yml and runs automated builds and tests on every pull request.

Trigger Conditions

Runner Environment

The CI pipeline runs on ubuntu-22.04 GitHub-hosted runners. This matches the primary production target and ensures that tests run in an environment identical to deployment.

Pipeline Steps

The CI workflow executes the following steps in order:

  1. Checkout — Clones the repository with full history for accurate change detection.
  2. Disk Cleanup — Reclaims disk space on the GitHub runner by removing unused toolchains and SDKs. GitHub-hosted runners have limited disk space, and Bazel builds can consume significant storage.
  3. Bazel Cache Restoration — Restores the Bazel build cache from GitHub Actions cache, keyed on MODULE.bazel.lock. When dependencies change, the cache key changes and a fresh cache is built. This dramatically reduces build times for PRs that don't modify dependencies.
  4. Install Bazelisk — Downloads and installs Bazelisk, which automatically manages the correct Bazel version (8.3.1) as specified in the .bazelversion file.
  5. Setup ROS2 Humble — Adds the ROS2 apt repository and installs the ros-humble-desktop meta-package along with development tools. Sources the ROS2 setup script to configure environment variables.
  6. Install System Dependencies — Installs required system libraries:
    • Qt6 — For the desktop control panel GUI.
    • OpenCV — For camera capture and image processing.
    • libevdev — For gamepad/joystick input device handling.
  7. Run Tests — Executes the full test suite with Bazel:
    bazel test //...
    This command discovers and runs all test targets in the repository, including C++ unit tests (Google Test), Python tests, and integration tests.
Cache Strategy The Bazel cache is keyed on MODULE.bazel.lock, which changes whenever external dependencies are added or updated. This means that most PRs (which only change source code) benefit from a fully warm cache, reducing CI build times from ~30 minutes to ~5 minutes.

Setup Script

The scripts/setup.sh script automates environment provisioning for both development workstations and production runtime environments. It handles the complete installation of all system dependencies, build tools, and framework prerequisites.

Environment Modes

The script supports two environment modes selected via the --env flag:

Mode Flag Description
Development --env=dev Full desktop environment with GUI tools, debugging utilities, IDE support, and all build dependencies. Includes Qt6 development headers, MuJoCo visualization, and X11 libraries.
Runtime --env=runtime Minimal runtime environment with only the libraries required to execute pre-built JOSHUA binaries. No build tools, no development headers, no GUI dependencies.

OS Auto-Detection

The script automatically detects the Ubuntu version (22.04 or 24.04) and selects the appropriate package versions, ROS2 distribution (Humble or Jazzy), and Python version. Running on an unsupported OS version will produce a clear error message.

Installation Stages

The setup script executes the following stages:

  1. ROS2 Installation — Adds the official ROS2 apt repository, installs the desktop meta-package (dev mode) or base meta-package (runtime mode), and configures the environment.
  2. OpenCV — Installs OpenCV libraries and Python bindings for camera capture and image processing.
  3. Python Dependencies — Installs Python packages via pip, including PyTorch, HuggingFace Transformers, JAX, and other ML framework dependencies.
  4. Docker — Installs Docker Engine and Docker Compose plugin, configures the current user for rootless Docker access.
  5. Bazel — Installs Bazelisk (which manages Bazel versioning) and verifies the installation.

NVIDIA Library Fixes

The setup script includes special handling for NVIDIA GPU libraries that are commonly misconfigured on Ubuntu systems:

# Full development setup on Ubuntu 22.04
./scripts/setup.sh --env=dev

# Minimal runtime setup on Ubuntu 24.04
./scripts/setup.sh --env=runtime
Warning: NVIDIA Fixes The NVIDIA library fixes in setup.sh modify system library symlinks. These changes are idempotent and safe to run multiple times, but they require sudo access. If you are running in a Docker container, ensure the container has the necessary permissions.

Code Quality

JOSHUA enforces code quality standards through pre-commit hooks, automated linting, and standardized PR templates. These gates ensure consistent code style and catch common issues before they reach the main codebase.

Pre-Commit Hooks

Two pre-commit hooks run automatically before each commit:

C++ Linting

C++ code is formatted and linted using clang-format-14. The project includes a .clang-format configuration file at the repository root that defines the coding style:

# Run clang-format on all C++ files
find . -name "*.cc" -o -name "*.h" | xargs clang-format-14 -i

# Check formatting without modifying (used in CI)
find . -name "*.cc" -o -name "*.h" | xargs clang-format-14 --dry-run --Werror

Python Linting

Python code is linted using ruff, a fast Python linter written in Rust. Ruff enforces PEP 8 style, import ordering, and common Python anti-patterns:

# Run ruff linter
ruff check .

# Run ruff with auto-fix
ruff check --fix .

PR Template

The repository includes a pull request template (.github/PULL_REQUEST_TEMPLATE.md) that standardizes PR descriptions with the following sections:

.clang-format Configuration

The .clang-format file at the repository root defines the C++ code style. All contributors must format their code according to this configuration before submitting a PR. The pre-commit hook (lint_check.sh) enforces this automatically.

Platform Support Matrix

The following table summarizes the supported platform configurations, their associated ROS2 distributions, Python versions, and current support status:

Platform Architecture ROS2 Version Python Version Docker Service Status
Ubuntu 22.04 AMD64 Humble 3.10 joshua-u22 Production
Ubuntu 22.04 ARM64 Humble 3.10 joshua-u22-arm64 Production
Ubuntu 24.04 AMD64 Jazzy 3.12 joshua-u24 Experimental
Ubuntu 24.04 ARM64 Jazzy 3.12 joshua-u24-arm64 Experimental
Production vs Experimental Production platforms are fully tested in CI, used in hardware deployments, and receive priority bug fixes. Experimental platforms are functional but may have occasional compatibility issues with newer ROS2 Jazzy APIs or Python 3.12 dependencies. They are intended for early adopters and forward-compatibility testing.

The Ubuntu 22.04 AMD64 configuration is the primary development and deployment target. It is the platform used in CI (ubuntu-22.04 runners), and all hardware deployments (desktop workstations, Jetson Orin Nano) are validated against this configuration first.