feat(compose): add horizontal scaling and service replicas support (#2579) - #5421
feat(compose): add horizontal scaling and service replicas support (#2579)#5421mini0n-ai wants to merge 3 commits into
Conversation
| compose.serviceScales && compose.serviceScales.length > 0 | ||
| ? `${[...compose.serviceScales] | ||
| .sort((a, b) => a.serviceName.localeCompare(b.serviceName)) | ||
| .map((scale) => `--scale ${scale.serviceName}=${scale.replicas}`) |
There was a problem hiding this comment.
Service Name Command Injection
The scaling API accepts any nonempty serviceName and persists it. Later Compose and Stack deployments insert that value directly into shell commands without quoting it. A user with deployment permission can store a name containing shell metacharacters and cause commands to run on the deployment host during a later deployment. Quote the complete scale argument or restrict input to valid Compose service names. The Stack scaling block at lines 73–76 has the same problem.
How this was verified: The unrestricted API value is stored in serviceScales, passed into deployment command generation, and executed through the shell without argument quoting.
| if (compose.composeType === "docker-compose") { | ||
| const { COMPOSE_PATH } = paths(!!compose.serverId); | ||
| const projectPath = join(COMPOSE_PATH, compose.appName, "code"); | ||
| const scaleCommand = `cd ${quote([projectPath])} && env -i PATH="$PATH" HOME="$HOME" docker compose -p ${quote([compose.appName])} up -d --no-build --scale ${quote([`${serviceName}=${replicas}`])} ${quote([serviceName])}`; |
There was a problem hiding this comment.
Configured Compose File Ignored
Dynamic scaling runs Docker Compose from the repository root without passing the configured composePath. For a supported nested file such as ./deploy/docker-compose.yml, Docker either finds no configuration or loads an unrelated root-level file, causing scaling to fail or target the wrong project definition. Build this command with the same file, environment-file, and project-directory flags used by createCommand.
| .map( | ||
| (s) => | ||
| `docker service scale ${compose.appName}_${s.serviceName}=${s.replicas} >/dev/null 2>&1 || true;`, | ||
| ) |
There was a problem hiding this comment.
Each post-deploy Swarm scale command discards its output and converts failures into success with || true. If a stored service no longer exists or Swarm rejects the operation, the deployment is still marked done even though the requested replica target was not applied. Let this required step fail the deployment, or verify and report the resulting replica state explicitly.
| serviceScales: jsonb("serviceScales") | ||
| .$type< | ||
| Array<{ | ||
| serviceName: string; | ||
| replicas: number; | ||
| }> | ||
| >() | ||
| .default([]), |
There was a problem hiding this comment.
This adds the persisted serviceScales column to the Drizzle schema without adding a database migration. Production startup applies the committed SQL migrations, so existing databases will not contain this column. ORM reads or scaling updates involving compose will therefore fail with a missing-column database error after rollout. Generate and commit the corresponding migration and snapshot update.
|
Updated with fixes addressing the automated review feedback:
Ready for review! |
What is this PR about?
This PR introduces horizontal scaling and replica management for Docker Compose services, addressing issue #2579.
Key Additions
packages/server/src/db/schema/compose.ts): AddedserviceScalesjsonb column to store per-service replica targets with strict Zod validation schema (apiScaleComposeService).packages/server/src/utils/builders/compose.ts): Injects deterministic--scale <service>=<replicas>flags for docker-compose deployments and Docker Swarmdocker service scale <appName>_<service>=<replicas>commands for stack deployments.packages/server/src/services/compose.ts,apps/dokploy/server/api/routers/compose.ts): AddedscaleComposeServiceandcompose.scaleServicetRPC procedure with audit logging and RBAC permission checks, enabling dynamic scaling of individual compose services without full rebuilds.apps/dokploy/__test__/compose/compose-replicas-scaling.test.ts): Verified--scalegeneration, multi-service deterministic ordering, Swarm scale handling, and backward compatibility.Checklist
canarybranch.Issues related (if applicable)
closes #2579
/claim #2579
Base L2 Payout Address:
0x46D5318E4397cFcBED06a235c1604E473682Ea1FThe PR is not safe to merge until the command-injection path, missing migration, incorrect Compose-file selection, and hidden Swarm scaling failures are addressed.
Summary
serviceScalesto the Compose model and request validation.Reviews (1) · Last reviewed commit: "feat(compose): add horizontal scaling an..."