version: '3.8' networks: maple-private-prod: external: true maple-public-prod: external: true secrets: maplepress_jwt_secret: external: true redis_password: external: true meilisearch_master_key: external: true # Uncomment if using S3/SeaweedFS: # s3_access_key: # external: true # s3_secret_key: # external: true services: backend: image: registry.digitalocean.com/ssp/maplepress_backend:latest hostname: backend networks: - maple-public-prod # Receive requests from NGINX - maple-private-prod # Access databases secrets: - maplepress_jwt_secret - redis_password - meilisearch_master_key # Uncomment if using S3: # - s3_access_key # - s3_secret_key environment: # Application Configuration - APP_ENVIRONMENT=production - APP_VERSION=${APP_VERSION:-1.0.0} # HTTP Server Configuration - SERVER_HOST=0.0.0.0 - SERVER_PORT=8000 # Cassandra Database Configuration # Use all 3 Cassandra nodes for high availability - DATABASE_HOSTS=cassandra-1:9042,cassandra-2:9042,cassandra-3:9042 - DATABASE_KEYSPACE=maplepress - DATABASE_CONSISTENCY=QUORUM - DATABASE_REPLICATION=3 - DATABASE_MIGRATIONS_PATH=file://migrations # Meilisearch Configuration - MEILISEARCH_HOST=http://meilisearch:7700 # Logger Configuration - LOGGER_LEVEL=info - LOGGER_FORMAT=json # S3/Object Storage Configuration (if using) # - AWS_ENDPOINT=https://your-region.digitaloceanspaces.com # - AWS_REGION=us-east-1 # - AWS_BUCKET_NAME=maplepress-prod # Read secrets and set as environment variables using entrypoint entrypoint: ["/bin/sh", "-c"] command: - | export APP_JWT_SECRET=$$(cat /run/secrets/maplepress_jwt_secret) export CACHE_PASSWORD=$$(cat /run/secrets/redis_password) export MEILISEARCH_API_KEY=$$(cat /run/secrets/meilisearch_master_key) # Uncomment if using S3: # export AWS_ACCESS_KEY=$$(cat /run/secrets/s3_access_key) # export AWS_SECRET_KEY=$$(cat /run/secrets/s3_secret_key) # Set Redis configuration export CACHE_HOST=redis export CACHE_PORT=6379 export CACHE_DB=0 # Start the backend exec /app/maplepress-backend deploy: replicas: 1 placement: constraints: - node.labels.backend == true restart_policy: condition: on-failure delay: 10s max_attempts: 3 resources: limits: memory: 1G cpus: '1.0' reservations: memory: 512M cpus: '0.5' update_config: parallelism: 1 delay: 10s failure_action: rollback order: start-first # Zero-downtime: start new before stopping old healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "--header=X-Tenant-ID: healthcheck", "http://localhost:8000/health"] interval: 30s timeout: 5s retries: 3 start_period: 60s