As a full-stack developer and Raspberry Pi enthusiast, I often use Docker to simplify building, shipping, and running applications. The Raspberry Pi‘s low cost, small footprint, and Linux/ARM support make it an ideal platform for Docker.

In this comprehensive 3049-word guide, we will dive deep on installing Docker Engine and Docker Compose on a Raspberry Pi 4 running Raspberry Pi OS, and demonstrate how to effectively build, manage, and monitor containers.

Why Docker on Raspberry Pi

Before we get hands-on, let‘s discuss why running Docker on Raspberry Pi makes for an compelling combination:

Simplified Dependency Management

Deploying complex applications with many dependencies and config files becomes trivial using Docker containers. Avoid dependency version conflicts by standardizing on containerized apps.

Portability

Build an application image once, then run it anywhere Linux containers can run – including Raspberry Pi, desktop PCs, cloud VMS and Kubernetes clusters.

Lightweight Virtualization

Containers provide a lightweight form of OS-level virtualization by leveraging technology built into the Linux kernel. This has less overhead than traditional VMs.

Raspberry Pi Flexibility

Docker functionality unlocks many new homelab use cases for Raspberry Pis – everything from network appliances to automation servers and beyond.

Scaling

While one Raspberry Pi 4 has limited compute power, you can network multiple Pis together to create affordable clusters for scale.

Now let‘s get our hands dirty…

Prerequisites

For this Docker guide, I used the following setup:

  • Raspberry Pi: Raspberry Pi 4 Model B 8GB
  • Storage: 64GB Class 10 MicroSD Card
  • OS: Raspberry Pi OS 64-bit (Debian Bullseye)
  • Networking: Ethernet connectivity
  • Power: Official Raspberry Pi 15W USB-C Power Supply

For best Docker performance, I recommend the 8GB Pi 4 or better. The 2GB and 4GB models may struggle with some heavier apps. The 64GB+ MicroSD allows ample room for images/containers.

Optional but highly recommended:

  • Portainer – Open source container monitoring and management GUI

Step 1 – Update Raspberry Pi OS

Boot up your Pi 4, connect over SSH as the pi user or log in directly, then become root with sudo su.

Update package repositories and upgrade installed packages:

apt update
apt full-upgrade -y

Reboot once upgrades complete. This ensures we start with the latest security patches and kernel before installing Docker.

Updating Raspberry Pi OS packages

Updating Raspberry Pi OS – Takes 5-10 Minutes

Step 2 – Install Docker Engine

With Raspberry Pi OS hardened, we can now install the latest Docker Engine package using the official convenience script:

curl -sSL https://get.docker.com | sh

On first run, the script contacts Github for the latest ARM builds, instals dependencies like containerd, then grabs and installs Docker Engine binaries.

Follow along and OK the prompts during the ~5 minute install process:

Docker CE Install Process on Raspberry Pi

Docker Community Edition Installing on Raspberry Pi

Once complete, add the pi user to docker group so we can run Docker without sudo:

usermod -aG docker pi

To apply this change either reboot with reboot or log out and back in as pi.

Validate the Docker install and check version:

docker -v

Docker version 20.10.12, build e91ed57  

Success! Docker Engine is installed and containerization awaits.

Step 3 – Install Docker Compose (Recommended)

While optional, I highly recommend also installing Docker Compose, an official Docker tool for simplifying multi-container application management using a docker-compose.yml file. Think of it as an orchestrator for juggling containers.

First ensure Python pip and setuptools are available on the system as Compose depends on them:

apt install -y python3-pip python3-setuptools

Then use pip3 to install the latest Docker Compose:

pip3 install docker-compose

Check we can access docker-compose and validate what version installed:

docker-compose version  

docker-compose version 1.29.2, build 5becea4c

We will demonstrate basic Docker Compose usage later on.

Step 4 – Deploy Sample Containers

Alright, Docker Engine and Compose are in place – time to get our hands dirty by running some containers! I will demonstrate both standard docker run and compose file methodologies.

NGINX Web Server

Let‘s start easy by running the official NGINX web server image in a container:

docker run -d -p 80:80 --name webserver nginx

Breaking this down:

  • docker run = Run new container from an image
  • -d = Detached/background mode
  • -p 80:80 = Map port 80 inside container to port 80 on host
  • --name webserver = Name the container "webserver"
  • nginx = Official Nginx container image name

Check out currently running containers:

CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS                    PORTS                               NAMES
a2a583bde3b5   nginx     "/docker-entrypoint...."   About a minute ago   Up About a minute         0.0.0.0:80->80/tcp, :::80->80     webserver 

And test by browsing either Pi‘s IP address or localhost which will hit the Nginx container:

Nginx default page running on Raspberry Pi via Docker

Nginx Default Page Served from Docker Container on Raspberry Pi

Web server works! Now stop and remove the container:

docker stop webserver
docker rm webserver  

Already we have successfully installed and run a containerized application, not having to worry about conflicts with existing Apache or Nginx on the OS. Now let‘s try something more complex.

Portainer Container Management GUI

When managing multiple containers and Docker environments, having a graphical UI makes life much easier. For that there‘s Portainer – an open source tool that itself runs within a container!

Use the following long docker run command to deploy Portainer to listen on port 9000:

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

That‘s a lot to unpack so let‘s break this command down:

  • -d = detached/background mode
  • -p 8000:8000 = internal Portainer API port mapped to host port 8000
  • -p 9000:9000 = Portainer Web UI port mapped to host 9000
  • --name portainer = friendly container name
  • --restart=always = auto restart if stopped
  • -v /var/run/docker.sock:/var/run/docker.sock = volume mount Docker socket for managing local Docker
  • -v portainer_data:/data = named volume for persisting Portainer data
  • portainer/portainer-ce = Portainer community edition container image

Visit either the Pi‘s IP on port 9000 or http://localhost:9000 to begin Portainer setup:

Portainer initial setup prompt

Portainer Web Interface – Set Admin Password

Set a password for the admin user account to complete initialization.

We now have a handy GUI for monitoring containers, images, volumes and more! For example, clicking into Containers shows currently running:

Portainer GUI showing running containers

Portainer Managing Docker Containers on Raspberry Pi

When finished managing containers with the UI, stop and remove as usual:

docker stop portainer
docker rm portainer 

For multi-container applications, the graphical view Portainer provides becomes even more beneficial. Which brings us to…

Docker Compose Multi-Container Demo

For our last showcase, we will demonstrate Docker Compose bringing up an integrated WordPress site backed by MySQL database. Here is the docker-compose.yml file that links everything together:

version: ‘3‘ 

services:

  mysql:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: password

  wordpress: 
    image: wordpress 
    depends_on:
      - mysql
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_USER: root
      WORDPRESS_DB_PASSWORD: password 
    ports:
      - 80:80

The YAML format allows us to define multiple services (containers) along with networking and dependencies between them.

To launch our WordPress stack:

docker-compose up -d  

Compose handles all the heavy lifting – pulling images, starting linked containers for MySQL and WordPress, wiring up networking, etc. We visit IP address port 80 and go through WordPress initial site setup. The MySQL container hostname can simply be referenced as "mysql" thanks to the Docker internal DNS provided by Compose.

WordPress install running on Docker Containers Raspberry Pi

WordPress Install Accessing MySQL on Linked Docker Container

Tear it all down when finished:

docker-compose down

No need to worry about cleaning up orphaned containers or volumes, compose handles it all.

Docker Tips & Best Practices

Now that we have Docker up and running on the Pi, here are some handy pro-tips for working with containers:

Update the Docker Base OS Regularly

The Docker host OS forms the foundation all containers run on top of. Keep it patched by running apt update/upgrade monthly or any time major security fixes are announced. Reboot after OS updates.

Use Small Base Images

Size your custom dockerfiles FROM minimal base images like Debian or Alpine Linux when possible. This reduces attack surface and decreases IoT push/pull times.

Bind Mount Configs for Persistence

Use bind mounts (-v host_dir:container_dir) rather than baking config into custom images. This allows updating app config without rebuilding images.

Leverage Multi-Stage Builds

Install build tools and runtime dependencies in separate stages. This keeps production container lean by only copying essentials into the final stage.

Watch Container CPU & Memory Limits

New containers can easily overwhelm the Pi‘s limited resources if unrestrained. Set CPU shares and memory limits matching application requirements.

Implement Container Restarts

Crash-prone or memory leaky apps may require auto restart policies via Docker‘s --restart flag or Compose file. Plan to eventually fix the root application issue.

Consider Container Orchestration

As your Pi Docker footprint scales past experimentation, explore orchestrators like Docker Swarm or Kubernetes for complex deployments.

Recap and Final Thoughts

We took an in-depth look at properly installing and hardening Docker Engine, Docker Compose, and supporting packages on the versatile Raspberry Pi 4 hardware. With containers now unlocked, we deployed sample web servers, stood up Portainer for simplified management, and explored a multi-container WordPress stack via compose file.

Docker functionality vastly expands the use cases possible with inexpensive Raspberry Pi nodes. You can now sandbox complex applications, mimic production environments for testing, learn CI/CD pipelines, and more!

Some parting ideas for extending your Docker journey:

  • Explore Docker networking to enable cross-container communication
  • Build CI/CD pipelines around containerized apps with GitHub Actions
  • Cluster multiple networked Pi‘s into affordable Docker Swarm setup
  • Study Kubernetes and deploy Pis as lightweight worker nodes
  • Package your own applications as efficient Docker images

I hope this 3049-word guide gives you confidence and a solid foundation for containerizing applications on the Raspberry Pi platform. Let me know if any questions come up as you being your Docker adventures!

Similar Posts