Docker¶
Installation¶
For more details follow the official installation guide to install in Ubuntu. In essence
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository to Apt sources:
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] 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
# Install docker packages:
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Note
If you plan to use docker as github runner for CI/CD, provide privileges to the docker.sock files:
sudo chmod 666 /var/run/docker.sock
More details here.
Arch install¶
Link to the Arch Wiki. To install the docker engine:
sudo pacman -Sy docker
Then either the docker.service
or the docker.socket
system service must be enabled.
The former loads docker at boot up (thus more load time could be required), while the latter loads on first usage:
sudo systemctl enable docker.socket
# Or alternatively
# sudo systemctl enable docker.socket
As discussed in the Arch wiki page and here, to run docker with sudo privileges it is recommended to add the own user to the docker
group.
You can check the existance of the group by calling
grep docker /etc/group
If the group exists, then add the user simply with the command
sudo usermod -aG docker $USER # or set the <user_name>
or alternatively create the group:
sudo groupadd docker
After this operation, remember to restart the docker service:
sudo systemctl restart docker
Useful commands¶
To pull a image from the DockerHub, call
docker pull <image_name>:<tag>
For instance to pull the ROS2 humble image call docker pull osrf/ros:humble-desktop-full
(this image comes also with GUI applications, such RViz).
To see the already pulled images that are ready to run call
docker image ls
To create a container, call
# docker image run <image>
# or, shorter,
docker run <image>
In general, configuration arguments that must be passed to the image on boot up must be called prior to the image name, while arguments that follows are executed on the spinned contained:
docker run <docker_arguments> <image> <commands>
A useful argument is -ti
that boots the image and starts an i
interactive t
terminal.
To see currently runnint containers, call
docker container ls
# or,
# docker ps
To see already spinned containers that have been terminated, append the -a
flag to the command.
Containers can be deleted with docker container rm <container_name> -f
, with -f
the force argument.
Additionally, you can pass the --rm
flag to the docker run
call to automatically delete the container when it stops spinning.
You can also start an already start a closed container or close a running container with the following commands:
docker start <container_name>
docker stop <container_name>
Run arguments¶
The following is a list of useful launch arguments that can be paired with the run
command to extend docker capabilities.
-it
: as already mentioned, starts the docker container and enters in the interactive terminal;--rm
: removes the container instance after the container stops spinning;--env <VAR>:<VAL>
or-e <VAR>:<VAL>
: sets an environment variableVAR
withVALUE
on the container;--net=<CONFIG>
: sets the networking configuration. Details can be found here, but available configurations arebridge
(default),host
(recommended),none
,overlay
,ipvlan
,macvlan
.
X11 windows forwarding¶
To enable X11 windows forwarding, you should provide the run
command the following arguments:
-e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix:rw
This command forwards the DISPLAY
argument to the container and binds the X11 socket of the host machine to the container one
(see here for further referencing).
If still you are unable to see the display and the terminal reports an error of the type cannot open display, call the following command to enable docker to control the local X11 server:
xhost +local:docker
Dockerfiles¶
To create a custom Docker image, it is simply necessary to write a Dockerfile
.
Once the file is written, the image can be build with the command
docker build -t <image_name> <path_to_Dockerfile><:tag (optional)>
So let us now see how to write a Dockerfile
.
In general the first line of a Dockerfile
is the FROM
command, which specifies the base image.
The base image can be either already built in the system or can be pulled from the Docker Hub registry.
For instance, the following is the statement to pull the Ubuntu 22.04 image from the Docker Hub registry:
FROM ubuntu:22.04
After the FROM
command are placed all other instructions.
Keep in mind that since image building is a layer-based process, the order of the instructions is important to correctly use caching.
For instance, RUN <cmd>
runs a given command in the shell and than layers the changes on the image.
To copy some files from the host machine to the image, the COPY <host_dir> <img_dir>
command is used.
To set the working directory of the image, the WORKDIR <dir>
command is used.
To set the user of the image, the USER <user>
command is used;
by default, root
is selected, thus commands can be installed withouth the sudo
keyword.
The last command of the Dockerfile
is usually either CMD
or ENTRYPOINT
.
The main is that CMD
is used to specify the default command to run when the container is started (if it was not specified through CLI),
while ENTRYPOINT
is always executed and optional arguments are appended to it.
For further details, this is a good article.
FROM ubuntu:22.04
# This is a good practice to install packages:
# 1. to help caching, collect all the installation procedure in a single RUN command
# 2. to avoid caching issues and save image space, base images come with available
# package lists that are empty.t So always first update the package list, then
# install the packages.
# 3. to avoid caching issues, remove the package list after installation
RUN apt-get update \
&& apt-get install -y <packages> \
&& rm -rf /var/lib/apt/lists/*
# This command copies the content of the current directory to the /application directory of the image
COPY . /application
WORKDIR /application
RUN touch test.txt
ENTRYPOINT ["echo", "Hello World!"]
Docker Compose¶
As the docker run
comman starts having lots of different argument that must be provided to it, it becomes hard to remember the exact command to start a container.
To overcome this limitation there are different methods, namely:
write the command into a shell
.sh
script, make it executable (chmod +x
) and run it from the terminal;for containers that are often used by the user, create an alias in the shell configuration file (
.bashrc
,.zshrc
) to make it easier to run the command;or, the preferrable way, is to use Docker Compose.
Docker Compose is a tool that enables to configure and run multiple containers using a single .yaml
configuration file.
Virtually, everything that can be done with the docker run
command can be done with Docker Compose.
As an example, the file
# File: docker-compose.yml
services:
myubuntu:
image: ubuntu:22.04
environment:
- DISPLAY=${DISPLAY}
- PRINTNAME=${USER}
volumes:
- /tmp/.X11-unix:/tmp/.X11-unix
command: bash -c "echo Hello, World!"
has the final result of the following command:
docker run \
--rm \
-e DISPLAY=$DISPLAY \
-e PRINTNAME=$USER \
-v /tmp/.X11-unix:/tmp/.X11-unix \
ubuntu:22.04 \
bash -c "echo Hello, World!"
To properly run the container through the Docker Compose command, first go to the directory where the docker-compose.yaml
file is located and run:
docker-compose up
This would yield the following output:
[+] Running 1/0
✔ Container test-myubuntu-1 Created 0.0s
Attaching to myubuntu-1
myubuntu-1 | Hello, World!
myubuntu-1 exited with code 0
In this case the docker-compose.yaml
file was placed in a folder named test
, thus the docker compose runtime created a container named test-myubuntu-1
.
The output of the command echo Hello, World!
was overlayed in the terminal and since all containers (1 in this case) finished, the docker compose command completed as well.
In general, to stop all containers created by the docker compose command, it is simply necessary to call docker-compose down
.
The complete list of available commands that can be used in Docker compose .yaml
files can be found here.