Skip to content

compose: add scale command - #5301

Open
cvas22 wants to merge 1 commit into
containerd:mainfrom
cvas22:feat/compose-scale
Open

cvas22 wants to merge 1 commit into
containerd:mainfrom
cvas22:feat/compose-scale

Conversation

@cvas22

@cvas22 cvas22 commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

I added nerdctl compose scale, another Compose command still listed as unimplemented in the command reference (tracked in #3867).

It follows docker compose scale:

  • nerdctl compose scale SERVICE=REPLICAS [SERVICE=REPLICAS...] sets the number of containers for each service.
  • Missing replicas are created and started in the background, reusing compose up with the requested scale.
  • Replicas above the requested number (for example svc-2 and svc-3 after svc=1) are stopped and removed. compose up --scale doesn't remove them, so Scale compares the service's containers with the replicas it should have and removes the rest.
  • --no-deps skips the dependencies of the scaled services. I added NoDeps to UpOptions for this, which passes types.IgnoreDependencies to ForEachService. Nothing else sets it, so compose up is unchanged.

Invalid arguments (svc, svc=x, svc=-1) and unknown services are rejected before anything is created.

Running it locally showed that scaling recreated the replicas that should have been kept: scale web=1 after scale web=3 re-created web-1. ServiceHash resets scale, but compose-go v2 keeps the number of replicas in deploy.replicas, so the hash changed with every new count. This also happens on main with compose up --scale. I made ServiceHash ignore deploy.replicas (on a copy, so the service config isn't modified). The hash of services that set deploy changes once, so their containers are recreated on the first up after upgrading.

Changes:

  • pkg/composer/scale.go: Composer.Scale
  • pkg/composer/up.go: UpOptions.NoDeps
  • pkg/composer/config.go: ServiceHash ignores deploy.replicas
  • cmd/nerdctl/compose/compose_scale.go: the command and argument parsing
  • tests: a unit test for argument parsing, and an integration test that scales up to 3 and back down to 1, checking that the kept replica isn't recreated
  • docs/command-reference.md: documented the command and removed it from the unimplemented list

Notes

I ran the tests locally, rootful, in a privileged container with nerdctl, containerd, runc, CNI and BuildKit built from this branch (docker buildx build --target out-full):

$ go test -count=1 -v -run 'TestComposeScale|TestComposeUp|TestComposeConfig' ./cmd/nerdctl/compose/ -args -test.target=nerdctl
--- PASS: TestComposeScale (101.73s)
    --- PASS: TestComposeScale/rejects_an_argument_without_replicas (0.02s)
    --- PASS: TestComposeScale/rejects_an_unknown_service (13.82s)
    --- PASS: TestComposeScale/scales_up (7.00s)
    --- PASS: TestComposeScale/scales_down (24.68s)

27 tests passed and 1 was skipped. I also ran it by hand (db and web, where web depends on db; log lines about image checks trimmed):

$ nerdctl compose scale web=3
$ nerdctl ps --format '{{.Names}} {{.ID}}'
demo-db-1 8a7bc43a6364
demo-web-1 3e69eabbe165
demo-web-2 6f5992c1b2f9
demo-web-3 255ee8967e81
$ nerdctl compose scale web=1
time="2026-10-29T04:12:02Z" level=info msg="Removing container demo-web-3"
time="2026-10-29T04:12:02Z" level=info msg="Removing container demo-web-2"
$ nerdctl ps --format '{{.Names}} {{.ID}}'
demo-db-1 8a7bc43a6364
demo-web-1 3e69eabbe165
$ nerdctl compose up -d --scale web=2
$ nerdctl ps --format '{{.Names}} {{.ID}}'
demo-db-1 8a7bc43a6364
demo-web-1 3e69eabbe165
demo-web-2 a57f174e9647
$ nerdctl compose down
$ nerdctl compose scale --no-deps web=2
$ nerdctl ps --format '{{.Names}} {{.ID}}'
demo-web-1 957d44713aea
demo-web-2 79d00132118c
$ nerdctl compose scale web
time="2026-10-29T04:12:27Z" level=fatal msg="invalid argument \"web\", should be SERVICE=REPLICAS"
$ nerdctl compose scale nope=1
time="2026-10-29T04:12:27Z" level=fatal msg="no such service: nope: not found"

Rootless is only covered by CI. This is independent of #5300 (compose wait), but both add a line to the same command list, so whichever merges second will need a trivial rebase.

@cvas22

cvas22 commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor Author

The failing linux jobs fail in TestContainerInspectUser (pulling ubuntu:23.10 fails), and on some jobs in the SOCI, cosign and systemd tests. The same jobs fail on main (run 40644999509), so they're not related to this change. TestComposeScale doesn't fail in any job: it runs in the rootless jobs and is skipped in the others.

Add nerdctl compose scale SERVICE=REPLICAS..., like docker compose scale.
Missing replicas are created and started in the background, and extra
replicas are stopped and removed. --no-deps skips the dependencies of
the scaled services, which UpOptions now supports through NoDeps.

Leave the number of replicas out of the service hash: compose-go keeps
it in deploy.replicas, so changing it with scale (or up --scale)
recreated the replicas that were kept.

Signed-off-by: Srinivas Chippagiri <cvas22@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants