Files
Data-Coupler/DOCKER_DEPLOYMENT_EXAMPLES.md
T
Alessio Dal Santo 23c2788fcf -Aggiunta configurazione tramite dockerfile per windows e linux
-Aggiunte github actions per la compilazione dei container e l'esposizione
2026-01-16 14:16:15 +01:00

16 KiB

🎯 Esempi Pratici di Deployment Docker

Questa guida fornisce esempi pratici e scenari reali di deployment del Data-Coupler usando Docker.

📚 Indice degli Scenari

  1. Development Locale
  2. Production Single Server
  3. Staging Environment
  4. High Availability con Load Balancer
  5. Docker Swarm Cluster
  6. Kubernetes Deployment

Scenario 1: Development Locale

Caso d'uso: Sviluppatore vuole testare l'applicazione localmente

Setup Rapido

# Pull ultima versione dev
docker pull ghcr.io/alessiodalsi/data-coupler:dev-latest

# Run con hot-reload friendly settings
docker run -d \
  --name data-coupler-dev \
  -p 7550:7550 \
  -v $(pwd)/test-data:/var/lib/Data_Coupler \
  -e ASPNETCORE_ENVIRONMENT=Development \
  -e Logging__LogLevel__Default=Debug \
  ghcr.io/alessiodalsi/data-coupler:dev-latest

# Verifica logs
docker logs -f data-coupler-dev

# Accedi all'app
# http://localhost:7550

Con Docker Compose

# docker-compose.dev.yml
version: '3.8'

services:
  data-coupler:
    image: ghcr.io/alessiodalsi/data-coupler:dev-latest
    ports:
      - "7550:7550"
    volumes:
      - ./dev-data:/var/lib/Data_Coupler
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - Logging__LogLevel__Default=Debug
    restart: unless-stopped

  # Database di test (opzionale)
  test-db:
    image: mcr.microsoft.com/mssql/server:2022-latest
    environment:
      - ACCEPT_EULA=Y
      - SA_PASSWORD=YourStrong@Passw0rd
    ports:
      - "1433:1433"
# Start
docker-compose -f docker-compose.dev.yml up -d

# Stop
docker-compose -f docker-compose.dev.yml down

Scenario 2: Production Single Server

Caso d'uso: Deploy production su singolo server Linux

Setup con Systemd Integration

1. Crea lo script di deployment

# /opt/data-coupler/deploy.sh
#!/bin/bash
set -e

# Pull ultima versione
docker pull ghcr.io/alessiodalsi/data-coupler:latest

# Stop e rimuovi container esistente
docker stop data-coupler 2>/dev/null || true
docker rm data-coupler 2>/dev/null || true

# Avvia nuovo container
docker run -d \
  --name data-coupler \
  --restart unless-stopped \
  -p 7550:7550 \
  -v /var/lib/data-coupler:/var/lib/Data_Coupler \
  -e ASPNETCORE_ENVIRONMENT=Production \
  --memory="2g" \
  --cpus="2" \
  ghcr.io/alessiodalsi/data-coupler:latest

echo "Deployment completato!"
docker ps --filter name=data-coupler

2. Crea servizio systemd

# /etc/systemd/system/data-coupler.service
[Unit]
Description=Data Coupler Service
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/data-coupler
ExecStart=/opt/data-coupler/deploy.sh
ExecStop=/usr/bin/docker stop data-coupler
StandardOutput=journal

[Install]
WantedBy=multi-user.target

3. Abilita e avvia

# Permissions
chmod +x /opt/data-coupler/deploy.sh

# Enable service
sudo systemctl daemon-reload
sudo systemctl enable data-coupler.service

# Start
sudo systemctl start data-coupler.service

# Status
sudo systemctl status data-coupler.service

# Logs
journalctl -u data-coupler.service -f

Setup Nginx Reverse Proxy

# /etc/nginx/sites-available/data-coupler
server {
    listen 80;
    server_name datacoupler.example.com;

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

server {
    listen 443 ssl http2;
    server_name datacoupler.example.com;

    ssl_certificate /etc/letsencrypt/live/datacoupler.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/datacoupler.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:7550;
        proxy_http_version 1.1;
        
        # WebSocket support for Blazor
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # Headers
        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;
        
        # Timeouts
        proxy_read_timeout 300s;
        proxy_connect_timeout 75s;
    }

    # Health check endpoint
    location /health {
        proxy_pass http://localhost:7550/health;
        access_log off;
    }
}
# Abilita configurazione
sudo ln -s /etc/nginx/sites-available/data-coupler /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Scenario 3: Staging Environment

Caso d'uso: Ambiente staging per test pre-production

Docker Compose Completo

# docker-compose.staging.yml
version: '3.8'

services:
  data-coupler:
    image: ghcr.io/alessiodalsi/data-coupler:staging-latest
    container_name: data-coupler-staging
    networks:
      - staging-network
    ports:
      - "7550:7550"
    volumes:
      - staging-data:/var/lib/Data_Coupler
      - ./logs:/var/log/data-coupler
    environment:
      - ASPNETCORE_ENVIRONMENT=Staging
      - Logging__LogLevel__Default=Information
      - ConnectionStrings__DefaultConnection=Server=staging-db;Database=DataCoupler;
    depends_on:
      - staging-db
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:7550/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 1G

  staging-db:
    image: mcr.microsoft.com/mssql/server:2022-latest
    container_name: staging-db
    networks:
      - staging-network
    environment:
      - ACCEPT_EULA=Y
      - SA_PASSWORD=${DB_PASSWORD}
    volumes:
      - staging-db-data:/var/opt/mssql
    ports:
      - "1433:1433"
    restart: unless-stopped

  # Monitoring (opzionale)
  portainer:
    image: portainer/portainer-ce:latest
    container_name: portainer-staging
    networks:
      - staging-network
    ports:
      - "9000:9000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer-data:/data
    restart: unless-stopped

networks:
  staging-network:
    driver: bridge

volumes:
  staging-data:
  staging-db-data:
  portainer-data:

Environment File

# .env.staging
DB_PASSWORD=YourStrongPassword123!

Deploy Script

#!/bin/bash
# deploy-staging.sh

# Load environment
export $(cat .env.staging | xargs)

# Pull latest images
docker-compose -f docker-compose.staging.yml pull

# Deploy
docker-compose -f docker-compose.staging.yml up -d

# Check health
sleep 10
curl http://localhost:7550/health

# Show logs
docker-compose -f docker-compose.staging.yml logs -f --tail=50

Scenario 4: High Availability

Caso d'uso: Setup HA con load balancer e multiple instances

Docker Compose con Scale

# docker-compose.ha.yml
version: '3.8'

services:
  nginx-lb:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - data-coupler
    networks:
      - ha-network
    restart: unless-stopped

  data-coupler:
    image: ghcr.io/alessiodalsi/data-coupler:latest
    networks:
      - ha-network
    volumes:
      - shared-data:/var/lib/Data_Coupler
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
    deploy:
      replicas: 3
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
      resources:
        limits:
          cpus: '1'
          memory: 1G
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:7550/health"]
      interval: 10s
      timeout: 5s
      retries: 3

networks:
  ha-network:
    driver: bridge

volumes:
  shared-data:
    driver: local
    driver_opts:
      type: nfs
      o: addr=nfs-server.example.com,rw
      device: ":/exports/data-coupler"

Nginx Load Balancer Config

# nginx.conf
events {
    worker_connections 1024;
}

http {
    upstream data-coupler-backend {
        least_conn;
        
        server data-coupler:7550 max_fails=3 fail_timeout=30s;
        
        # Docker Compose scale gestisce automaticamente multiple instances
        # Se necessario, aggiungi manualmente:
        # server data-coupler-2:7550;
        # server data-coupler-3:7550;
    }

    server {
        listen 80;
        
        location / {
            proxy_pass http://data-coupler-backend;
            
            # Sticky sessions per Blazor SignalR
            ip_hash;
            
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            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_read_timeout 300s;
        }
        
        location /health {
            proxy_pass http://data-coupler-backend/health;
            access_log off;
        }
    }
}

Scale Up/Down

# Scale to 5 instances
docker-compose -f docker-compose.ha.yml up -d --scale data-coupler=5

# Scale down to 2 instances
docker-compose -f docker-compose.ha.yml up -d --scale data-coupler=2

# Check instances
docker-compose -f docker-compose.ha.yml ps

Scenario 5: Docker Swarm

Caso d'uso: Cluster multi-node con orchestrazione

Initialize Swarm

# Manager node
docker swarm init --advertise-addr <MANAGER-IP>

# Worker nodes (run on each worker)
docker swarm join --token <TOKEN> <MANAGER-IP>:2377

# Verify cluster
docker node ls

Stack Deploy

# stack-data-coupler.yml
version: '3.8'

services:
  data-coupler:
    image: ghcr.io/alessiodalsi/data-coupler:latest
    ports:
      - target: 7550
        published: 7550
        mode: host
    volumes:
      - data-coupler-data:/var/lib/Data_Coupler
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
    networks:
      - data-coupler-network
    deploy:
      mode: replicated
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
        order: start-first
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
      placement:
        constraints:
          - node.role == worker
      resources:
        limits:
          cpus: '1'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:7550/health"]
      interval: 30s
      timeout: 10s
      retries: 3

networks:
  data-coupler-network:
    driver: overlay
    attachable: true

volumes:
  data-coupler-data:
    driver: local

Deploy and Management

# Deploy stack
docker stack deploy -c stack-data-coupler.yml datacoupler

# Check services
docker stack services datacoupler

# Check tasks
docker service ps datacoupler_data-coupler

# Scale service
docker service scale datacoupler_data-coupler=5

# Update image
docker service update --image ghcr.io/alessiodalsi/data-coupler:latest \
  datacoupler_data-coupler

# View logs
docker service logs -f datacoupler_data-coupler

# Remove stack
docker stack rm datacoupler

Scenario 6: Kubernetes

Caso d'uso: Deploy su cluster Kubernetes

Namespace e ConfigMap

# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: data-coupler
---
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: data-coupler-config
  namespace: data-coupler
data:
  ASPNETCORE_ENVIRONMENT: "Production"
  ASPNETCORE_URLS: "http://+:7550"
  Logging__LogLevel__Default: "Information"

Deployment

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: data-coupler
  namespace: data-coupler
spec:
  replicas: 3
  selector:
    matchLabels:
      app: data-coupler
  template:
    metadata:
      labels:
        app: data-coupler
    spec:
      containers:
      - name: data-coupler
        image: ghcr.io/alessiodalsi/data-coupler:latest
        ports:
        - containerPort: 7550
        envFrom:
        - configMapRef:
            name: data-coupler-config
        volumeMounts:
        - name: data-volume
          mountPath: /var/lib/Data_Coupler
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
        livenessProbe:
          httpGet:
            path: /health
            port: 7550
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /health
            port: 7550
          initialDelaySeconds: 10
          periodSeconds: 5
      volumes:
      - name: data-volume
        persistentVolumeClaim:
          claimName: data-coupler-pvc

Service

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: data-coupler-service
  namespace: data-coupler
spec:
  selector:
    app: data-coupler
  ports:
  - protocol: TCP
    port: 80
    targetPort: 7550
  type: LoadBalancer

Ingress

# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: data-coupler-ingress
  namespace: data-coupler
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - datacoupler.example.com
    secretName: datacoupler-tls
  rules:
  - host: datacoupler.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: data-coupler-service
            port:
              number: 80

Persistent Volume

# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-coupler-pvc
  namespace: data-coupler
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
  storageClassName: standard

Deploy su Kubernetes

# Apply all manifests
kubectl apply -f namespace.yaml
kubectl apply -f configmap.yaml
kubectl apply -f pvc.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml

# Check status
kubectl get all -n data-coupler

# Check pods
kubectl get pods -n data-coupler

# View logs
kubectl logs -f deployment/data-coupler -n data-coupler

# Scale
kubectl scale deployment data-coupler --replicas=5 -n data-coupler

# Rolling update
kubectl set image deployment/data-coupler \
  data-coupler=ghcr.io/alessiodalsi/data-coupler:latest \
  -n data-coupler

# Check health
kubectl exec -it deployment/data-coupler -n data-coupler -- \
  curl http://localhost:7550/health

🔧 Utility Scripts

Auto-Update Script

#!/bin/bash
# auto-update.sh - Aggiorna automaticamente all'ultima versione

# Colori
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

# Config
IMAGE="ghcr.io/alessiodalsi/data-coupler:latest"
CONTAINER_NAME="data-coupler"

echo "Checking for updates..."

# Pull latest
docker pull $IMAGE

# Get current image ID
CURRENT_ID=$(docker inspect --format='{{.Image}}' $CONTAINER_NAME 2>/dev/null)
LATEST_ID=$(docker inspect --format='{{.Id}}' $IMAGE)

if [ "$CURRENT_ID" == "$LATEST_ID" ]; then
    echo -e "${GREEN}Already up to date!${NC}"
    exit 0
fi

echo -e "${GREEN}New version available! Updating...${NC}"

# Backup current database (opzionale)
echo "Creating backup..."
docker exec $CONTAINER_NAME tar czf /tmp/backup.tar.gz /var/lib/Data_Coupler
docker cp $CONTAINER_NAME:/tmp/backup.tar.gz ./backup-$(date +%Y%m%d-%H%M%S).tar.gz

# Stop and remove old container
docker stop $CONTAINER_NAME
docker rm $CONTAINER_NAME

# Start new container
docker run -d \
  --name $CONTAINER_NAME \
  --restart unless-stopped \
  -p 7550:7550 \
  -v data-coupler-data:/var/lib/Data_Coupler \
  $IMAGE

# Wait for health
for i in {1..30}; do
    if curl -sf http://localhost:7550/health > /dev/null; then
        echo -e "${GREEN}Update completed successfully!${NC}"
        exit 0
    fi
    sleep 2
done

echo -e "${RED}Update completed but health check failed${NC}"
exit 1

Backup Script

#!/bin/bash
# backup.sh - Backup database e configurazioni

BACKUP_DIR="/backups/data-coupler"
CONTAINER_NAME="data-coupler"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)

mkdir -p $BACKUP_DIR

# Backup database
docker exec $CONTAINER_NAME tar czf - /var/lib/Data_Coupler \
  > $BACKUP_DIR/backup-$TIMESTAMP.tar.gz

# Keep only last 7 days
find $BACKUP_DIR -name "backup-*.tar.gz" -mtime +7 -delete

echo "Backup completed: $BACKUP_DIR/backup-$TIMESTAMP.tar.gz"

Data Creazione: 16 Gennaio 2026
Versione: 1.0
Testato su: Docker 24.x, Docker Compose 2.x, Kubernetes 1.28+