Deploy: drop cpus: limits and stop assuming docker compose exists

Two NAS realities, both hit on a real Synology box.

- "NanoCPUs" error part-way through the project build: `cpus:` maps to the
  NanoCPUs field, which DSM's Docker daemon rejects. Removed from all three
  services (and from .env.prod.example). mem_limit uses the much older Memory
  field and works, so memory caps remain the throttle. Noted in the header
  next to the other DSM constraints.
- `docker compose build` on DSM: "'compose' is not a docker command". DSM and
  QTS ship the standalone `docker-compose` binary with no plugin subcommand,
  so every one of the script's 21 compose invocations was wrong for the target
  platform. The script now detects which is present, and only passes `--wait`
  when it finds v2 — on v1 it falls back to the health_gate it already had,
  which is also now run after `up` on both paths.

That the build reached container creation before failing says their compose
parses the rest of the file (anchors, profiles, service_completed_successfully,
top-level name), so this was a daemon-level rejection, not a schema one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nux3LCu4zP9nih4BRhPyHw
This commit is contained in:
2026-09-14 20:09:32 +02:00
co-authored by Claude Opus 5
parent f3dcd938b1
commit 2f03bee45b
3 changed files with 43 additions and 10 deletions
+4 -3
View File
@@ -21,6 +21,10 @@
# Start: ./deploy/webmail.sh up
# Manual: docker compose up -d (reads .env from this directory)
#
# Likewise, no `cpus:` limits: that maps to NanoCPUs, which DSM's Docker
# daemon rejects ("NanoCPUs can not be set"). mem_limit uses the much older
# Memory field and works fine, so memory caps are the throttle here.
#
# Interpolation here must stay on the oldest, dumbest forms: ${VAR} and
# ${VAR:-default}. DSM's bundled Compose rejects `${VAR:?message}` with
# "invalid interpolation format", and rejects `include:` outright. Required
@@ -224,7 +228,6 @@ services:
migrate: { condition: service_completed_successfully }
restart: unless-stopped
mem_limit: ${API_MEM_LIMIT:-512m}
cpus: ${API_CPUS:-1.0}
logging: *logging
worker-sync:
@@ -243,7 +246,6 @@ services:
migrate: { condition: service_completed_successfully }
restart: unless-stopped
mem_limit: ${WORKER_SYNC_MEM_LIMIT:-512m}
cpus: ${WORKER_CPUS:-1.5}
# Leases are released on SIGTERM (workers/run.py targets <10 s); give it room.
stop_grace_period: 30s
logging: *logging
@@ -262,7 +264,6 @@ services:
migrate: { condition: service_completed_successfully }
restart: unless-stopped
mem_limit: ${WORKER_JOBS_MEM_LIMIT:-640m}
cpus: ${WORKER_CPUS:-1.5}
stop_grace_period: 30s
logging: *logging