Docker Workflow Guide¶
This guide covers practical Docker operations for AirStack development. For concepts, see Key Concepts.
Quick Reference¶
# Start/stop
airstack up # Start all services
airstack up robot-desktop # Start only robot
airstack down # Stop all services
# Manage
airstack status # Show running containers
airstack connect robot # Connect to container
airstack logs robot # View logs
# Pull/build images
docker compose pull # Pull from registry
docker compose build # Build from scratch
Pull Images¶
The AirLab docker registry (airlab-docker.andrew.cmu.edu) is public — no docker login is needed to pull:
The available image tags are listed here.
Pushing images still requires an AirLab account (docker login airlab-docker.andrew.cmu.edu first).
Build Images¶
For an overview of build-time options (BASE_IMAGE, ROS_DISTRO, platform profiles), see Docker Build Profiles. For runtime container operations, continue below.
# Build all images from scratch
docker compose build
# Build specific service
docker compose build robot
Isaac Sim¶
Start a bash shell in the Isaac Sim container:
# if the isaac container is already running, execute a bash shell in it
airstack connect isaac-sim # or equivalently: docker exec -it isaac-sim bash
Within the isaac-sim Docker container, the alias runapp launches Isaac Sim.
The --path argument can be passed with a path to a .usd file to load a scene.
It can also be run in headless mode (airstack up --sim isaac --headless) and accessed remotely via WebRTC streaming — see Isaac Sim Docker → Accessing Isaac Sim for the current access methods. (The Omniverse Streaming Client and runheadless.native.sh have been discontinued upstream.)
The container also has the isaacsim ROS2 package within that can be launched with ros2 launch isaacsim run_isaacsim.launch.py.
Robot¶
Start a bash shell in a robot container, e.g. for robot_1:
To launch more than one robot, use --robots — it sets NUM_ROBOTS and keeps the Isaac launch script consistent (a plain NUM_ROBOTS=2 airstack up with the single-drone default script is rejected by preflight, since only one drone would exist in sim):
airstack up --sim isaac --robots 2
airstack connect robot-1 # to connect to robot 1
airstack connect robot-2 # to connect to robot 2
Launch flags and readiness¶
airstack up accepts intent flags that derive the coordinated env-var sets for you (they override .env for that run without editing it). For example:
airstack up --sim isaac --robots 2 # simulator profile + matching URDF + multi-drone script
airstack up --no-autolaunch # idle containers, no tmux launch (development)
airstack up --headless --wait # no sim window; block until flight-ready
The full flags table (--play/--no-play, --dry-run, --stack, --fleet, --scene, ...) is in the CLI reference.
Every up prints the resolved launch config and saves it to .airstack/runs/<timestamp>/effective_config.env. Preflight validates the resolved values (one simulator profile, URDF pairing, robot-count/script consistency, missing images by name) before compose runs; AIRSTACK_SKIP_PREFLIGHT=1 downgrades errors to warnings.
airstack up returns as soon as containers start — workspaces may still be building and the sim loading. To wait for actual flight-readiness (containers → sim /clock → per-robot autonomy nodes → PX4 connected + EKF armable):
airstack ready # staged progress, per-gate diagnostics
airstack ready --json # machine-readable (last line), exit 0 when ready
With AUTOLAUNCH enabled (the default), each robot container launches the autonomy stack in a tmux session. To attach to the session within the docker container, e.g. to inspect output, run tmux a.
The following commands are available within the robot container:
# in robot docker
cws # cleans workspace
bws # builds workspace
bws --packages-select [your_packages] # builds only desired packages
sws # sources workspace
ros2 launch autonomy_bringup robot.launch.xml # top-level launch (dispatches the selected stack)
These aliases are defined in AirStack/robot/docker/.bashrc.
Each robot has ROS_DOMAIN_ID set to its ID number. ROBOT_NAME is set to robot_$ROS_DOMAIN_ID.
Ground Control Station¶
Currently the ground control station uses the same image as the robot container. This may change in the future.
Start a bash shell in a robot container:
The available aliases within the container are currently the same.
On the GCS ROS_DOMAIN_ID is set to 0.
SSH into Robots¶
The containers mimic the robots' onboard computers on the same network. Therefore we intend to interface with the robots through ssh.
The gcs and robot containers are set up with an ssh daemon, so you can ssh into the containers using the IP address.
You can get the IP address of each container by running the following command:
Then ssh in, for example (containers get addresses on the 172.31.0.0/24 bridge network; use the docker inspect command above to find the actual IP):
The ssh password is airstack.
Automated Testing¶
Automated testing is handled by the pytest-based test harness: run airstack test -m <mark> (e.g. airstack test -m unit -v) in a containerized runner. See the Testing docs and tests/README.md for the full mark reference and options.
Docker Compose Variable Overrides¶
As mentioned above, the airstack CLI is a wrapper around Docker Compose.
Therefore, it supports variable interpolation in the docker-compose.yaml file, allowing you to adjust project settings by modifying environment variables.
For settings that have a launch-intent flag, prefer the flag — it derives
the env vars for you (see the flag reference): --no-play
instead of PLAY_SIM_ON_START=false, --no-autolaunch instead of
AUTOLAUNCH=false, --robots N instead of NUM_ROBOTS=N, plus --sim,
--headless, --scene, --stack, and --fleet.
Environment variables remain the mechanism for everything without a
flag. For example, to run a custom Isaac Sim launch script (they live in
simulation/isaac-sim/launch_scripts/):
A list of all available environment variables is in the default .env file in the project root directory, which allows specifying all the variables in one place.
When no --env-file argument is passed to docker compose, it automatically uses this default .env file.
The default .env file is reproduced below:
# This is the main .env file for AirStack, which sets DOCKER COMPOSE VARIABLES FOR VARIABLE INTERPOLATION IN docker-compose.yaml.
# These variables do NOT get set within the robot container itself. For setting container environment variables, use env_file: attribute in docker-compose.yaml.
# Standard Usage: airstack up (reads this file automatically; flags like --sim/--robots override it — see `airstack help up`)
# Warning: even though this file is organized into sections, all variables get propagated to all sub-level
# docker-compose files, so be careful about naming conflicts.
# =============== PROJECT ====================
# THESE VARIABLES ARE USED TO TAG THE DOCKER IMAGES.
# The name of the project. This is used as the repository name for the docker images, and also as part of the default image tag.
PROJECT_NAME="airstack"
# If you've run ./airstack.sh setup, then this will auto-generate from the git commit hash every time a change is made
# to a Dockerfile or docker-compose.yaml file. Otherwise this can also be set explicitly to make a release version.
# auto-generated from git commit hash
VERSION="0.20.7"
# Image-tag discriminator ONLY (appears in the image tag suffix, e.g. ..._robot-x86-64_dev).
# No Dockerfile consumes it: "prebuilt" does NOT bake the built ros_ws into the image today —
# a real prebuilt (workspace-baked) stage is future work. Keep "dev" (mounted code, built live).
DOCKER_IMAGE_BUILD_MODE="dev"
# Where to push and pull images from. Can replace with your docker hub username if using docker hub.
PROJECT_DOCKER_REGISTRY="airlab-docker.andrew.cmu.edu/airstack"
# This is the default profile that docker compose will use if you just run `docker compose up` without specifying a profile.
# It can be overridden with the --profile flag, or by setting the COMPOSE_PROFILES environment variable to a different value
# before running `docker compose up`.
COMPOSE_PROFILES="desktop,isaac-sim"
# ============================================
# ================= Common ===================
AUTOLAUNCH="true" # If false, the docker-compose will just spawn idle docker containers with no launch command.
NUM_ROBOTS="1" # Number of robot containers to launch.
RECORD_BAGS="false" # "true" or "false"
# ============== ISAAC SIM =====================
ISAAC_SIM_GUI="/isaac-sim/AirStack/simulation/isaac-sim/assets/scenes/simple_pegasus.scene.usd"
# Set to "true" to launch Isaac Sim using a standalone Python script instead of USD file
ISAAC_SIM_USE_STANDALONE="true" # "true" or "false"
# Script name (must be in /AirStack/simulation/isaac-sim/launch_scripts/)
ISAAC_SIM_SCRIPT_NAME="example_one_px4_pegasus_launch_script.py"
PLAY_SIM_ON_START="true" # Sim starts PLAYING by default (launch with `airstack up --no-play` to come up paused).
# Scene to load, set by `airstack up --scene <shortname>` (see simulation/scenes.yaml
# for shortnames). Can also be set directly to a Pegasus SIMULATION_ENVIRONMENTS
# key or a USD URL. Empty = the launch script's default (Default Environment).
# ISAAC_SIM_SCENE="Warehouse"
# ISAAC_SIM_STAGE_SCALE="1.0" # scale applied to /World/stage (0.01 for cm-authored stages)
# ===============================================
# ================= MS-AIRSIM =====================
# Scene to run, set by `airstack up --scene <shortname>` (see simulation/scenes.yaml).
# A fetch_scene.sh key; the pre-built UE4 binary is auto-fetched if absent.
# Empty = blocks. Ignored when MS_AIRSIM_BINARY_PATH is set.
# MS_AIRSIM_SCENE="blocks"
# Do not set if you want airstack to fetch a simple blocks world.
# MS_AIRSIM_ENV_DIR=./simulation/ms-airsim/assets/scenes
# MS_AIRSIM_BINARY_PATH="/ms-airsim-env/Blocks/LinuxNoEditor/Blocks.sh"
# =================================================
# ================= ROBOT =====================
ROBOT_NAME_MAP_CONFIG_FILE="default_robot_name_map.yaml" # Determines how to set ROBOT_NAME and ROS_DOMAIN_ID. See robot/docker/robot_name_map/
URDF_FILE="robot_descriptions/iris/urdf/iris_with_sensors.pegasus.robot.urdf"
DEBUG_RVIZ="false" # "true" or "false". If true, launches RViz alongside the robot via desktop_bringup/robot.launch.xml.
# offboard API streaming out. this is so that ports don't conflict for multi-agent FCU communication.
OFFBOARD_BASE_PORT=14540
ONBOARD_BASE_PORT=14580
To override the default .env file, you can pass the --env-file argument with the syntax airstack --env-file [env_file] up (or docker compose --env-file [env_file] up -d).
Multiple --env-file arguments can be passed to compose overriding sets of variables.env files.
All subsequent --env-file arguments override the previous ones, allowing you to layer configurations.