Part 2. Installing Docker in Raspberry Pi 4

How to prepare a Docker ready development environment for rapid prototyping


In the first article of this serie, Part 1- Getting the most from Raspberry Pi 4, you were given the steps to setup a Raspberry Pi 4 with a M2 SSD disk, running with Ubuntu 20.04 Operating System. The hardware assembly should be similar to the one in the figure above.

Since Raspberry Pi 4 now boots from the M.2 disk unit, it will show a much better performance than if doing from the micro SD card. Using the M.2 the read/write speeds to the disk increase up to a factor 10x.

Given this tiny & powerful hardware setup, in order to complete the development environment we will use Docker, the Linux containers technology that speed up the development of application as well as the distribution to the clients.

Let’s go with the practical part. First we will customize Ubuntu to work confortably from the command line. Then, we will proceed to install and test Docker and Docker Compose, being this last component the necessary complement to build applications that are made of several services, i.e. a frontend client, a backend server and a database for data persistence.

Next we detail every step of how to do it:

1. Setup of OS in the Raspberry Pi

Connect to a wifi network if you did not do it in during the installation process. Remember that Pi4 comes with Ethernet Gigabyte, so if you have a fast Internet connection, you’ll take advantage of it using the wired connection instead of the wifi.

Now it’s time to access to internet for getting updates and be able to install packages.

1.1 Update your system

Fetch Ubuntu source repositories and upgrade system packages to have the latest security patches:

$ sudo apt update && sudo apt upgrade

2. Enable sudo without password

This provides the feature of not being requested the password every time you need to use sudo. Edit the configuration with the following command:

$ sudo visudo

This will open the _nano _editor with that configuration. Then add the following line at the end (we assume that the username is _pi_):


Press CTRL+X, then enter to save the changes.

3. Install basic packages

The package net-tools is a convenient utility for managing network communications from the command line:

$ sudo apt install net-tools

Tip: You could better manage your network connections with netplan, instead of the GUI Network Manager. The advantage comes more evident when you work with the Ubuntu server versions, where there is no desktop.

Finally we install _git _for managing the code and synchronize it with remote repositories, and ssh server to remotely connect to the Raspberry Pi:

$ sudo apt install git openssh-server

After the installation, the SSH service will start automatically. You can check it with the following command:

$ sudo systemctl status ssh

You should find that the service is active and running. Also remember the _hostname _you defined when setting up Ubuntu on first boot. In any case you can see which it is with the following command:

$ hostname

You can also use the _ifconfig _command to find the IP address, that will be particularly useful when connecting from non-Linux devices.

Hence, now the Pi is ready to be connected from a remote terminal, releasing the screen you have needed to access the Ubuntu desktop environment.

4. Switch to work from a remote terminal

Assuming you set up the main user as _pi_, connect from an Ubuntu laptop using the _ssh _command:

$ ssh pi@.local

Replace with the actual one of your Raspberry Pi. If you are connecting from a Windows PC, use the IP address instead:

$ ssh pi@

After providing the password you will have complete access to your Raspberry Pi from the bash terminal.

At this point we have the basic setup to build the Docker infrastructure for the development environment.

Setting up Docker

The time to fully enter into the Linux container world has come!

Yes, any serious developer should test existing software- as well as new ideas- using Docker. This way you’ll do it fast, and will keep a cleaner system that let’s you scape from the hell of dependencies in Linux software.

In Docker every app will be packaged into a container, or a group of containers. Whenever you want to remove an app you will only need to remove the affected containers. This will boost your productivity in almost every scenario. For example in the case in that you are evaluating new software while comparing alternatives in the practice.

Installing Docker

First add the required dependencies and the security key:

$ sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common$ curl -fsSL  | sudo apt-key add -

Make sure that the key fingerprint is_ 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88_:

$ sudo apt-key fingerprint 0EBFCD88

Add the Docker repository corresponding to your CPU architecture and Operating System version (arch=arm64):

$ sudo add-apt-repository "deb [arch=arm64]  $(lsb_release -cs) stable"

If instead of a 64 bits OS, you want the 32 bits version (also covered by Raspberry Pi 4), you should change the reference to the architecture_ _in the previous command to [arch=armhf].

Finally update the repository sources:

$ sudo apt-get update

Also guarantee that you are about to install from the official Docker repository, instead of the default Ubuntu repo:

$ apt-cache policy docker-ce

Then install Docker:

$ sudo apt-get -y install docker-ce

Add your user to docker group:

$ sudo usermod -aG docker ${USER}

So that this change takes effect you have log out and log in again.

Hello World in Docker

Use Hello World example to check your Docker installation:

$ docker run --rm hello-world

The --rm flag tells Docker to remove the container once it finishes its execution. The output in the terminal is self-explaining of what happened:

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.  
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

Listing all containers should show an empty list:

$ docker ps -a

And listing Docker images will show you that hello-world:latest takes less than 5 kB:

$ docker images

It’s worth you try the suggestion of the output of the _hello-world _example above:

$ docker run -it ubuntu bash

What will you have? A complete Ubuntu Server inside the host Ubuntu OS! Amazing…

The second part of the installation involves docker-compose, the tool that will provide the capability of deploying applications that are composed of several containers.

Installing Docker Compose

This component_ _is avaible as a Python package that makes very easy its installation. First install the Python package manager:

$ sudo apt install python3-pip

Then install Docker Compose:

$ sudo pip3 install docker-compose

The hello-world example can be obtained cloning a repository using the git tool:

$ git clone https://github.com/therobotacademy/docker-compose-hello-world

Change to the folder where the code has been dowloaded:

$ cd docker-compose-hello-world

Then deploy the application:

$ docker-compose up -d

The _-d_ flag tells Docker to run the containers in the background. As a consequence, after the application starts you have the terminal free for writing new commands. Find what _docker-compose _is running with the following command:

$ docker-compose ps

For this command to work, it has to be launched from the root of the repository we cloned. Here is where you can find the file docker-compose.yml that contains the description of the containers that form the application. The output of the command is as follows:

There are two containers _…_redis_1_ and _…_web_1_. The last one forwards its internal port 80 to the same port in the host machine ( -> 80/tcp). To access the aplication open the URL http://.local:80 for the web browser. It should show you this result:

Reloading the site in the browser window will provide:

So, the application is simply a counter of visits:

  • The container _docker-compose-hello-world_redis_1_ is a _redis _instance, that is a fast database that runs in RAM memory. It stores the number of visits the site has received.
  • The container _docker-compose-hello-world_web_1_ is a Python web application that prints the number of visits in the home page.

Even if you load the page from another browser tab, you will find that it continues counting visits as well.

To remove the application, just launch this command from the root of the repository:

$ docker-compose down

Whenever you want to launch it again, you only have to repeat the command docker-compose up -d. If you do so, you will find that the launch time is much lower than in the first run. This is because you already have locally stored the Docker images of the two services (in the first run they were automatically downloaded from the public Docker registry).

Congratulations, at this point you have the basic infraestructure to start working the Docker way: fast, repeatable and efficient deployments.

In the next post we will use Docker to deploy our first application- the most basic one a developer needs-, an _Integrated Development Environment _(IDE) to edit code.