Skip to main content

Docker Swarm Deployment

Deploy OpenLift on Docker Swarm for production-ready container orchestration with built-in load balancing, service discovery, and high availability.

Note: OpenLift container images are not yet published. To avoid implying availability, all image references are removed or commented. Replace placeholders with your own images when ready.

Prerequisites

System Requirements

  • Docker Engine (20.10.0+ recommended)
  • Docker Swarm initialized
  • Multiple nodes (3+ recommended for production)
  • Shared storage (NFS, GlusterFS, or similar for data persistence)
  • Load balancer (optional, for external traffic distribution)

Network Requirements

  • Overlay network capability
  • Ingress routing for external access
  • Inter-node communication on required Docker Swarm ports

Quick Start

Initialize Docker Swarm

# On the manager node
docker swarm init --advertise-addr <MANAGER-IP>

# On worker nodes (use the command output from init)
docker swarm join --token <TOKEN> <MANAGER-IP>:2377

# Verify cluster status
docker node ls

Deploy OpenLift Stack

# Download the Docker Swarm compose file
curl -o docker-swarm.yml https://raw.githubusercontent.com/openlift/openlift/main/docker-swarm.yml

# Deploy the stack
docker stack deploy -c docker-swarm.yml openlift

# Check services status
docker stack services openlift

Docker Swarm Compose Configuration

Complete Stack File

Create docker-swarm.yml:

version: '3.8'

services:
openlift:
# image: <to-be-published>
networks:
- openlift-network
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=mongodb://mongodb:27017/openlift
- REDIS_URL=redis://redis:6379
- MINIO_ENDPOINT=http://minio:9000
- MINIO_ACCESS_KEY=minioadmin
- MINIO_SECRET_KEY=minioadmin
- MINIO_BUCKET_NAME=openlift
- JWT_SECRET=${JWT_SECRET}
- CORS_ORIGIN=https://openlift.yourdomain.com
secrets:
- jwt_secret
- db_password
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
placement:
constraints:
- node.role == worker
resources:
limits:
memory: 2G
cpus: '1.0'
reservations:
memory: 1G
cpus: '0.5'
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s

mongodb:
# image: <set-your-image>
networks:
- openlift-network
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD_FILE=/run/secrets/db_password
- MONGO_INITDB_DATABASE=openlift
secrets:
- db_password
volumes:
- mongodb_data:/data/db
- mongodb_config:/data/configdb
deploy:
replicas: 1
placement:
constraints:
- node.labels.storage == true
resources:
limits:
memory: 2G
cpus: '1.0'
reservations:
memory: 1G
cpus: '0.5'
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 10s
retries: 5
start_period: 40s

redis:
# image: <set-your-image>
networks:
- openlift-network
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
deploy:
replicas: 1
placement:
constraints:
- node.labels.storage == true
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
cpus: '0.25'
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5

minio:
# image: <set-your-image>
networks:
- openlift-network
ports:
- "9000:9000"
- "9001:9001"
command: server /data --console-address ":9001"
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=${MINIO_PASSWORD}
volumes:
- minio_data:/data
deploy:
replicas: 1
placement:
constraints:
- node.labels.storage == true
resources:
limits:
memory: 1G
cpus: '0.5'
reservations:
memory: 512M
cpus: '0.25'
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3

nginx:
# image: <set-your-image>
networks:
- openlift-network
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- nginx_certs:/etc/nginx/certs
deploy:
replicas: 2
update_config:
parallelism: 1
delay: 10s
placement:
constraints:
- node.role == manager
depends_on:
- openlift

networks:
openlift-network:
driver: overlay
attachable: true

volumes:
mongodb_data:
driver: local
driver_opts:
type: nfs
o: addr=${NFS_SERVER},rw
device: ":/path/to/mongodb/data"
mongodb_config:
driver: local
driver_opts:
type: nfs
o: addr=${NFS_SERVER},rw
device: ":/path/to/mongodb/config"
redis_data:
driver: local
driver_opts:
type: nfs
o: addr=${NFS_SERVER},rw
device: ":/path/to/redis/data"
minio_data:
driver: local
driver_opts:
type: nfs
o: addr=${NFS_SERVER},rw
device: ":/path/to/minio/data"
nginx_certs:
driver: local

secrets:
jwt_secret:
external: true
db_password:
external: true

Environment Configuration

Create .env file:

# Application settings
JWT_SECRET=your-super-secure-jwt-secret-here
REDIS_PASSWORD=secure-redis-password
MINIO_PASSWORD=secure-minio-password

# Storage settings
NFS_SERVER=192.168.1.100

# Domain settings
DOMAIN=openlift.yourdomain.com

Production Deployment Setup

1. Prepare Swarm Cluster

# Label nodes for specific services
docker node update --label-add storage=true node1
docker node update --label-add storage=true node2

# Create overlay network
docker network create --driver overlay --attachable openlift-network

2. Create Secrets

# Create JWT secret
echo "your-super-secure-jwt-secret" | docker secret create jwt_secret -

# Create database password
echo "secure-database-password" | docker secret create db_password -

3. Set up Shared Storage

# Example NFS setup (on NFS server)
sudo mkdir -p /nfs/openlift/{mongodb,redis,minio}
sudo chown -R nobody:nobody /nfs/openlift
sudo chmod -R 755 /nfs/openlift

# Configure NFS exports
echo "/nfs/openlift *(rw,sync,no_subtree_check,no_root_squash)" >> /etc/exports
sudo exportfs -a

4. Nginx Load Balancer Configuration

Create nginx.conf:

events {
worker_connections 1024;
}

http {
upstream openlift_backend {
least_conn;
server openlift:3000 max_fails=3 fail_timeout=30s;
}

server {
listen 80;
server_name openlift.yourdomain.com;

# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl http2;
server_name openlift.yourdomain.com;

ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;

# SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

location / {
proxy_pass http://openlift_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

# Timeout settings
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}

# Health check endpoint
location /health {
access_log off;
proxy_pass http://openlift_backend/api/health;
}
}
}

Service Management

Deploy and Update Services

# Deploy the complete stack
docker stack deploy -c docker-swarm.yml openlift

# Update a specific service
# Example (placeholder): update service image when available
# docker service update --image <your-image>:<tag> openlift_openlift

# Scale services
docker service scale openlift_openlift=5

# Check service logs
docker service logs openlift_openlift --follow

Health Monitoring

# Check stack services
docker stack services openlift

# Check service details
docker service inspect openlift_openlift

# Check service tasks
docker service ps openlift_openlift

# Monitor resource usage
docker stats

Rolling Updates

# Update with zero downtime
docker service update \
--update-parallelism 1 \
--update-delay 30s \
--update-failure-action rollback \
openlift_openlift

# Monitor update progress
watch docker service ps openlift_openlift

High Availability Configuration

Multi-Node Setup

# Ensure proper node distribution
docker service update --constraint-add 'node.hostname!=node1' openlift_openlift
docker service update --placement-pref 'spread=node.hostname' openlift_openlift

Backup and Recovery

# Backup database
docker exec $(docker ps -q -f name=openlift_mongodb) \
mongodump --out /backup/$(date +%Y%m%d_%H%M%S)

# Backup MinIO data
docker exec $(docker ps -q -f name=openlift_minio) \
tar czf /backup/minio_$(date +%Y%m%d_%H%M%S).tar.gz /data

Monitoring and Alerting

# Set up health check monitoring
docker run -d --name monitoring \
--network openlift-network \
-v /var/run/docker.sock:/var/run/docker.sock \
<your-monitoring-image:tag>

Troubleshooting

Common Issues

# Check service status
docker stack services openlift

# View service logs
docker service logs openlift_openlift --tail 100

# Check node status
docker node ls

# Inspect service configuration
docker service inspect openlift_openlift --pretty

# Check network connectivity
docker network ls
docker network inspect openlift-network

Service Recovery

# Force service recreation
docker service update --force openlift_openlift

# Remove and redeploy stack
docker stack rm openlift
sleep 30
docker stack deploy -c docker-swarm.yml openlift

Performance Optimization

# Optimize container placement
docker service update \
--constraint-add 'node.labels.performance==high' \
openlift_openlift

# Adjust resource limits
docker service update \
--limit-memory 4G \
--limit-cpu 2 \
openlift_openlift

Security Considerations

  • Use Docker secrets for sensitive data
  • Enable Docker security scanning for images
  • Implement network segmentation with overlay networks
  • Regular security updates for all services
  • TLS encryption for all external communications
  • Access control with proper user permissions

Docker Swarm provides a simpler alternative to Kubernetes while still offering production-ready container orchestration. This setup ensures high availability, automatic load balancing, and easy scaling for your OpenLift deployment.