Tutorials (Intermediate)
Before going on, let's go back to the docker run hello-world
command. What docker run
does is create a container from the hello-world
image. You can create as many containers (completely unrelated) as you want from the same image.
Note: We suggest you the vscode docker extension to explore all containers and images on your system.
You should also have noticed that docker run
will download (or rather pull
) the hello-world
image from the web (actually from some known repositories, like apt
does) if it was not found locally. Try one by one the commands below.
docker rmi hello-world #will erase the local image
docker pull hello-world #only downloads the latest version of the image.
docker run hello-world #start a container with a random fancy name
docker run --name pippo hello-world #start a container named pippo
docker run --name pluto --rm hello-world #start a container named pippo, automatically remove it on stop (--rm)
docker container ls #list all running container
Dockerfiles
In you went through the ROS tutorial, you probably installed some apt
packages to proceed, or maybe you manually downloaded some code from git
.
The point is, if you loose the container for some reason, will you also loose all the installations you made, all the files you downloaded, within the container? The answer is "yes".
That's the reason why we use a Dockerfile
to keep track of most of the installations. Let's consider the learn the C++ basics example.
docker run -d -t --name ubuntu ubuntu #start a basic Linux container: -d sends it in the background (detach), -t keeps it running
docker exec -it ubuntu bash -c 'g++ --version' #gives error, g++ is not installed yet
docker exec -it ubuntu bash -c 'apt update && apt install g++ -y' #install the C++ compiler, you will need it!
We can keep track of the g++
installation with a Dockerfile
. Create it from vscode and save it in a dedicated folder
FROM ubuntu
RUN apt update && apt install g++ -y
How it works? Save it and use it to build a specialized Docker Image
docker build -f /path/to/your/folder/Dockerfile -t my-image
so that if you start a container from the newly created image you will find g++
already there
docker run -d -t --name my-ubuntu my-image
docker exec -it ubuntu bash -c 'g++ --version' #no error, prints the compiler version
docker run -it --rm my-image g++ --version #test the new image in a single line
Docker Compose
Docker Containers can be composed together to form a modular architecture. For instance, consider a practical case on our teleoperation platform.
You are developing a super cool ROS package which turns a target 6D pose for the robot into target joint angles for the robotic arm. The vendor, Universal Robots in our case, provides us the ROS driver package, which will listen for your joint angle commands (via a ros2 topic
) and will take care to send them to the robot.
The point is, are you sure that you want to test your new algorithm directly on real (very expensive) robots? Wouldn't you like to see first how the math that you implemented behaves? Maybe you'll find some bugs, so it's a good practice you test your codes on simulated robots first. Remember, simulated arms are free!
Here's where modularity helps you! Let's say that your ROS package is installed along with the UR driver into a dedicated container, let's call it drivers. You only need to start a second container which runs the simulator to start debugging.
Moreover, imagine that a colleague of yours has a container, let's name it devices, which turns mocap data into target 6D poses for the robots. You can just compose devices and drivers together and the teleoperation system is ready to go!
Whenever you're ready to test with real robots, just stop the simulator container and connect the drivers with your real robots.
ROS
First, learn how it works in a minimal ROS architecture example.
Try to add a custom service (i.e. a container supported by a specific image) to the compose architecture using the Dockerfile
version: '2'
services:
talker:
image: osrf/ros:jazzy-desktop
command: ros2 run demo_nodes_cpp talker
listener:
image: osrf/ros:jazzy-desktop
command: ros2 run demo_nodes_cpp listener
depends_on: talker
my_service:
build:
dockerfile: /path/to/your/folder/Dockerfile
command: g++ --version
docker compose build my_service #build only my_service
docker compose up my_service #run only my_service
or
docker compose build
docker compose up
Note: Docker will take a lot of memory (disk) to store images and containers. Periodically remove unused images. Moreover clear the builder cache with docker builder prune
. Cleaning the cache means that new builds will start almost from scratch, which means they eill take more time.