Skip to content

Deploy Odoo on Docker Swarm: Multi-Node Cluster Guide (2026)

DeployMonkey Team · March 23, 2026 11 min read

Why Docker Swarm for Odoo?

Docker Swarm provides container orchestration without the complexity of Kubernetes. If you need multi-node deployment, rolling updates, and automatic service recovery but find Kubernetes overkill, Docker Swarm is the middle ground. It uses the same Docker CLI you already know, requires no additional tooling, and can be set up in minutes.

For Odoo deployments with 2-5 servers, Docker Swarm delivers high availability and load balancing with dramatically less operational overhead than Kubernetes.

Architecture

Manager Node 1 (leader)
  ├── Traefik (reverse proxy + SSL)
  ├── Odoo replica 1
  └── PostgreSQL (primary)

Worker Node 2
  ├── Odoo replica 2
  └── PostgreSQL (replica, optional)

Worker Node 3
  └── Odoo replica 3

Prerequisites

  • 2-5 servers (Ubuntu 24.04 recommended)
  • Docker installed on all nodes
  • Ports 2377, 7946, 4789 open between nodes
  • Domain name pointing to manager node IP

Step 1: Initialize the Swarm

# On manager node
docker swarm init --advertise-addr YOUR_MANAGER_IP

# This outputs a join token. Run it on worker nodes:
docker swarm join --token SWMTKN-xxx YOUR_MANAGER_IP:2377

# Verify nodes
docker node ls

Step 2: Create Overlay Network

docker network create --driver overlay --attachable odoo-network

Step 3: Create Docker Compose for Swarm

# docker-compose.yml
version: '3.8'

services:
  postgresql:
    image: postgres:16
    environment:
      POSTGRES_USER: odoo
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
      POSTGRES_DB: odoo
    volumes:
      - pg_data:/var/lib/postgresql/data
    networks:
      - odoo-network
    secrets:
      - db_password
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      resources:
        limits:
          memory: 4G
          cpus: '2'

  odoo:
    image: odoo:19
    environment:
      HOST: postgresql
      PORT: 5432
      USER: odoo
      PASSWORD_FILE: /run/secrets/db_password
    volumes:
      - odoo_data:/var/lib/odoo
      - odoo_addons:/mnt/extra-addons
    networks:
      - odoo-network
    secrets:
      - db_password
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 30s
        order: start-first
      restart_policy:
        condition: on-failure
        delay: 10s
      resources:
        limits:
          memory: 4G
          cpus: '2'
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.odoo.rule=Host(`erp.yourdomain.com`)"
      - "traefik.http.routers.odoo.tls.certresolver=le"
      - "traefik.http.services.odoo.loadbalancer.server.port=8069"
      - "traefik.http.services.odoo.loadbalancer.sticky.cookie=true"

  traefik:
    image: traefik:v3.0
    command:
      - --providers.docker.swarmMode=true
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - [email protected]
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - letsencrypt:/letsencrypt
    networks:
      - odoo-network
    deploy:
      placement:
        constraints:
          - node.role == manager

volumes:
  pg_data:
  odoo_data:
  odoo_addons:
  letsencrypt:

networks:
  odoo-network:
    external: true

secrets:
  db_password:
    external: true

Step 4: Deploy the Stack

# Create secrets
echo "secure_password" | docker secret create db_password -

# Deploy
docker stack deploy -c docker-compose.yml odoo

# Check services
docker service ls
docker service ps odoo_odoo

Step 5: Rolling Updates

Update Odoo with zero downtime:

# Build and push your custom Odoo image
docker build -t your-registry/odoo:19-custom-v2 .
docker push your-registry/odoo:19-custom-v2

# Update the service
docker service update --image your-registry/odoo:19-custom-v2 odoo_odoo

# The update_config ensures:
# - 1 container at a time (parallelism: 1)
# - 30s delay between updates
# - New container starts before old one stops (start-first)

Shared Storage

Odoo's filestore must be shared across all replicas. Options:

SolutionComplexityPerformanceCost
NFS shareLowGoodFree (self-managed)
GlusterFSMediumVery goodFree
AWS EFSLowGood$0.30/GB/mo
MinIO (S3-compatible)MediumExcellentFree

Monitoring

Add monitoring to your Swarm stack:

# Add to docker-compose.yml
  portainer:
    image: portainer/portainer-ce
    ports:
      - "9443:9443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer_data:/data
    deploy:
      placement:
        constraints:
          - node.role == manager

Docker Swarm vs Kubernetes for Odoo

FeatureDocker SwarmKubernetes
Setup complexityMinutesHours to days
Learning curveLow (Docker CLI)High (new concepts)
ScalingManual or basicHPA, VPA, custom metrics
Rolling updatesBuilt-inBuilt-in, more options
Service discoveryBuilt-in DNSCoreDNS, services
EcosystemSmallerVast (Helm, operators)
Best for2-10 nodes10+ nodes, complex apps

DeployMonkey + Docker Swarm

DeployMonkey uses Docker for container orchestration. If you need multi-node Odoo deployments without Kubernetes complexity, Docker Swarm provides the right balance of simplicity and reliability.