Deploying Applications to Raspberry Pi with Docker Compose (from my Mac)

This blog post explains how to deploy applications from your Mac to a Raspberry Pi using Docker Compose. We'll use a simple Go web application as an example.

Prerequisites

  • A Raspberry Pi running RaspberryPi OS (deployment machine)

  • A Mac (development machine) - theoretically, this should work on any OS (on Windows, you can use WSL2)

  • Basic knowledge of Docker and SSH

1. Setting Up Docker on Raspberry Pi

First, we need to install Docker on the Raspberry Pi. Connect to your Pi and run these commands:

Adding Docker's Official GPG Key

sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

Adding Docker Repository

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

Installing Docker

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Running Docker Without Sudo

To avoid using sudo for every Docker command:

sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker

2. Setting Up SSH Access

Create and configure SSH keys on your Mac:

  1. Generate a new SSH key:
ssh-keygen -t rsa -f ~/.ssh/rpi_rsa
  1. Add the key to SSH agent:
ssh-add ~/.ssh/rpi_rsa
  1. Copy the public key to your Raspberry Pi:
ssh-copy-id -i ~/.ssh/rpi_rsa.pub username@raspberry-pi-hostname
  1. Create SSH config file (~/.ssh/config):
Host raspberry-pi-hostname
   HostName raspberry-pi-hostname
   PreferredAuthentications publickey
   IdentityFile ~/.ssh/rpi_rsa

3. Creating Docker Remote Context

Set up a remote Docker context to manage Docker on the Raspberry Pi:

docker context create \
    --docker host=ssh://username@raspberry-pi-hostname \
    --description="Remote engine on Raspberry Pi" \
    rpi-remote

Switch to the remote context:

docker context use rpi-remote

4. Example Application

Let's look at our example Go application that we'll deploy:

Main Application Code (main.go)

package main

import (
    "log"
    "net/http"
    "os"
)

func main() {
    var httpPort = os.Getenv("HTTP_PORT")
    if httpPort == "" {
        httpPort = "8080"
    }

    mux := http.NewServeMux()
    mux.HandleFunc("/", func(response http.ResponseWriter, request *http.Request) {
        response.Header().Add("Content-Type", "text/html;charset=utf-8")
        response.Write([]byte("<h1>👋 Hello World 🌍</h1>"))
    })

    log.Println("🌍 http server is listening on: " + httpPort)
    log.Fatal(http.ListenAndServe(":"+httpPort, mux))
}

Dockerfile

FROM golang:1.22.1-alpine as buildernext
WORKDIR /app
COPY main.go .
COPY go.mod .
COPY go.sum .
RUN go build

FROM scratch
WORKDIR /app
COPY --from=buildernext /app/tiny-service .
CMD ["./tiny-service"]

Docker Compose File (compose.yaml)

services:
  web-app:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      - HTTP_PORT=6066
    ports:
      - 6066:6066

5. Deploying the Application

With everything set up, deploy the application:

  1. Ensure you're using the remote context:
docker context use rpi-remote
  1. Deploy using Docker Compose:
docker compose up --build -d

use --build only if you want to rebuild the image.

The application will be built on your Raspberry Pi and deployed to your Raspberry Pi, accessible on port 6066.

Testing the Deployment

Access the application by opening a web browser and navigating to:

http://raspberry-pi-hostname:6066

You should see the "👋 Hello World 🌍" message.

Troubleshooting Tips

  • Verify your context is correct: docker context ls

  • Check container status: docker ps

  • View logs: docker compose logs

  • Return to local context: docker context use default

Conclusion

Using Docker Compose with a remote context provides a streamlined way to deploy applications to a Raspberry Pi (or any other server) from your Mac. This setup allows you to manage deployments remotely while maintaining a clean separation between development and deployment environments.

2
Subscribe to my newsletter

Read articles from Philippe Charrière directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Philippe Charrière
Philippe Charrière