Skip to content

Parallel Environments Setup - Portugal Odyssey Platform

⚠️ Historical doc. References infrastructure/scripts/ci-deploy.sh retired in Riff #50 (2026-04-30). Current deploy doctrine: GitLab CI auto-deploys qual on push to main; prod is a manual CI job (Riff #10). See docs/reference/makefile.md for the current Makefile surface.

Purpose: Configure qualification and production environments to run in parallel on the same server, sharing the existing Traefik instance while maintaining security and isolation.

Date: 2025-01-03


Current Server State

Existing Services

  1. Traefik Instance (/opt/traefik-standalone)
  2. Container: traefik
  3. Network: traefik (bridge)
  4. Ports: 80, 443, 8080
  5. Email: zmeireles@gmail.com

  6. Existing Webapp (/opt/experiencias100fim)

  7. Services: web, strapi, db
  8. Network: traefik (external)
  9. Domains: x100f.codecomedy.dev, cms.x100f.codecomedy.dev

Required Changes

  1. Network Configuration
  2. All environments must use the existing traefik network (not po-traefik-public)
  3. Each environment needs isolated internal networks
  4. Production should use named external networks for shared infrastructure

  5. Container Naming

  6. All containers must have unique names with environment suffix
  7. Format: po-<service>-<env> (e.g., po-postgres-qual, po-postgres-prod)

  8. Volume Naming

  9. All volumes must be environment-specific
  10. Format: po-<service>-<env> (e.g., po-postgres-data-qual)

  11. Traefik Router Names

  12. All router names must be unique across all environments
  13. Format: <service>-<env> (e.g., public-fo-qual, public-fo-prod)

  14. Port Conflicts

  15. No services should expose ports directly (only Traefik)
  16. All services communicate internally via Docker networks

Configuration Changes Required

1. Update Production Compose File

File: infrastructure/compose/production.yml

Changes: - Change po-traefik-public to use existing traefik network - Ensure all networks are properly isolated - Add environment suffix to all container names - Add environment suffix to all volume names - Ensure all Traefik router names are unique

2. Update Qualification Compose File

File: infrastructure/compose/qualification.yml

Changes: - Change po-traefik-public to use existing traefik network - Ensure all networks are properly isolated - Verify all container names have -qual suffix - Verify all volume names have -qual suffix - Verify all Traefik router names have -qual suffix

3. Update Infrastructure Compose File

File: infrastructure/compose/infrastructure.yml

Changes: - Remove Traefik service (using existing one) - Update network references to use existing traefik network - Ensure infrastructure services can be shared or isolated

4. Update Deployment Scripts

File: infrastructure/scripts/ci-deploy.sh

Changes: - Ensure script doesn't try to start Traefik - Verify network creation logic - Update health check endpoints


Network Architecture

┌─────────────────────────────────────────────────────────┐
│                    Traefik (Shared)                      │
│              Network: traefik (bridge)                  │
│              Container: traefik                          │
└─────────────────────────────────────────────────────────┘
        ┌─────────────────┼─────────────────┐
        │                 │                 │
        ▼                 ▼                 ▼
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ Existing     │  │ PO Platform  │  │ PO Platform  │
│ Webapp       │  │ Qual         │  │ Prod         │
│              │  │              │  │              │
│ Network:     │  │ Network:     │  │ Network:     │
│ traefik      │  │ traefik      │  │ traefik      │
│              │  │ + internal   │  │ + internal   │
└──────────────┘  └──────────────┘  └──────────────┘

Network Isolation Strategy

  1. Shared Network: traefik (external, existing)
  2. Used by: Traefik, all frontend services, all services with Traefik labels
  3. Purpose: Allow Traefik to route to services

  4. Qualification Internal Networks:

  5. po-postgres-network-qual (bridge, isolated)
  6. po-redis-network-qual (bridge, isolated)
  7. po-rabbitmq-network-qual (bridge, isolated)
  8. po-elasticsearch-network-qual (bridge, isolated)
  9. po-internal-qual (bridge, isolated)

  10. Production Internal Networks:

  11. po-postgres-network-prod (bridge, isolated)
  12. po-redis-network-prod (bridge, isolated)
  13. po-rabbitmq-network-prod (bridge, isolated)
  14. po-elasticsearch-network-prod (bridge, isolated)
  15. po-internal-prod (bridge, isolated)

Container Naming Convention

All containers must follow this pattern:

  • Qualification: po-<service>-qual
  • Production: po-<service>-prod

Examples: - po-postgres-qual, po-postgres-prod - po-api-gateway-qual, po-api-gateway-prod - po-strapi-cms-qual, po-strapi-cms-prod


Volume Naming Convention

All volumes must follow this pattern:

  • Qualification: po-<service>-<env>-qual
  • Production: po-<service>-<env>-prod

Examples: - po-postgres-data-qual, po-postgres-data-prod - po-redis-data-qual, po-redis-data-prod - po-strapi-uploads-qual, po-strapi-uploads-prod


Traefik Router Naming Convention

All Traefik router names must be unique:

  • Qualification: <service>-qual
  • Production: <service>-prod

Examples: - public-fo-qual, public-fo-prod - api-gateway-qual, api-gateway-prod - strapi-cms-qual, strapi-cms-prod


Domain Naming Convention

  • Qualification: *-qual.portugalodyssey.pt
  • Production: *.portugalodyssey.pt (no suffix)

Examples: - Qual: api-qual.portugalodyssey.pt, cms-qual.portugalodyssey.pt - Prod: api.portugalodyssey.pt, cms.portugalodyssey.pt


Changes Required in Existing Services

Traefik Configuration

No changes required - The existing Traefik instance will automatically discover new services via Docker labels.

Existing Webapp

No changes required - The existing webapp will continue to work as-is since: - It uses the same traefik network - Router names are different (x100f-* vs po-*-qual/po-*-prod) - Domains are different (*.codecomedy.dev vs *.portugalodyssey.pt)


Security Considerations

  1. Network Isolation: Each environment's internal services are isolated in separate networks
  2. Volume Isolation: Each environment has separate volumes
  3. Database Isolation: Separate databases per environment
  4. Traefik Routing: Traefik routes based on domain names, ensuring no cross-environment access
  5. Container Isolation: Containers cannot communicate across environments except via Traefik

Deployment Checklist

Before deploying:

  • [ ] Verify existing Traefik network exists: docker network ls | grep traefik
  • [ ] Verify no port conflicts (all services use internal networking)
  • [ ] Verify all container names are unique
  • [ ] Verify all volume names are unique
  • [ ] Verify all Traefik router names are unique
  • [ ] Verify DNS records point to correct domains
  • [ ] Test qualification deployment first
  • [ ] Test production deployment after qualification is stable

Testing Parallel Deployment

  1. Start Qualification:

    cd /opt/po-platform
    docker compose -f infrastructure/compose/infrastructure.yml \
                   -f infrastructure/compose/qualification.yml \
                   --env-file .env.qual up -d
    

  2. Verify Qualification:

    docker ps | grep po-.*-qual
    curl -I https://api-qual.portugalodyssey.pt/health
    

  3. Start Production (while qualification is running):

    docker compose -f infrastructure/compose/infrastructure.yml \
                   -f infrastructure/compose/production.yml \
                   --env-file .env.prod up -d
    

  4. Verify Both Running:

    docker ps | grep po-
    # Should see both qual and prod containers
    

  5. Verify No Conflicts:

    # Check for duplicate container names
    docker ps --format '{{.Names}}' | sort | uniq -d
    # Should return empty
    
    # Check for duplicate volumes
    docker volume ls --format '{{.Name}}' | sort | uniq -d
    # Should return empty
    


Troubleshooting

Issue: Container name already exists

Solution: Ensure all container names include environment suffix

Issue: Volume name conflict

Solution: Ensure all volume names include environment suffix

Issue: Traefik routing to wrong service

Solution: Verify router names are unique and domain names are correct

Issue: Services can't communicate

Solution: Verify services are on the same internal network

Issue: Port conflicts

Solution: Ensure no services expose ports directly (only Traefik should expose ports)


Last Updated: 2025-01-03