name: gochat-production x-gochat-image: &gochat-image ${GOCHAT_IMAGE_REF:?set GOCHAT_IMAGE_REF to an immutable image digest} x-gochat-environment: &gochat-environment GOCHAT_ENV: production GOCHAT_SERVER_HOST: 0.0.0.0 GOCHAT_SERVER_PORT: 3000 GOCHAT_SERVER_MODE: release GOCHAT_SERVER_CORS_ALLOWED_ORIGINS: ${GOCHAT_SERVER_CORS_ALLOWED_ORIGINS:?set production CORS origins} GOCHAT_DATABASE_DSN: ${GOCHAT_DATABASE_DSN:-postgres://${POSTGRES_USER:-gochat}:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-gochat_production}?sslmode=disable} GOCHAT_DATABASE_RUN_MIGRATIONS: "false" GOCHAT_DATABASE_MIGRATIONS_PATH: /app/migrations GOCHAT_REDIS_DSN: redis://:${REDIS_PASSWORD:?set REDIS_PASSWORD}@redis:6379 GOCHAT_SEARCH_ENGINE: meilisearch GOCHAT_SEARCH_HOST: http://meilisearch:7700 GOCHAT_SEARCH_API_KEY: ${MEILI_MASTER_KEY:?set MEILI_MASTER_KEY} GOCHAT_JWT_SECRET: ${GOCHAT_JWT_SECRET:?set GOCHAT_JWT_SECRET} GOCHAT_JWT_PREVIOUS_SECRETS: ${GOCHAT_JWT_PREVIOUS_SECRETS:-} GOCHAT_LOG_LEVEL: info GOCHAT_LOG_FORMAT: json GOCHAT_STORAGE_PROVIDER: local GOCHAT_STORAGE_LOCAL_PATH: /app/storage/uploads services: postgres: image: ${POSTGRES_IMAGE_REF:-pgvector/pgvector:pg16@sha256:ccc6e83d6e35e931dc7c5def2022729d5a6c370318d099181995567ff1fb4d6b} restart: always environment: POSTGRES_DB: ${POSTGRES_DB:-gochat_production} POSTGRES_USER: ${POSTGRES_USER:-gochat} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 5s timeout: 5s retries: 20 deploy: resources: limits: memory: 1G redis: image: ${REDIS_IMAGE_REF:-redis:7-alpine@sha256:ff02b58f971e7d7d156a1267e283fcbbeee91773b6aa36c49dac28ecfe28eadf} restart: always command: ["redis-server", "--requirepass", "${REDIS_PASSWORD:?set REDIS_PASSWORD}", "--appendonly", "yes", "--maxmemory", "512mb", "--maxmemory-policy", "allkeys-lru"] environment: REDIS_PASSWORD: ${REDIS_PASSWORD:?set REDIS_PASSWORD} volumes: - redis_data:/data healthcheck: test: ["CMD-SHELL", "redis-cli -a '$${REDIS_PASSWORD}' ping"] interval: 5s timeout: 5s retries: 20 deploy: resources: limits: memory: 512M meilisearch: image: ${MEILI_IMAGE_REF:-getmeili/meilisearch:v1.13@sha256:bed3fb650e62da53145777204891159242f6ea4ce69e215b36223af4aa64a0ae} restart: always environment: MEILI_ENV: production MEILI_MASTER_KEY: ${MEILI_MASTER_KEY:?set MEILI_MASTER_KEY} MEILI_NO_ANALYTICS: "true" volumes: - meili_data:/meili_data healthcheck: test: ["CMD", "wget", "--no-verbose", "--spider", "http://127.0.0.1:7700/health"] interval: 5s timeout: 5s retries: 20 gochat: image: *gochat-image restart: always stop_grace_period: ${GOCHAT_STOP_GRACE_PERIOD:-35s} depends_on: postgres: condition: service_healthy redis: condition: service_healthy meilisearch: condition: service_healthy environment: *gochat-environment ports: - "127.0.0.1:${GOCHAT_PORT:-3000}:3000" volumes: - gochat_storage:/app/storage healthcheck: test: ["CMD", "wget", "-q", "-T", "3", "-O", "/dev/null", "http://127.0.0.1:3000/ready"] interval: 10s timeout: 5s start_period: 15s retries: 30 deploy: resources: limits: memory: 512M cpus: "1.0" reservations: memory: 256M cpus: "0.5" worker: image: *gochat-image restart: always stop_grace_period: ${GOCHAT_STOP_GRACE_PERIOD:-35s} depends_on: gochat: condition: service_healthy postgres: condition: service_healthy redis: condition: service_healthy meilisearch: condition: service_healthy command: ["worker"] healthcheck: disable: true environment: <<: *gochat-environment GOCHAT_DATABASE_RUN_MIGRATIONS: "false" volumes: - gochat_storage:/app/storage deploy: resources: limits: memory: 512M cpus: "1.0" migrate: image: *gochat-image profiles: ["ops"] depends_on: postgres: condition: service_healthy entrypoint: ["/app/migrate"] command: ["up"] restart: "no" environment: <<: *gochat-environment GOCHAT_DATABASE_DSN: postgres://${POSTGRES_USER:-gochat}:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-gochat_production}?sslmode=disable&lock_timeout=5000&statement_timeout=900000 GOCHAT_DATABASE_RUN_MIGRATIONS: "false" backup: image: *gochat-image user: "0:0" profiles: ["ops"] depends_on: postgres: condition: service_healthy entrypoint: ["/app/scripts/db_backup.sh"] restart: "no" environment: GOCHAT_DATABASE_DSN: postgres://${POSTGRES_USER:-gochat}:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-gochat_production}?sslmode=disable GOCHAT_STORAGE_PATH: /source/storage/uploads GOCHAT_CONNECTOR_BACKUP_FILE: /source/connector/${GOCHAT_CONNECTOR_BACKUP_NAME:-latest.db} GOCHAT_BACKUP_DIR: /backup/local GOCHAT_BACKUP_OFFSITE_DIR: /backup/offsite GOCHAT_BACKUP_PASSPHRASE_FILE: /run/secrets/backup-passphrase GOCHAT_BACKUP_RETENTION_DAYS: ${GOCHAT_BACKUP_RETENTION_DAYS:-30} GOCHAT_VERSION: ${GOCHAT_IMAGE_REF} volumes: - gochat_storage:/source/storage:ro - shangwutong_backups:/source/connector:ro - ${GOCHAT_BACKUP_DIR:-./backups/local}:/backup/local - type: bind source: ${GOCHAT_BACKUP_OFFSITE_DIR:?set an existing external off-site mount point} target: /backup/offsite bind: create_host_path: false - ${GOCHAT_BACKUP_PASSPHRASE_FILE:-./.secrets/backup-passphrase}:/run/secrets/backup-passphrase:ro restore: image: *gochat-image user: "0:0" profiles: ["ops"] depends_on: postgres: condition: service_healthy entrypoint: ["/app/scripts/db_restore.sh"] command: ["/backup/offsite/${GOCHAT_RESTORE_BUNDLE:-missing.tar.enc}"] restart: "no" environment: GOCHAT_DATABASE_DSN: postgres://${POSTGRES_USER:-gochat}:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-gochat_production}?sslmode=disable GOCHAT_STORAGE_PATH: /restore/storage/uploads GOCHAT_CONNECTOR_DB_PATH: /restore/connector/connector.db GOCHAT_BACKUP_PASSPHRASE_FILE: /run/secrets/backup-passphrase volumes: - gochat_storage:/restore/storage - shangwutong_data:/restore/connector - type: bind source: ${GOCHAT_BACKUP_OFFSITE_DIR:?set an existing external off-site mount point} target: /backup/offsite read_only: true bind: create_host_path: false - ${GOCHAT_BACKUP_PASSPHRASE_FILE:-./.secrets/backup-passphrase}:/run/secrets/backup-passphrase:ro shangwutong: image: ${SHANGWUTONG_IMAGE_REF:?set SHANGWUTONG_IMAGE_REF to an immutable image digest} restart: always stop_grace_period: ${SWT_SHUTDOWN_TIMEOUT:-30s} environment: SWT_CONNECTOR_LISTEN: :9100 SWT_CONNECTOR_DB_PATH: /data/connector.db GOCHAT_BASE_URL: http://gochat:3000 GOCHAT_CONNECTOR_SERVICE_TOKEN: ${GOCHAT_CONNECTOR_SERVICE_TOKEN:-} SWT_MAX_INFLIGHT_HEARTBEATS: ${SWT_MAX_INFLIGHT_HEARTBEATS:-64} SWT_INBOUND_WORKERS: ${SWT_INBOUND_WORKERS:-8} SWT_OUTBOUND_WORKERS: ${SWT_OUTBOUND_WORKERS:-8} SWT_SHUTDOWN_TIMEOUT: ${SWT_SHUTDOWN_TIMEOUT:-30s} volumes: - shangwutong_data:/data - shangwutong_backups:/backup healthcheck: test: ["CMD", "wget", "-q", "-T", "3", "-O", "/dev/null", "http://127.0.0.1:9100/readyz"] interval: 30s timeout: 5s start_period: 15s retries: 3 deploy: resources: limits: memory: 512M cpus: "1.0" reservations: memory: 128M cpus: "0.25" volumes: postgres_data: redis_data: meili_data: gochat_storage: shangwutong_data: shangwutong_backups: