Loadbalance docker compose replicas

1. The problem I’m having:

I’m not sure how to map replicas running in a docker container to the load balancer.

And if it’s possible to have a generic solution where I don’t need to manually specify the ports in the Caddyfile for each app?

I`m currently running my app using docker / docker compose:

services:
  nodejs-app:
    image: ghcr.io/myusername/myrepo:master
    container_name: nodejs-app
    restart: unless-stopped
    networks:
      - backend
    environment:
      - NODE_ENV=production
    build:
      context: .
    deploy:
      replicas: 3        # NEW - create 3 replicas
    ports:
      - "8080:8080"
    env_file:
      - .env
  caddy:
    image: caddy:2.8.4-alpine
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./site:/srv
      - caddy_data:/data
      - caddy_config:/config

volumes:
  caddy_data:
  caddy_config:

networks:
  backend:
    driver: bridge

I want to create 3 replicas, and how I should point each of the instances to the Caddy reverse proxy. My current Caddyfile:

{
    email redacted@redacted.com
}

subdomain.redacted.com {
    reverse_proxy nodejs-app:8080  {
        header_down Strict-Transport-Security max-age=31536000;
    }
    basic_auth {
        redacted redacted
    }

}

2. Error messages and/or full log output:

N/A

3. Caddy version:

v2.8.4
Running in docker container

4. How I installed and ran Caddy:

In docker, please see above.
image: caddy:2.8.4-alpine

a. System environment:

Ubuntu 24.04

docker version:

Client: Docker Engine - Community
 Version:           27.1.2
 API version:       1.46
 Go version:        go1.21.13
 Git commit:        d01f264
 Built:             Mon Aug 12 11:50:54 2024
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          27.1.2
  API version:      1.46 (minimum version 1.24)
  Go version:       go1.21.13
  Git commit:       f9522e5
  Built:            Mon Aug 12 11:50:54 2024
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.7.20
  GitCommit:        8fc6bcff51318944179630522a095cc9dbf9f353
 runc:
  Version:          1.1.13
  GitCommit:        v1.1.13-0-g58aa920
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

b. Command:

N/A run through docker:

caddy:
    image: caddy:2.8.4-alpine
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./site:/srv
      - caddy_data:/data
      - caddy_config:/config

c. Service/unit/compose file:

N/A

d. My complete Caddy config:


{
    email redacted@redacted.com
}

subdomain.redacted.com {
    reverse_proxy nodejs-app:8080  {
        header_down Strict-Transport-Security max-age=31536000;
    }
    basic_auth {
        redacted redacted
    }

}

5. Links to relevant resources:

Docker replicas: Compose Deploy Specification | Docker Docs

You could use GitHub - lucaslorentz/caddy-docker-proxy: Caddy as a reverse proxy for Docker which dynamically produces Caddyfile config based on the Docker services running, including load balancing to multiple replicas.

I’m not currently aware of a dynamic upstreams plugin that can use Docker Swarm’s service discovery, but that should be possible in theory if you prefer that approach over using CDP for generating your config.

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.