The O3DE 24.09.1 Release is here! DOWNLOAD NOW
NEWS & BLOGS | Member Blog

Running robotic simulations using Docker Images

15 Jan, 2025 | 4 min read

Written by Steve Pham, Senior Software Development Engineer at Amazon and contributor to the O3DE community

This article originally ran on Steve’s O3DE blog. For more content like this, click here.

Distributing Simulation Projects

For robotics simulation projects using ROS2 and O3DE, collaboration on constructing and refining the simulation can be shared across a team through source control such as GIT or Perforce. However, in order to access, develop, and contribute to the simulation project, you need an environment that has O3DE, ROS2, and its dependencies installed and configured properly. The environment must also be consistent for every member of the team collaborating on the simulation. In my previous blog post, I explained how Amazon’s EC2 helps provide a pre-configured environment through an AWS Marketplace AMI.

The primary goal of simulations is for training robots through ROS2. The O3DE Editor is not needed to run the simulation, it can be launched through a separate launcher application. The same development environment is not necessary either. Once the simulation project is ready for distribution, it can be exported into the launcher application separate from the O3DE Editor and build environment. Exporting a simulation project into its own launcher will package just the launcher executable and its bare minimum dependent binaries, assets, and necessary settings needed to launch the simulation. All the additional Editor and Asset Processor related binaries that comes with a full O3DE installation is omitted.

Containerization

The exported project alone usually is not enough to have it run on different machines. Along with the base operating system (in this case, Ubuntu Linux) there are additional pre-requisite package requirements. In order to have the simulation project run consistently across different machines, each machine must have the same operating system, packages, and environment. We will use Containerization to address this issue. This provides many benefits for our use case:

Portability

The simulation project will be contained in its own isolated environment and operating system. The specific operating system, Ubuntu 22.04, and all of its required packages will be embedded in the container image and isolated from the host machine. That means no additional simulation-specific prerequisites are needed to launch the simulation (other than the Container service and the NVIDIA Container Toolkit). This allows it to run on multiple devices and operating systems.

Consistency

Container images are immutable. This ensures that the application will run in a consistent manner across any environment or operating system.

Scalability

Containers are lightweight and run efficiently. Unlike virtual machines, they do not need to boot up to load the operating system. Containers can be easily distributed and managed through container orchestration tools as well.

Exporting the Project

Once the simulation project is working as expected through the Editor and from command line, we can use O3DE to export the project to a single folder. Open Project Manager, click on the context button for the project MyRobotSimulation and click on Open Export Settings…

O3DE Project Manager

This brings up the export settings specific to this project. Next, we configure the settings needed to export just the simulation (game) launcher.

Export Setting

The export settings is designed for any type of project, not just simulations. There’re only a few settings needed to create our simulation launcher:

Project Build Configuration profile
Build Assets true
Level Names DemoLevel
Max Size 2048
Asset Bundling Path build/asset_bundling
Archive Format none
Build Game Launcher true
Build Server Launcher false
Build Unified Launcher false
Build Headless Server Launcher false

Once the configuration is set, click on Save to save the settings. To run the project export, click on the context menu button for the project again, and click on Export Launcher->Linux

Export Linux

When the process is complete, the exported project will be located in a folder named MyRobotSimulationGamePackage in the path ~/O3DE/Projects/MyRobotSimulation/build/export/

Creating a Docker Image

The exported project can now be stored into a compressed archive and distributed to other Ubuntu 22.04 hosts to use. However, the exported project still requires the minimal environment and settings to run successfully and consistently. We will create an OCI Complaint container Image for the environment and settings, and include the exported project and the sample navigation scripts for ROS and RViz. We will use Docker Engine in conjunction with the NVIDIA Container toolkit to build and test the image.

Installing Docker Engine

Install Docker Engine for Ubuntu using the Docker Installation instructions. The following is a quick cheat-sheet to install Docker Engine using the apt repository based on the Docker’s apt instructions.

1. Set up Docker’s apt repository

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

2. Install the Docker packages

sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

3. Create a docker group (if not already created). Add the current user to the docker group

sudo groupadd docker

sudo usermod -aG docker $USER

newgrp docker

4. Verify that you can run Docker without sudo by running the hello-world image.

docker run hello-world

Note: If you run into any issues during these steps, refer to the Docker Installation instructions for help.

Installing NVIDIA Container Toolkit

In addition to Docker Engine, you will need the NVIDIA Container toolkit in order to run the simulation within the Docker Image. The following is another quick cheat-sheet to installing the toolkit based on NVIDIA’s apt instructions.

1. Set up NVIDIA’s production repository

curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
  && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
    sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

2. Update the package list from the repository

sudo apt-get update

3. Install the toolkit from apt

sudo apt-get install -y nvidia-container-toolkit

4. Configure the toolkit for Docker (rootless)

nvidia-ctk runtime configure --runtime=docker --config=$HOME/.config/docker/daemon.json

systemctl --user restart docker

sudo nvidia-ctk config --set nvidia-container-cli.no-cgroups --in-place

Create the Docker Image

Dockerfile is the recipe for the Docker Engine to build an image. The Docker Image will include the minimal required packages for O3DE launchers and ROS2, based on the type of simulation that MyRobotSimulation was built for. Docker uses a path to refer to as its context root, and in our example, we will use the root of the simulation project (~/O3DE/Projects/MyRobotSimulation/).

1. Create a Dockerfile

Navigate to the path ~/O3DE/Projects/MyRobotSimulation/build/export/ and create a file named Dockerfile with the following contents:


# This image will be based on ROS's ros humble base image
FROM ros:humble-ros-base-jammy

ENV WORKSPACE=/data/workspace

WORKDIR $WORKSPACE

RUN apt-get update && apt-get upgrade -y

# Get the necessary packages needed for the simulation launcher
RUN apt-get install -y --no-install-recommends libglu1-mesa \
                       libfontconfig1 \
                       libxcb-image0 \
                       libxcb-keysyms1 \
                       libxcb-render-util0 \
                       libxcb-randr0 \
                       libxcb-xinerama0 \
                       libxcb-xinput0 \ 
                       libxcb-xkb1 \
                       libxcb-xfixes0 \
                       libxkbcommon-x11-0 \
                       libunwind8 \ 
                       libxcb-icccm4 \
                       libnvidia-gl-470 \
                       ros-${ROS_DISTRO}-slam-toolbox \
                       ros-${ROS_DISTRO}-navigation2 \
                       ros-${ROS_DISTRO}-nav2-bringup \
                       ros-${ROS_DISTRO}-pointcloud-to-laserscan \
                       ros-${ROS_DISTRO}-gazebo-msgs \
                       ros-${ROS_DISTRO}-ackermann-msgs \
                       ros-${ROS_DISTRO}-rmw-cyclonedds-cpp \
                       ros-${ROS_DISTRO}-control-toolbox \
                       ros-${ROS_DISTRO}-nav-msgs \
                       ros-${ROS_DISTRO}-rviz2 \
    && rm -rf /var/lib/apt/lists/* 

# Copy over the exported project into this image
COPY build/export/MyRobotSimulationGamePackage $WORKSPACE/Simulation
COPY Examples/slam_navigation/launch $WORKSPACE/launch

# Enable the necessary environments for the NVIDIA toolkit and ROS2
ENV NVIDIA_VISIBLE_DEVICES=all
ENV NVIDIA_DRIVER_CAPABILITIES=all
ENV RMW_IMPLEMENTATION=rmw_cyclonedds_cpp 

2. Build the Docker image

Once the Dockerfile recipe is saved, use Docker’s command line tool to build an OCI-compliant container image. Name the image my_robot_simulation (Docker is case-sensitive and does not allow for mixed casing in the name) and use the latest tag for our sample.

Use the following command to build the image.

docker build -t my_robot_simulation:latest ~/O3DE/Projects/MyRobotSimulation -f ~/O3DE/Projects/MyRobotSimulation/build/export/Dockerfile

3. Test the Docker Image locally

Before uploading and distributing the Docker Image, test it locally by running in through Docker Engine and using the NVIDIA Container Toolkit.

In order for the image to have access to the local display, you need to add it to xhost.

xhost +local:root

To launch the simulation through Docker, run the following command

docker run --rm --gpus all -e DISPLAY=:1 -v /tmp/.X11-unix:/tmp/.X11-unix my_robot_simulation:latest /data/workspace/Simulation/MyRobotSimulation.GameLauncher

While the simulation is running from the Docker Image, you can now connect to it through ROS2 using the sample navigation example from the MyRobotSimulation project (as described in the previous blog). Open up a new terminal and enter the following lines.

cd ~/O3DE/Projects/MyRobotSimulation/Examples

ros2 launch slam_navigation/launch/navigation.launch.py

Publish the Docker Image

Docker Images do not upload to a repository the same way as regular files or archives do. Instead, they rely on OCI-Compliant container registries. For this example, we will use Amazon Elastic Container Registry (ECR) to upload and distribute our Docker image.

Note: As with the AWS EC2 instance from the previously blog, we will be using the same Amazon account login for ECR

Before starting, make sure that you have the AWS CLI installed using the following command:

sudo apt install awscli

Make sure that you have your AWS credentials and region setup running aws configure

1. Create a repository called my_robot_simulation

Run the following command from the terminal to create a repository called ‘my_robot_simulation’

aws ecr create-repository --repository-name my_robot_simulation

Note: Docker enforces a strict naming convention, and does not allow for mixed casing in the name.

You should get a response similar to the following:

{
    "repository": {
        "repositoryArn": "arn:aws:ecr:us-west-2:000000000000:repository/my_robot_simulation",
        "registryId": "000000000000",
        "repositoryName": "my_robot_simulation",
        "repositoryUri": "000000000000.dkr.ecr.us-west-2.amazonaws.com/my_robot_simulation",
        "createdAt": 1734476138.426,
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": false
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
}

Note the repositoryUri value and set it to an environment variable for convenience, for example:

export ECR_SIMULATION_URI=000000000000.dkr.ecr.us-west-2.amazonaws.com/my_robot_simulation

2. Log into Amazon ECR with the following command

aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_SIMULATION_URI

You should see a message saying Login Succeeded

3. Tag the local Docker Image for the simulation to the repository URI

docker tag my_robot_simulation $ECR_SIMULATION_URI

4. Push the local Docker Image to the Amazon ECR for your account.

docker push $ECR_SIMULATION_URI

This will begin the process to push the Docker Image to ECR. Once the process is done, you can view and verify that the image has been uploaded to your account. Log into your AWS console and go to the Amazon ECR dashboard, and click on Repositories. You should see the new my_robot_simulation repository under Private repositories.

Export Linux

Running Docker Image on other machines

With the Docker Image stored in your Amazon ECR account, you can distribute and run the image on any Linux host provided that it has Docker Engine, NVIDIA Container Toolkit, and the AWS CLI installed (refer to the Installing Docker Engine section earlier). For this example, we will continue to use Docker Engine but from a different Ubuntu Linux host.

You will need to authenticate to the AWS account where the Image has been uploaded and registered to. The user or IAM must have the right permission to pull and run the image. Also, the repository URI from the publish steps above is needed to identify the Image to download. You can also get the URI from the AWS console.

1. Set the Repository URI and log into AWS

For convenience, set an environment variable to the URI for the Docker Image.

export ECR_SIMULATION_URI=000000000000.dkr.ecr.us-west-2.amazonaws.com/my_robot_simulation

Once logged into your AWS account using the same aws configure steps above, you can pull the Docker Image based on the repository URI. Then get the login password for your ECR and send it to the docker login

aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_SIMULATION_URI

2. Pull the Docker Image

Pull the Docker Image from ECR to the local Docker Engine. This will make the Image ready to run.

docker pull $ECR_SIMULATION_URI:latest

Note: If this step is omitted, the first attempt to run the image will perform the pull operation anyways.

3. Launch the Docker Image

Once the Docker Image is pulled to your local Docker Engine, launch the image. We will be using the ROS2 environment embedded in the Docker Image, so instead of running the simulation directly, we will log into the Docker Image’s bash terminal with the following commands:

xhost +local:root

docker run --rm --gpus all -e DISPLAY=:1 -v /tmp/.X11-unix:/tmp/.X11-unix -it $ECR_SIMULATION_URI:latest /bin/bash

Once logged into the Docker Image, launch the simulation as a background process and redirect the output to a log file:

/data/workspace/Simulation/MyRobotSimulation.GameLauncher > simuation.log 2>&1 &

This will launch the simulation client in a new window on your host machine. Wait until the client initializes and shows the warehouse scene to ensure that the simulation has started, and run the following command to launch the rviz tool to connect.

ros2 launch /data/workspace/launch/navigation.launch.py

You will now be able to see the RViz client connected to the simulation.

Tearing Down

Once we are done with distributing the simulation, we can remove it from Amazon ECR. The cost that Amazon ECR incurs is based on the storage that is used by the Docker Image ($0.10 USD per GB/Month). The image constructed with this blog takes up about 1.7 GB of storage, which translates to about $0.17 USD per month. To delete the ECR image, log into your AWS console and navigate to the Amazon ECR dash board. Locate the my_robot_simulation under Private registry->Repositories. Select it and click the Delete button.

Conclusion

In this blog, we introduced a portable and consistent approach to distributing an O3DE simulation project to different machines. We took the sample robotic simulation project we created in a previous blog post and exported the simulation as a separate package. We used this exported package to build an OCI compliant container image using Docker Engine and published it to a container registry using Amazon ECR. Finally, we demonstrated how to pull and run the simulation Docker Image using Docker Engine and NVIDIA container toolkit.

Keep up to date with O3DE:

Subscribe for the latest updates, events, webinars and community news