Blue-Green Deployment with Docker Compose and Caddy on Raspberry Pi

This article explains how to implement a blue-green deployment strategy for a Go application using Docker Compose and Caddy on a Raspberry Pi. Blue-green deployment is a technique that reduces downtime by running two identical environments called Blue and Green.

Prerequisites

Before following this tutorial, make sure you have read the blog post Deploying Applications to Raspberry Pi with Docker Compose (from my Mac). This post explains how to set up a Docker remote context to easily deploy applications to a remote machine like a Raspberry Pi.

Project Structure

Our project consists of the following files:

  • main.go: A simple Go web server

  • Dockerfile: Instructions to build the Go application

  • compose.yaml: Docker Compose configuration for our services

  • Caddyfile: Caddy reverse proxy configuration

  • caddy.Dockerfile: Dockerfile for Caddy setup

Understanding the Components

The Go Application

Our application is a simple web server that displays a coloured greeting. The colour (blue or green) helps us identify which version is currently running:

package main

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

func main() {
    var httpPort = os.Getenv("HTTP_PORT")
    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>")) // Blue version
    })

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

Docker Compose Configuration

The compose.yaml file defines three services:

  1. web-app-blue: Blue version running on port 6065

  2. web-app-green: Green version running on port 7065

  3. caddy: Reverse proxy running on port 9090

services:
  web-app-blue:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      - HTTP_PORT=6065
    ports:
      - 6065:6065
    networks:
      - proxy-network

  web-app-green:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      - HTTP_PORT=7065
    ports:
      - 7065:7065
    networks:
      - proxy-network

  caddy:
    build:
      context: .
      dockerfile: caddy.Dockerfile
    ports:
      - "9090:9090"
    networks:
      - proxy-network

networks:
  proxy-network:
    driver: bridge

Implementation Steps

1. Deploy the Blue Version

First, deploy (and build) the blue version of the application:

docker compose up -d --build web-app-blue

You can verify the deployment by accessing http://robby.local:6065 in your browser.

2. Set Up the Reverse Proxy

Configure Caddy to route traffic to the blue version:

:9090 {
    reverse_proxy web-app-blue:6065
    log {
        output stdout
        format console
    }
}

Deploy Caddy:

docker compose up -d --build caddy

Now you can access the application through the reverse proxy at http://robby.local:9090.

3. Deploy the Green Version

Update the application code to display the green version.

Change the response message in main.go:

response.Write([]byte("<h1>🔵 👋 Hello World 🌍</h1>")) // Blue version

by:

response.Write([]byte("<h1>🟢 👋 Hello World 🌍</h1>")) // Green version

Then deploy (and build) the green version:

docker compose up -d --build web-app-green

Verify the green version at http://robby.local:7065.

4. Switch Traffic to Green Version

Update the Caddyfile to route traffic to the green version:

:9090 {
    reverse_proxy web-app-green:7065
    log {
        output stdout
        format console
    }
}

Redeploy Caddy to switch the traffic:

docker compose up -d --build caddy

Now you can access the green version of the application through the reverse proxy at http://robby.local:9090.

Testing the Deployment

After each step, you can verify the deployment:

Benefits of This Approach

  1. Zero-downtime deployments: Users always have access to one version of the application

  2. Easy rollback: If issues are found in the green version, you can quickly switch back to blue

  3. Verification: You can test the new version before routing traffic to it

  4. Simple implementation: Uses standard Docker Compose and Caddy features

Conclusion

This setup provides a simple but effective way to implement blue-green deployments on a Raspberry Pi. While this example shows manual switching between versions, you could automate this process using scripts or CI/CD pipelines for production environments.

1
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