Skip to content

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

2 watching

Forks

Latest commit

 

History

9 Commits

Folders and files

Repository files navigation

From Containers to Robots: Understanding Docker for ROS and ROS2 Development

The first part of the session covers Docker fundamentals: how to create images, manage containers, and configure networks between applications. The second part focuses on deploying ROS and ROS2 inside containers, demonstrating how Docker simplifies experimentation, teaching setups, and development workflows. The session will also show how Docker can help bridge ROS and ROS2, easing the migration process between the two frameworks.

CHAPTER 0 -- Install Docker

Linux

Ubuntu-based

  1. Update your existing packages:

    sudo apt update
    sudo apt upgrade -y
  2. Install required packages:

    sudo apt install apt-transport-https ca-certificates curl software-properties-common -y
  3. Add Docker’s official GPG key:

    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg
  4. Add the Docker repository:

    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
      $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  5. Install Docker Engine:

    sudo apt update
    sudo apt install docker-ce docker-ce-cli containerd.io -y
  6. Verify installation:

    docker --version

Fedora-based

  1. Remove old Docker versions (if any):

    sudo dnf remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
  2. Install dependencies:

    sudo dnf -y install dnf-plugins-core
  3. Add the Docker repository:

    sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
  4. Install Docker Engine:

    sudo dnf install docker-ce docker-ce-cli containerd.io -y
  5. Start and enable Docker:

    sudo systemctl start docker
    sudo systemctl enable docker
  6. Verify installation:

    docker --version

Arch-based

  1. Update your system:

    sudo pacman -Syu
  2. Install Docker:

    sudo pacman -S docker
  3. Start and enable the Docker service:

    sudo systemctl start docker
    sudo systemctl enable docker
  4. (Optional) Run Docker without sudo:

    sudo usermod -aG docker $USER
    newgrp docker
  5. Verify installation:

    docker --version

NixOS

  1. Add Docker to your NixOS configuration. Edit /etc/nixos/configuration.nix and enable Docker:

    services.docker.enable = true;
  2. Apply the configuration:

    sudo nixos-rebuild switch
  3. (Optional) Allow your user to run Docker without sudo. Add your username to the docker group:

    users.users.yourusername.extraGroups = [ "docker" ];

    Then rebuild again:

    sudo nixos-rebuild switch
  4. Verify installation:

    docker --version

Windows

  1. Download Docker Desktop for Windows from the official Docker site: 👉 https://www.docker.com/products/docker-desktop/

  2. Run the installer and follow the setup wizard.

  3. Ensure WSL 2 (Windows Subsystem for Linux) is enabled. If not, Docker Desktop will guide you through enabling it.

  4. After installation, restart your machine if required.

  5. Verify installation by opening PowerShell or Command Prompt:

    docker --version

macOS

  1. Download Docker Desktop for Mac from the official Docker site: 👉 https://www.docker.com/products/docker-desktop/

  2. Open the .dmg file and drag Docker to your Applications folder.

  3. Launch Docker Desktop from Applications.

  4. Follow the setup wizard and grant permissions if prompted.

  5. Verify installation:

    docker --version

Post-installation Steps

After installing Docker, it’s a good idea to verify everything works correctly.

  1. Check the Docker service status (Linux only):

    sudo systemctl status docker

    If it’s not running, start it:

    sudo systemctl start docker
  2. Run the Docker “Hello World” test image:

    docker run hello-world
    • If Docker is installed correctly, you’ll see a message:

      Hello from Docker!
      This message shows that your installation appears to be working correctly.
      
  3. Download Docker images that are going to be used in this workshop (saves time)

    docker pull ubuntu:latest ubuntu:20.04 jupyter/scipy-notebook theasp/novnc:latest alpine nginxdemos/hello ollama/ollama:0.11.5-rc5 ghcr.io/open-webui/open-webui:main osrf/ros:noetic-desktop-full-focal osrf/ros:jazzy-desktop-full mjpc13/foxglove-bridge andrejorsula/ros1_bridge:foxy
    

CHAPTER 1 -- Creating and interacting with Docker Containers

Creating our first Dockerfile

Simple Ubuntu Neofetch

Create a simple Dockerfile:

#Dockerfile
FROM ubuntu

RUN apt-get -y update && apt-get -y install neofetch

CMD [ "neofetch" ]

Build the docker image with:

docker build -t docker-tutorial .

And create and run the container:

docker run --rm docker-tutorial

Pin Ubuntu version

What if we want a specific Ubuntu version? In the Dockerfile replace FROM ubuntu with FROM ubuntu:20.04:

#Dockerfile
FROM ubuntu:20.04

RUN apt-get -y update && apt-get -y install neofetch

CMD [ "neofetch" ]

and build again the new image:

docker build -t docker-tutorial .

And create and run the container:

docker run --rm docker-tutorial

Public available images are usually found in DockerHub.

How to interact with a Docker Container?

Create a new environmental variable, append to a file and print it to the console:

#Dockerfile
FROM ubuntu:20.04

RUN apt-get -y update && apt-get -y install neofetch nano

ENV VAR1="HELLO WORLD!!!"

WORKDIR /workspace

RUN echo "We just wrote $VAR1" >> example.txt

CMD [ "cat", "example.txt" ]

build again the Docker image:

docker build -t docker-tutorial .

and run it:

docker run docker-tutorial

Copy files from host to inside a container

Create a new .txt file in the same directory as the Dockerfile;

You use the COPY command to copy files:

#Dockerfile
FROM ubuntu:20.04

RUN apt-get -y update && apt-get -y install neofetch nano

ENV VAR1 "HELLO WORLD!!!"

WORKDIR /workspace

COPY example.txt example.txt

CMD [ "cat", "example.txt" ]

and run it:

docker run docker-tutorial

Edit the container

Jump into a bash session:

docker run -it docker-tutorial bash

Edit the file (add some lines or delete characters), with either:

  1. With nano: nano example.txt
  2. Append some text to it: echo "\n I am too lazy to edit the file myself" >> example.txt

Mounting volumes

Mount directory example_dir into a docker container:

docker run -it --rm -v example_dir:/workspace/my_dir docker-tutorial bash

Docker CLI

The Docker CLI is the main way to interact with Docker. Below are some of the most useful commands:

  • Check version

    docker --version

    Shows the installed Docker version.

  • List images

    docker images

    Displays downloaded container images.

  • Download an image

    docker pull <image>

    Fetches an image from Docker Hub.

  • Run a container

    docker run <image>

    Creates and starts a new container from an image.

  • List running containers

    docker ps

    Shows active containers.

  • List all containers (including stopped)

    docker ps -a
  • Stop a container

    docker stop <container_id>
  • Remove a container

    docker rm <container_id>
  • Remove an image

    docker rmi <image_id>
  • View logs of a container

    docker logs <container_id>

CHAPTER 2 -- Use Applications inside Docker

Web Applications

Run a Jupyter scipy-notebook:

docker run --rm --name jupyter-scipy -p 8000:8888 jupyter/scipy-notebook

GUI applications

X11 Server (Linux only)

Create a Dockerfile with a gui application:

#Dockerfile
FROM ubuntu:20.04

RUN apt-get -y update && apt-get -y install x11-apps

CMD [ "xeyes" ]

build the image:

docker build -t vis-tutorial .

run a container:

docker run -it --rm --env="DISPLAY" --env="QT_X11_NO_MITSHM=1" --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" vis-tutorial

If you have the error Error: Can't open display: :0 you need to run the following command:

xhost +local:root

Watch the application in localhost

Local VNC Docker Compose

To use a VNC server we need to start multiple containers at a time. We can use Docker Compose to easily manage multiple containers.

Now we are starting multiple containers at a time:

#docker-compose.yaml

# Creates a network
networks:
  vnc-net:
    name: vnc-net

services:
  #Creates and runs the VNC server
  novnc:
    image: theasp/novnc:latest
    container_name: novnc
    ports:
      - "8085:8080"
    environment:
      DISPLAY_WIDTH: 3000
      DISPLAY_HEIGHT: 1800
      RUN_XTERM: "no"
    networks:
      - vnc-net
    restart: unless-stopped

  # Runs the xeyes application
  xeyes:
    image: vis-tutorial
    container_name: xeyes
    networks:
      - vnc-net
    depends_on:
      - novnc

Run the compose file with:

docker compose up

CHAPTER 3 -- Networking in Docker

Bridge

The docker-compose.yaml example:

# Creates a network
networks:
  example-net:

services:
  #Pings APP2 from APP1
  app1:
    image: alpine
    container_name: app1
    networks:
      - example-net
    command: ["ping", "app2"]
    
  #Pings APP1 from APP2
  app2:
    image: alpine
    container_name: app2
    networks:
      - example-net
    command: ["ping", "app1"]

Host

The docker-compose.yaml example:

services:
  web-server:
    image: nginxdemos/hello
    container_name: web-host
    network_mode: "host"

CHAPTER 4 -- Final Example

Ollama Dockerfile with a light LLM (tinyllama):

FROM ollama/ollama:0.11.5-rc5

RUN ollama pull tinyllama

#RUN ollama serve & sleep 5 ; ollama pull tinyllama ; \
#    echo "kill 'ollama serve' process" ; \
#    ps -ef | grep 'ollama serve' | grep -v grep | awk '{print $2}' | xargs -r kill -9
networks:
  ollama-net:

services:
  ollama:
    build:
      context: .
      dockerfile: Dockerfile 
    networks:
      - ollama-net

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    networks:
      - ollama-net
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434

CHAPTER 5 -- ROS in Docker

ROS1

#Dockerfile
FROM osrf/ros:noetic-desktop-full-focal

ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHON_VERSION=python3
ENV ROS_WS=/catkin_ws


### INSTALL DEPENDENCIES ###
RUN apt-get update \
  && apt-get install -y curl git \
  ros-$ROS_DISTRO-roscpp-tutorials \
  ros-$ROS_DISTRO-rosbridge-suite \
  ${PYTHON_VERSION}-catkin-tools

### END INSTALL DEPENDENCIES ###
SHELL ["/bin/bash", "-l", "-c"]
WORKDIR ${ROS_WS}

Talker/Listener

#docker-compose.yaml
networks:
  ros1-net:

services:
  master:
    image: osrf/ros:noetic-desktop-full-focal
    container_name: master
    networks:
      - ros1-net
    command: "roscore"

  talker:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: ros1-talker
    environment:
      - ROS_MASTER_URI=http://master:11311
    depends_on:
      - master
    networks:
      - ros1-net
    command: ["rosrun", "roscpp_tutorials", "talker"]    
    
  listener:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: ros1-listener
    environment:
      - ROS_MASTER_URI=http://master:11311
    depends_on:
      - master
    networks:
      - ros1-net
    command: ["rosrun", "roscpp_tutorials", "listener"]

  ros-bridge:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: ros-bridge
    environment:
      - ROS_MASTER_URI=http://master:11311
    depends_on:
      - master
    networks:
      - ros1-net
    ports:
      - "9090:9090"
    command: ["roslaunch", "rosbridge_server", "rosbridge_websocket.launch", "--wait"]

ROS2

#Dockerfile
FROM osrf/ros:jazzy-desktop-full

ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHON_VERSION=python3

SHELL ["/bin/bash", "-c", "-l"]

# Install required tools and dependencies
RUN apt update && apt install -y \
    ros-$ROS_DISTRO-example-interfaces \
    ros-$ROS_DISTRO-ros-testing \
    ${PYTHON_VERSION}-colcon-common-extensions \
    git \
    && rm -rf /var/lib/apt/lists/*

Talker/Listener

#docker-compose.yaml
networks:
  ros2-net:

services:
  talker:
    build:
      context: .
      dockerfile: Dockerfile
    networks:
      - ros2-net
    command: ["ros2", "run", "demo_nodes_cpp", "talker"]
  listener:
    build:
      context: .
      dockerfile: Dockerfile
    networks:
      - ros2-net
    command: ["ros2", "run", "demo_nodes_cpp", "listener"]

  foxglove-bridge:
    image: mjpc13/foxglove-bridge
    networks:
      - ros2-net
    ports:
      - "9092:8765"

Developing in Docker

#Dockerfile

###########################################
# BASE Image for TurtleBot3 Tutorial #
###########################################
FROM osrf/ros:jazzy-desktop-full AS base

ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHON_VERSION=python3

### INSTALL DEPENDENCIES ###
RUN apt-get update \
  && apt-get install -y curl git wget \
  ros-$ROS_DISTRO-ros-gz  \
  ros-$ROS_DISTRO-cartographer ros-$ROS_DISTRO-cartographer-ros \
  ros-$ROS_DISTRO-navigation2 \
  ros-$ROS_DISTRO-nav2-bringup \
  ${PYTHON_VERSION}-vcstool

RUN echo '#!/bin/bash\n\
    set -e\n\
    # Source ROS2\n\
    source /opt/ros/$ROS_DISTRO/setup.bash\n\
    # Build TurtleBot3 workspace if it exists\n\
    if [ -d /turtlebot3_ws/src ]; then\n\
        cd /turtlebot3_ws\n\
        colcon build --symlink-install\n\
        source install/setup.bash\n\
    fi\n\
    # Build your development workspace if it exists\n\
    if [ -d /devel_ws/src ]; then\n\
        cd /devel_ws\n\
        colcon build --symlink-install\n\
        source install/setup.bash\n\
    fi\n\
    exec "$@"' > /entrypoint.sh && chmod +x /entrypoint.sh

ENTRYPOINT [ "/entrypoint.sh" ]


###########################################
# OVERLAY IMAGE for TurtleBot3 Simulation #
###########################################

FROM base AS overlay

WORKDIR /turtlebot3_ws

RUN /bin/bash -c " \
    mkdir src/ && \
    wget https://raw.githubusercontent.com/ROBOTIS-GIT/turtlebot3/refs/heads/main/turtlebot3.repos && \
    vcs import src < turtlebot3.repos && \
    source /opt/ros/$ROS_DISTRO/setup.bash && \
    colcon build --symlink-install"

ENTRYPOINT [ "/entrypoint.sh" ]
CMD [ "ros2", "launch", "turtlebot3_gazebo", "turtlebot3_house.launch.py" ]

###############################################
# Development Image for TurtleBot3 Simulation #
###############################################
FROM base AS devel 

WORKDIR /devel_ws

# Dev container arguments
ARG USERNAME=devuser
ARG UID=1000
ARG GID=${UID}

# Install extra tools for development
RUN apt-get update && apt-get install -y --no-install-recommends \
 gdb gdbserver nano vim

# Create new user and home directory
RUN groupadd --gid $GID $USERNAME \
 && useradd --uid ${GID} --gid ${UID} --create-home ${USERNAME} \
 && echo ${USERNAME} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${USERNAME} \
 && chmod 0440 /etc/sudoers.d/${USERNAME} \
 && mkdir -p /home/${USERNAME} \
 && chown -R ${UID}:${GID} /home/${USERNAME}

# Set the ownership of the overlay workspace to the new user
RUN chown -R ${UID}:${GID} /turtlebot3_ws/

# Set the user and source entrypoint in the user's .bashrc file
USER ${USERNAME}
RUN echo "source /entrypoint.sh" >> /home/${USERNAME}/.bashrc

docker-compose.yaml:

#docker-compose.yaml
networks:
  ros2-net:

services:
  #ROS2
  turtlebot3:
    image: turtlebot3_test:overlay
    build:
      context: .
      dockerfile: Dockerfile
      target: overlay
    environment:
      - GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:/turtlebot3_ws/src/turtlebot3/turtlebot3_simulations/turtlebot3_gazebo/models
      - TURTLEBOT3_MODEL=waffle_pi
      - DISPLAY=novnc:0.0
    depends_on:
      - novnc
    networks:
      - ros2-net
    command: [ "ros2", "launch", "turtlebot3_gazebo", "turtlebot3_world.launch.py" ]
  
  #Creates and runs the VNC server
  novnc:
    image: theasp/novnc:latest
    container_name: novnc
    ports:
      - "9093:8080"
    environment:
      DISPLAY_WIDTH: 3000
      DISPLAY_HEIGHT: 1800
      RUN_XTERM: "no"
    networks:
      - ros2-net

  #Foxglove Bridge to vizualize topics from ROS2
  foxglove-bridge:
    image: mjpc13/foxglove-bridge
    networks:
      - ros2-net
    ports:
      - "9092:8765"

  turtlebot3-slam:
    extends: turtlebot3
    networks:
      - ros2-net
    command: [ "ros2", "launch", "turtlebot3_cartographer", "cartographer.launch.py", "use_sim_time:=True"]

  turtlebot3-devel:
    image: turtlebot3_test:devel
    build:
      context: .
      dockerfile: Dockerfile
      target: devel
    volumes:
      - ./devel_ws:/devel_ws
    networks:
      - ros2-net
    command: ["ros2", "launch", "turtlebot_explorer", "explorer_launch.py"]

Bridge ROS1 and ROS2 in Docker

networks:
  ros1-net:
  ros2-net:

services:
  #ROS1 SERVICES
  ros1-master:
    image: osrf/ros:noetic-desktop-full-focal
    networks:
      - ros1-net
    command: "roscore"
  ros1-talker:
    build:
      context: ../01_ros1/
      dockerfile: Dockerfile
    environment:
      - ROS_MASTER_URI=http://ros1-master:11311
    depends_on:
      - ros1-master
    networks:
      - ros1-net
    command: ["rosrun", "roscpp_tutorials", "talker"]

  #ROS1 to ROS2 Bridge
  ros1-bridge:
    image: andrejorsula/ros1_bridge:foxy
    environment:
      - ROS_MASTER_URI=http://ros1-master:11311
    depends_on:
      - ros1-master
    networks:
      - ros1-net
      - ros2-net
  #ROS2
  listener:
    build:
      context: ../02_ros2/
      dockerfile: Dockerfile
    networks:
      - ros2-net
    command: [ "ros2", "run", "demo_nodes_cpp", "listener", "__log_disable_rosout:=true"]

  #Foxglove Bridge to vizualize topics from ROS2
  foxglove-bridge:
    image: mjpc13/foxglove-bridge
    networks:
      - ros2-net
    ports:
      - "8765:8765"

CHAPTER 6 -- Closing Remarks

You can delete every image and container created in this tutorial:

Delete images pulled in this tutorial:

docker rmi -f ubuntu:latest ubuntu:20.04 jupyter/scipy-notebook theasp/novnc:latest alpine nginxdemos/hello ollama/ollama:0.11.5-rc5 ghcr.io/open-webui/open-webui:main osrf/ros:noetic-desktop-full-focal osrf/ros:jazzy-desktop-full mjpc13/foxglove-bridge andrejorsula/ros1_bridge:foxy docker-tutorial vis-tutorial 

Remove all unused images (be carefull):

docker image prune -a

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages