Skip to content

chore: refactor docker-compose configuration to integrate Traefik for… #375

chore: refactor docker-compose configuration to integrate Traefik for…

chore: refactor docker-compose configuration to integrate Traefik for… #375

# ============================================================================
# Production CI/CD Pipeline - Traefik Zero-Downtime Deployment
# ============================================================================
#
# Architecture:
# Traefik (SSL/LB) → Services (auto-discovered via Docker labels)
#
# Deployment Strategy:
# Rolling update - Traefik handles graceful traffic shifting
# New containers start → health check passes → old containers removed
#
# ============================================================================
name: CI-Production
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
ENV_SOURCE: /opt/projects/prod.docs.plus/.env
ENV_FILE: .env.production
COMPOSE_FILE: docker-compose.prod.yml
DEPLOY_TAG: ${{ github.sha }}
jobs:
deploy:
name: 🚀 Deploy to Production
runs-on: prod.docs.plus
if: contains(github.event.head_commit.message, 'build') && (contains(github.event.head_commit.message, 'front') || contains(github.event.head_commit.message, 'back'))
steps:
- name: 📦 Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: 🥟 Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: 📥 Install Dependencies
run: bun install --frozen-lockfile
- name: 🔐 Prepare Environment
run: |
echo "📁 Copying environment file..."
if [ ! -f "${{ env.ENV_SOURCE }}" ]; then
echo "❌ .env file not found at ${{ env.ENV_SOURCE }}"
exit 1
fi
cp "${{ env.ENV_SOURCE }}" "${{ env.ENV_FILE }}"
# Add deploy tag
echo "DEPLOY_TAG=${{ env.DEPLOY_TAG }}" >> "${{ env.ENV_FILE }}"
# Validate required vars
for var in DATABASE_URL SUPABASE_URL SUPABASE_ANON_KEY; do
if ! grep -q "^${var}=" "${{ env.ENV_FILE }}"; then
echo "❌ ${var} not found in .env"
exit 1
fi
done
echo "✅ Environment prepared"
- name: 🏗️ Build Docker Images
run: |
echo "🔨 Building images with tag: ${{ env.DEPLOY_TAG }}"
# Load env vars for build args
set -a
source ${{ env.ENV_FILE }}
set +a
docker-compose -f ${{ env.COMPOSE_FILE }} \
--env-file ${{ env.ENV_FILE }} \
build --parallel
echo "✅ Images built"
- name: 🚀 Deploy Services
run: |
echo "🚀 Deploying services..."
# Deploy with rolling update
# Traefik automatically routes to healthy containers
docker-compose -f ${{ env.COMPOSE_FILE }} \
--env-file ${{ env.ENV_FILE }} \
up -d \
--remove-orphans \
--scale webapp=2 \
--scale rest-api=2 \
--scale hocuspocus-server=2 \
--scale hocuspocus-worker=1
echo "✅ Services deployed"
- name: ⏳ Wait for Health Checks
run: |
echo "⏳ Waiting for services to be healthy..."
sleep 30
# Check Traefik
if ! docker ps --filter "name=traefik" --filter "health=healthy" | grep -q traefik; then
echo "⚠️ Traefik not healthy yet, waiting..."
sleep 15
fi
echo "✅ Initial wait complete"
- name: 🩺 Verify Deployment
run: |
echo "🩺 Verifying deployment..."
# Check all services are running
SERVICES="traefik docsplus-redis"
for svc in $SERVICES; do
if ! docker ps --filter "name=$svc" | grep -q "$svc"; then
echo "❌ $svc is not running"
docker logs $svc --tail 50 2>/dev/null || true
exit 1
fi
done
# Check scaled services
for svc in webapp rest-api hocuspocus-server hocuspocus-worker; do
COUNT=$(docker ps --filter "name=${svc}" --format "{{.Names}}" | wc -l)
if [ "$COUNT" -eq 0 ]; then
echo "❌ No $svc containers running"
exit 1
fi
echo "✅ $svc: $COUNT container(s) running"
done
# Health check via Traefik
echo "🔍 Testing endpoints via Traefik..."
# Wait for SSL cert (first deploy might take a moment)
for i in {1..30}; do
if curl -sf -o /dev/null https://docs.plus/api/health 2>/dev/null; then
echo "✅ docs.plus is healthy"
break
fi
if [ $i -eq 30 ]; then
echo "⚠️ docs.plus health check timed out (may still be provisioning SSL)"
fi
sleep 5
done
echo "✅ Deployment verified"
- name: 🧹 Cleanup
run: |
# Remove old images
docker image prune -f --filter "until=24h"
# Remove unused volumes (careful!)
docker volume prune -f --filter "label!=keep"
echo "✅ Cleanup complete"
- name: 📊 Summary
run: |
echo "======================================"
echo "✅ DEPLOYMENT SUCCESSFUL"
echo "======================================"
echo "Tag: ${{ env.DEPLOY_TAG }}"
echo ""
echo "Services:"
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | head -20
echo ""
echo "URLs:"
echo " - https://docs.plus"
echo " - https://prodback.docs.plus"
echo "======================================"
- name: 🚨 Rollback on Failure
if: failure()
run: |
echo "⚠️ Deployment failed - attempting rollback..."
# Get previous working tag (if any)
PREV_TAG=$(docker images docsy-webapp --format "{{.Tag}}" | grep -v "${{ env.DEPLOY_TAG }}" | head -1)
if [ -n "$PREV_TAG" ] && [ "$PREV_TAG" != "latest" ]; then
echo "🔄 Rolling back to: $PREV_TAG"
sed -i "s/DEPLOY_TAG=.*/DEPLOY_TAG=$PREV_TAG/" "${{ env.ENV_FILE }}"
docker-compose -f ${{ env.COMPOSE_FILE }} \
--env-file ${{ env.ENV_FILE }} \
up -d --remove-orphans
echo "✅ Rollback complete"
else
echo "⚠️ No previous version to rollback to"
fi
# ===========================================================================
# UPTIME KUMA (Monitoring)
# ===========================================================================
deploy-uptime-kuma:
name: 🔔 Deploy Uptime Kuma
runs-on: prod.docs.plus
if: contains(github.event.head_commit.message, 'build') && contains(github.event.head_commit.message, 'uptime-kuma')
steps:
- name: 🚀 Deploy
run: |
docker network create docsplus-network 2>/dev/null || true
docker stop uptime-kuma 2>/dev/null || true
docker rm uptime-kuma 2>/dev/null || true
docker run -d \
--name uptime-kuma \
--network docsplus-network \
--restart unless-stopped \
-v uptime-kuma-data:/app/data \
--label "traefik.enable=true" \
--label "traefik.http.routers.uptime.rule=Host(\`status.docs.plus\`)" \
--label "traefik.http.routers.uptime.entrypoints=websecure" \
--label "traefik.http.routers.uptime.tls.certresolver=letsencrypt" \
--label "traefik.http.services.uptime.loadbalancer.server.port=3001" \
louislam/uptime-kuma:latest
sleep 15
echo "✅ Uptime Kuma deployed at https://status.docs.plus"