Skip to content

Docker Environment

The Docker container is the alternative to the native pixi workflow. There are two ways to use it:

  1. Dev Container (VS Code) — uses the dev stage of the Dockerfile with dev tooling pre-installed. Open the repo in VS Code and choose Reopen in Container.
  2. Standalone container (docker-compose) — uses the runtime stage for running simulations on any host without VS Code. NVIDIA GPU passthrough is enabled automatically when hardware is detected.

The Dockerfile at docker/Dockerfile has two stages:

FROM ros:jazzy-ros-base AS runtime # simulation + VNC/display stack
FROM runtime AS dev # + dev tooling (ruff, onshape-to-robot, shfmt)

Everything needed to run simulations:

ros:jazzy-ros-base (Ubuntu Noble 24.04 + ROS 2 Jazzy)

Simulation stack:

PackagePurpose
Gazebo HarmonicPhysics simulation engine
ros-jazzy-ros-gzROS 2 / Gazebo integration + bridge
ros-jazzy-ros2-controllersJoint state broadcaster + trajectory controller
ros-jazzy-gz-ros2-controlHardware interface for Gazebo
ros-jazzy-rviz2Robot visualization
ros-jazzy-xacroURDF macro processing
ros-jazzy-joint-state-publisher-guiJoint state publishing GUI

Display stack (headless GUI):

PackagePurpose
xserver-xorg-core + xserver-xorg-video-dummyVirtual X server with dummy driver (no GPU)
openboxLightweight window manager
x11vncVNC server for remote X11 access
novnc + websockifyBrowser-based VNC client
xvfbVirtual framebuffer for Jetson/Tegra (no DRI)
mesa-utils, libgl1-mesa-driSoftware OpenGL rendering

Build tools:

PackagePurpose
python3-colcon-common-extensionsROS 2 workspace build system
python3-rosdepROS dependency installer
gitVersion control

Adds on top of runtime:

PackagePurpose
ruffPython linter
onshape-to-robotCAD-to-URDF conversion (used by sim create)
open3dSTL mesh decimation
shfmtShell script formatter

The container runs as a non-root user trickfire with passwordless sudo:

RUN useradd trickfire --shell /bin/bash --create-home
RUN echo "trickfire ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/user

The devcontainer.json configures how VS Code opens the container:

Build target: dev stage of docker/Dockerfile

Workspace mount: The repo is bind-mounted into the container at /home/trickfire/gazebo-simulations.

Compose config: .devcontainer/devcontainer.json uses docker/docker-compose.yml plus .devcontainer/docker-compose.devcontainer.yml. The override only switches the build target to dev; the base compose file starts the X server / VNC stack automatically.

Port forwarding: Ports 6080 (noVNC) and 5900 (VNC) are forwarded to the host.

Privileged mode: The container runs with --privileged and device access for hardware interaction (USB, CAN bus).

X11 forwarding: The devcontainer relies on the Compose-managed VNC desktop. The standalone GPU compose stack can still mount /tmp/.X11-unix when you want host X11 rendering.

VS Code extensions: Pre-installs Python, C++, ROS, URDF, Docker, formatting, and docs (Astro/MDX) extensions.

Xorg/Xvfb → x11vnc → websockify → Browser
↑ ↑
Openbox WM noVNC client
↑ (port 6080)
Gazebo / RViz

Alternatives like Xvfb don’t support GLX properly, which means Gazebo’s 3D rendering fails. Using Xorg with a dummy driver + Mesa software rendering gives us full OpenGL support without needing a real GPU. The VNC + noVNC layer makes it accessible from any browser. On Jetsons, we fall back to Xvfb because there’s no /dev/dri, but GPU rendering still works via EGL through injected Tegra libs.

VariableValueSet in
DISPLAYHost-dependentdocker-compose.yml (standalone)
VNC_PORT5900Dockerfile
NOVNC_PORT6080Dockerfile

To add system packages, edit docker/Dockerfile and rebuild. For Python packages, add them to the pip3 install section in the appropriate stage (runtime for things needed at simulation time, dev for development-only tools).

After changing the Dockerfile, use Dev Containers: Rebuild Container in VS Code’s Command Palette.