Introduction to Docker – Part 2

Docker

This tutorial series will show you how to use Docker on a Linux computer. This part focuses on Docker images and containers.

Images and containers – what are they?

Image

If you’re familiar with computers, you’ve probably heard of disk images: these are files that contain an exact copy of the structure and data of a disk. For example, this type of image is used to install an operating system on a machine (e.g., .iso files). Flashing an image to a disk means recreating a faithful copy of its contents.

Docker images follow the same principle. A Docker image is a file containing all the files, libraries, dependencies, etc., of an environment at a given time. Like a disk image, it can be “flashed” — in Docker we call this “running it” — to get a functional system based on that image.

Container

When you run an image, you create a container. It’s like a disk where you flashed an image: you can access the container, run programs, create files, etc. Any modifications made to the container won’t alter the original image. Containers can be started or stopped at will, just like turning a computer on or off.

Running an image again will create a new container identical to the previous one — but without any modifications.

Working with images

Listing and adding images

You can list the images available in your Docker setup with this command:

docker images

For example, if you ran the command docker run hello-world from the previous tutorial, you’ll see the “hello-world” image listed:

Terminal
mowibox@chroma:~$ docker images
REPOSITORY    TAG      IMAGE ID       CREATED        SIZE
hello-world   latest   74cc54e27dc4   4 months ago   10.1kB

You can also add new images to your Docker setup. For instance, try adding the ROS 2 Humble image with the following command:

docker pull ros:humble

You can verify the image was added with docker images:

Terminal
mowibox@chroma:~$ docker images
REPOSITORY    TAG      IMAGE ID       CREATED        SIZE
hello-world   latest   74cc54e27dc4   4 months ago   10.1kB
ros           humble   168e1f658ab5   3 years ago    753MB

Note

As you may have seen with the “hello-world” image in the previous tutorial, if you try to run a container from an image that hasn’t been added, Docker will automatically download it.

Removing images

To remove an image, such as “hello-world”, use:

docker rmi hello-world
Terminal
mowibox@chroma:~$ docker rmi hello-world
Error response from daemon: conflict: unable to remove repository reference "hello-world" (must force) - container 55ccfd696889 is using its referenced image 74cc54e27dc4

It didn’t work! Likely the same happened for you. Why? Because we launched a container from this image, and it still exists (even if stopped), so Docker doesn’t allow deleting the image just like that. To force deletion, use the -f flag:

docker rmi -f hello-world

Example :

Terminal
mowibox@chroma:~$ docker rmi -f hello-world
Untagged: hello-world:latest
Untagged: hello-world@sha256:940c619fbd418f9b2b1b63e25d8861f9cc1b46e3fc8b018ccfe8b78f19b8cc4f
Deleted: sha256:74cc54e27dc41bb10dc4b2226072d469509f2f22f1a3ce74f4a59661a1d44602

mowibox@chroma:~$ docker images
REPOSITORY    TAG      IMAGE ID       CREATED       SIZE
ros           humble   168e1f658ab5   3 years ago   753MB

The image is now removed from the list.

Working with containers

Creating a container

Now try running a container from the ROS 2 Humble image with the run command:

docker run ros:humble

Ironically, if everything went well, nothing happened… By default, Docker opens the container and exits as soon as it finishes the default command. This is ideal for deploying applications — like in robotics — where a protocol runs and exits.

But for development purposes, we want to interact with the container. Use the -it flags (i for interactive, t for TTY):

docker run -it ros:humble

Example :

root@2f7a757d7c23:/
mowibox@chroma:~$ docker run -it ros:humble
root@2f7a757d7c23:/#

Just like in any terminal, you can browse files (ls), create new ones (touch/mkdir), delete them (rm), etc.

Listing and removing containers

Like images, you can list active containers. Without closing your container, open a second terminal and run:

docker ps

Example :

Terminal n°2
mowibox@chroma:~$ docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS         PORTS     NAMES
2f7a757d7c23   ros:humble   "/ros_entrypoint.sh …"   3 minutes ago   Up 3 minutes             suspicious_black

Inside the container, you can use ROS 2 commands without needing to install ROS on your host computer — amazing!

Example from inside the container:

root@2f7a757d7c23:/
root@2f7a757d7c23:/# ros2 topic list
/parameter_events
/rosout

Outside the container (assuming no native ROS installation):

Terminal n°2
mowibox@chroma:~$ ros2 topic list
bash: ros2: command not found

To exit the container, two methods:

  • Inside the container: Press CTRL + D or run exit
  • From the second terminal: Use docker stop <name>. <name> being the name of the container generated in the container list. In my case, the container is called “suspicious_black”, so I’ll use:
docker stop suspicious_black  # Adapt the command to the name of your container

Running docker ps will show the container is no longer active. To view all containers (including stopped ones), use:

docker ps -a

Example :

Terminal
mowibox@chroma:~$ docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS         PORTS     NAMES

mowibox@chroma:~$ docker ps -a
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS         PORTS                NAMES
2f7a757d7c23   ros:humble   "/ros_entrypoint.sh …"   11 minutes ago   Exited (137)   About a minute ago   suspicious_black

To restart the container, you can use:

docker start -i suspicious_black # Adapt the command to the name of your container

To delete an inactive container, use one of these two commands:

  • Delete a specific container:
docker rm <name>
  • Delete all inactive containers
docker container prune

Using multiple terminals in one container

Sometimes you may want multiple terminals in the same container. First, launch it normally:

docker run -it ros:humble

Then, in another terminal, use the following command:

docker exec -it <name> /bin/bash

Example :

Terminal n°1
mowibox@chroma:~$ docker run -it ros:humble
root@a719943a59fc:/#
Terminal n°2
mowibox@chroma:~$ docker ps # Pour récupérer le nom du conteneur
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS     NAMES
a719943a59fc   ros:humble   "/ros_entrypoint.sh …"   12 seconds ago   Up 11 seconds             unruffled_cray

mowibox@chroma:~$ docker exec -it unruffled_cray /bin/bash
root@a719943a59fc:/#

The docker run command has useful flags:

  • --name sets a custom name for your container. This avoids having to manage a random name each time a container is created:
docker run --name <container_name> <image_name>
  • --rm deletes the container automatically when it stops:
docker run -rm <image name>

Tip

Multiple flags can be combined!

With these commands, you already have a solid foundation in how images and containers work. However, every time you create a new container, you lose changes made in previous ones using the same image — there’s no persistent way to save files yet. This is where the Dockerfile comes in — the subject of the next tutorial.


Credits