Beginner’s Guide to Install and Use Docker with Raspberry PI

4.8
(45)

In this tutorial, I’ll show you how to set up a Docker on Raspberry PI, by showing you some of the main commands to use containers.

Docker containers are the new trend in deploying microservices without duplicating OS jobs on the host machine. They are also fast and allow quick development techniques unavailable in classic development. It is possible (and useful) to install Docker on Raspberry PI computer boards, getting container advantages in our powerful single-board, credit-sized computer

Main Docker Concepts

With the open-source docker engine, you can use docker containers up with the single-line command “docker run”. You can also use base images to customize your services with the “docker build” command and very simple dockerfiles. Moreover, the “docker compose” command enables you to deploy complete services defined in simple “docker-compose.yml” files. Finally, the “docker swarm” command will simplify Raspberry PI cluster creation to distribute the load between different physical boards.

All the most used images come from the Docker Hub, where you can pick microservices ready for use by checking that these are available for ARM architecture: Raspberry PI has arm processors, so only those docker images compiled for ARM can be run on it. Sometimes also processor version can also be crucial: for example, some docker images are compiled to run only with armv6, and they will run only in older Raspberry PI computer models. As we’ll see in the following chapters, we’ll get our current Raspberry PI processor architecture with the docker version command.

This procedure has been tested on many Raspberry Pi computer models (Zero W, PI 3 Model A+, PI 3 Model B/B+, PI 4 model B, PI 5 model B), so it should work with any Raspberry PI computer board with internet connectivity.

What We Need

As usual, I suggest adding from now to your favourite e-commerce shopping cart all the needed hardware, so that at the end you will be able to evaluate overall costs and decide if to continue with the project or remove them from the shopping cart. So, hardware will be only:

raspberry-pi-5-model-b-board

Step-by-Step Procedure

Prepare the Operating System

The first step is installing the Raspberry PI OS Lite (I suggest the 64-bit version, for boards supporting it) to get a fast and light operating system (headless). If you need a desktop environment, you can also use the Raspberry PI OS Desktop, in this case working from its terminal app. Please find the differences between the 2 OS versions in my Raspberry PI OS Lite vs Desktop article.

Please make sure that your OS is up to date. From your terminal, use the following command::

sudo apt update -y && sudo apt upgrade -y

Install Docker on Raspberry PI

The default (and suggested) docker installation comes with the “convenience” script, a simplified bash installation script that makes all the work for you. This adds the required repositories to your “apt” file, downloads and installs the dependencies and the latest Docker engine version. Type the following commands from the terminal:

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

The second command will take a few minutes as it will download all the required packages for your Raspberry PI architecture and install them.

At the prompt, you can test it by typing the following docker command:

sudo docker version

It will return all the main info of your Docker version, such as the architecture (“Arch” variable), similarly to the following:

pi@raspberrypi:~ $ sudo docker version
Client: Docker Engine - Community
 Version:           26.1.4
 API version:       1.45
 Go version:        go1.21.11
 Git commit:        5650f9b
 Built:             Wed Jun  5 11:29:12 2024
 OS/Arch:           linux/arm64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          26.1.4
  API version:      1.45 (minimum version 1.24)
  Go version:       go1.21.11
  Git commit:       de5c9cf
  Built:            Wed Jun  5 11:29:12 2024
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.6.33
  GitCommit:        d2d58213f83a351ca8f528a95fbd145f5654e957
 runc:
  Version:          1.1.12
  GitCommit:        v1.1.12-0-g51d5e94
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

If you would like to use Docker as a non-root user, I suggest you considering to add your user to the “docker” group. To accomplish it for the classic “pi” user:

sudo usermod -aG docker pi

You will need to reboot (or, at least logout and login) to make it work:

sudo reboot

At the Raspberry PI’s reboot, you will be ready to test the main Docker commands as in the following paragraphs.

Docker Run Command

The first command to learn to use Docker with Raspberry PI is the “docker run” command. It checks if the required image is available locally in your Raspberry PI’s storage. If not, it will download the image from the Docker Hub and execute it. Everything in one command line!

The “docker run” command requires only 1 mandatory variable: the image name. With it, you can set a specific version by adding it after the image name, separated with a colon. If you don’t specify it, docker will automatically set the version value to “latest” and use the latest version. Let’s look at it with an example.

As the first test, we’ll use the “hello-world” docker image. From the Docker Hub, at the hello-world tag page, we can see that it supports quite all the architectures and includes our one (mine is arm64). Please note that the following screenshot is for the version tagged as “latest” (top-right side of the picture):

docker-raspberry-pi-hello-world-hub-architecture

This container will print something like a welcome message. The command will be docker run hello-world (which equals to docker run hello-world:latest). The result of this command is available below:

pi@raspberrypi:~ $ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
478afc919002: Pull complete
Digest: sha256:d1b0b5888fbb59111dbf2b3ed698489c41046cb9d6d61743e37ef8d9f3dda06f
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (arm64v8)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

At the end of this execution, the docker container will stop executing. You can get a list of your containers with the following command:

docker ps -a

The “-a” option will show you both the active and the stopped containers. The result will be similar to the following:

pi@raspberrypi:~ $ docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED       STATUS                   PORTS     NAMES
51f2700426f1   hello-world   "/hello"   4 hours ago   Exited (0) 4 hours ago             bold_mcclintock

In this result:

  • the CONTAINER ID is a random identifier associated to every container. You can’t change it.
  • the IMAGE is the name of the image on which the container is based.
  • the COMMAND is the main command running in the container. Inside the hello-world there’s a script named “hello” which prints the message and ends. At the end of the main command, the container will stop running.
  • the STATUS shows if the container is running or closed (or other available states). “Exited (0)” means that the container finished the script and exited with an exit code = 0 (this code means that it has run correctly). Different exit codes mean that the end is caused by errors.
  • the PORTS columns show if some of the container ports are mapped in your Raspberry PI network.
  • the final NAMES columns show a mnemonic name for every container. This name is set with a random name unless the user sets it to a specific value in the docker run command.

The “docker run” command allows you to add a large number of options to fit your needs. The following paragraphs will show you the main ones. All of these options must be set between the “docker run” and the image name of your command.

The -d option equals to --detach. This option runs a container without the need to keep a terminal session active with the container. The container will run as a daemon in your Raspberry PI, even if you close your terminal.

The -it option is an alternative to “-d” and equals to 2 options: --interactive and --tty. Interactive means that the container will run with an interactive shell which expects your commands to make anything, while the tty will create this interactive session in your terminal shell. With these 2 options, you will be prompted inside the container, in a way similar to a virtual machine. But the container will stop running once you will exit from this session. It is important to note that if you need to store any data inside your container, the proper way is by mapping a volume between the container and your Raspberry PI storage (see later) and you shouldn’t rely on keeping data inside a stopped container.

The -p option equals to --publish. This command allows you to use one of the host (Raspberry PI) network ports to expose a container service/port. This means that a user can query the container services from the Raspberry PI ports instead of entering the docker internal network. For example, the following command (working only with 64-bit Raspberry PI OS):

docker run -d -p 7000:8080 bitnami/apache:latest

Will use an Apache image managed by VMware. By default, the container exposes its service (a simple web page) at port 8080, but the docker run command maps this port to the 7000 of the Raspberry PI. So, you can see the result from a remote computer, by using the Raspberry PI’s IP address followed by the specified Raspberry PI port. In my case, as my Raspberry PI has IP address 192.168.1.218, my URL will be http://192.168.1.218:7000 and the result will be the following:

docker-raspberry-pi-bitnami-apache-test

Of course, for beginners, it is important to note that you can’t expose more than one service on 1 Raspberry PI port. Nevertheless, with the -p option you can use quite any free Raspberry PI port for services.

The -v option equals to --volume. It enables you to map a Raspberry PI’s folder into the container file system. For example, if you run the command:

docker run -it -v ./ubuntu_home:/home ubuntu:latest

It will create an interactive ubuntu container. In the Raspberry PI’s current folder, a new subfolder named “ubuntu_home” will be created (if not exists). This will include all the files of “/home” in the ubuntu container. By running a second terminal session in your Raspberry PI, you will be able to see that any new file stored in “ubuntu_home” will be immediately available also in the “/home” inside the container. Volumes are really useful with containers as they are persistent even if the container is stopped and removed. From the ubuntu container shell, you can exit by running the exit command.

The --name option allows you to set a custom container name. For example, the following command:

docker run --name my_hello hello-world

This will execute the same hello-world container, but the name will be a set as set in our docker run command:

pi@raspberrypi:~ $ docker ps -a
CONTAINER ID   IMAGE                   COMMAND                  CREATED             STATUS                      PORTS                                                 NAMES
37b8181622b7   hello-world             "/hello"                 27 minutes ago      Exited (0) 27 minutes ago                                                         my_hello

The --restart option allows you to set a restart policy for your containers. It has the following possible values:

  • no – the container desn’t automatically restart after an exit
  • on-failure[:max-retries] – the container will restart (optionally up to the max-retries value) only on failures, that means exit with code different from 0
  • unless-stopped – the container will always restart unless the user doesn’t explicitly stops it (with a “docker stop” command)
  • always – the container will always restart

The default restart policy is set to “no”, which means that the container will not restart, for example, after a Raspberry PI reboot. For this option, I usually adopt the “unless-stopped” policy, so that I can keep control of restarts and all my containers will be live even after my Raspberry PI’s reboot.

Main Commands to Control Docker

There are also some main commands to control your Docker on Raspberry PI and see what’s happening.

We have already seen the docker ps command, which allows you to see the running containers. With the “-a” option, you will be able to see also the exited containers.

With the docker image ls command, you will be able to list the docker images already downloaded in your Raspberry PI. The following shows an example from my docker environment:

pi@raspberrypi:~ $ docker image ls
REPOSITORY               TAG       IMAGE ID       CREATED         SIZE
bitnami/apache           latest    8468ba16c5bb   9 days ago      241MB
ubuntu                   latest    ffb64c9b7e8b   2 weeks ago     101MB
hello-world              latest    ee301c921b8a   13 months ago   9.14kB

You can also manage your images, removing those not in use with the docker image rm <<image_name>>. the name, in this case, is composed of the repository and the tag, separated from a colon (for example “hello-world:latest”).

Something similar for the volumes. You can list them with the docker volume ls and remove them with the docker volume rm <<volume name>> command. Please note that removing a volume will delete all the data inside the volume.

Finally, the docker container ls will give you an output similar to the “docker ps” command. But “docker container” allows you to manage containers with more functions like:

  • docker container start <<container name>> : to start an exited container
  • docker container stop <<container name>>: to stop a running container
  • docker container rm <<container name>>: to remove an exited container
  • docker container logs <<container name>>: to see the internal logs of the container
  • docker container rm <<container name>>: to remove an exited container

With these commands, you can use both the CONTAINER ID or the name you set with the option “–name” as container name.

Docker Compose

It has been included in the docker installation from 2024 and now you don’t need to install it separately. You can verify your docker-compose installation by typing:

docker compose version

Docker compose enables your Docker environment to use yaml files to compose and quickly boot complete service infrastructures. With docker compose, you can define all the required images, settings, connections, dependencies, volumes, and so on in a single file, named “docker-compose.yaml”. I suggest creating this file into a dedicated folder, as docker compose will use the folder’s name as prefix for all the container names and for the network name.

Once you have a valid docker compose file, you can build the whole infrastructure with the command:

docker compose up -d

Here the “-d” option still means “–detached” as previously seen.

You can remove the whole infrastructure with the command:

docker compose down

Please note that at the infrastructure remotion (with the docker compose down command), only the files in your mapped volumes will be kept.

Install Portainer

A graceful web GUI helping in managing containers is portainer. In our case, we need to install an arm-compatible version and then launch it with the docker run command:

docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest

It will download and install the latest available container version for your Raspberry PI and OS. After this, you can reach your docker server with a browser, just connecting to https://<<RaspberryIpAddress>>:9443. Please remember to use https and not http! Depending on your browser, you may be warned about the insecure certificate. As we’re in a local environment and you’re sure that you’re connecting to your Raspberry PI, you can proceed.

In your very first connection to Portainer, you will be required to set your default password for the admin user:

docker-raspberry-pi-portainer-set-admin-password

Moreover, you will be asked if you want to control only your local docker environment or connect an existing environment with multiple devices. Please select the first option:

docker-raspberry-pi-portainer-setup-local

Then you will be prompted to the Portainer GUI, which will give you a visual control of your docker host and containers:

docker-raspberry-pi-portainer-home

What’s Next

Want to know more about cool projects to do with Raspberry PI computer boards? In this case, the right resource for you is my Raspberry PI tutorials pages.

Enjoy Docker with Raspberry PI!

How useful was this post?

Click on a star to rate it anonymously!

Average rating 4.8 / 5. Vote count: 45

No votes so far! Be the first to rate this post.

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?