Skip to content

build: Add per-step CPU and memory resource limits#3876

Merged
tonistiigi merged 1 commit into
docker:masterfrom
jirimoravcik:feat/per-step-resource-limits
Jun 10, 2026
Merged

build: Add per-step CPU and memory resource limits#3876
tonistiigi merged 1 commit into
docker:masterfrom
jirimoravcik:feat/per-step-resource-limits

Conversation

@jirimoravcik

@jirimoravcik jirimoravcik commented May 29, 2026

Copy link
Copy Markdown
Contributor

Port of moby/buildkit#6569 to buildx. Adds --resource row with things like --memory, --memory-swap, --cpu-shares, --cpu-period, --cpu-quota, --cpuset-cpus, and --cpuset-mems to build, plus the equivalent bake target attributes

@crazy-max crazy-max left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks but I don't think Buildx should expose this as seven new top-level build flags and seven independent bake fields.

Can we make the Buildx API a single extensible resource collection instead? For CLI, I think --resource fits better with existing repeatable buildx flags:

--resource=memory=2g --resource=memory-swap=4g --resource=cpu-quota=50000

For bake, I think this should mirror that as one target field, like:

resources = ["memory=2g", "memory-swap=4g", "cpu-quota=50000"]

That keeps the user-facing API smaller, matches the existing repeatable key/value style, and avoids adding a new flag and bake field every time BuildKit grows another resource knob.

I also don't think we should add these to Compose x-bake. New Compose build fields should be added upstream in https://github.com/compose-spec/compose-spec first and implemented in https://github.com/compose-spec/compose-go, then Buildx can consume them from the normal Compose build model. Expanding x-bake for new fields moves the schema in the wrong place and we plan to deprecate it: #3025

@jirimoravcik

Copy link
Copy Markdown
Contributor Author

Thanks but I don't think Buildx should expose this as seven new top-level build flags and seven independent bake fields.

Can we make the Buildx API a single extensible resource collection instead? For CLI, I think --resource fits better with existing repeatable buildx flags:

--resource=memory=2g --resource=memory-swap=4g --resource=cpu-quota=50000

For bake, I think this should mirror that as one target field, like:

resources = ["memory=2g", "memory-swap=4g", "cpu-quota=50000"]

That keeps the user-facing API smaller, matches the existing repeatable key/value style, and avoids adding a new flag and bake field every time BuildKit grows another resource knob.

I also don't think we should add these to Compose x-bake. New Compose build fields should be added upstream in https://github.com/compose-spec/compose-spec first and implemented in https://github.com/compose-spec/compose-go, then Buildx can consume them from the normal Compose build model. Expanding x-bake for new fields moves the schema in the wrong place and we plan to deprecate it: #3025

Thanks for the review. So the existing:

flags.StringVarP(&ignore, "memory", "m", "", "Memory limit")
	flags.MarkHidden("memory")

	flags.StringVar(&ignore, "memory-swap", "", `Swap limit equal to memory plus swap: "-1" to enable unlimited swap`)
	flags.MarkHidden("memory-swap")

	flags.Int64VarP(&ignoreInt, "cpu-shares", "c", 0, "CPU shares (relative weight)")
	flags.MarkHidden("cpu-shares")

	flags.Int64Var(&ignoreInt, "cpu-period", 0, "Limit the CPU CFS (Completely Fair Scheduler) period")
	flags.MarkHidden("cpu-period")

	flags.Int64Var(&ignoreInt, "cpu-quota", 0, "Limit the CPU CFS (Completely Fair Scheduler) quota")
	flags.MarkHidden("cpu-quota")

	flags.StringVar(&ignore, "cpuset-cpus", "", `CPUs in which to allow execution ("0-3", "0,1")`)
	flags.MarkHidden("cpuset-cpus")

	flags.StringVar(&ignore, "cpuset-mems", "", `MEMs in which to allow execution ("0-3", "0,1")`)
	flags.MarkHidden("cpuset-mems")

should stay there, right? or do we want to remove it as well?

@jirimoravcik
jirimoravcik force-pushed the feat/per-step-resource-limits branch from 7be227d to f3d3173 Compare May 29, 2026 17:39
@tonistiigi

Copy link
Copy Markdown
Member

I think we want to keep the existing flags (and connect them with --resource) but leave them hidden. User's shouldn't use them, but if you have an old command there is no need to error.

For the bake format, I guess it should be a struct (or double format like the cache and output options).

@crazy-max

Copy link
Copy Markdown
Member

@jirimoravcik Sorry if it was not clear but yes we can keep the existing flags as @tonistiigi explained above.

@crazy-max crazy-max added this to the v0.35.0 milestone Jun 2, 2026
@jirimoravcik
jirimoravcik force-pushed the feat/per-step-resource-limits branch 4 times, most recently from e92893f to 2f56a6b Compare June 4, 2026 22:29
@jirimoravcik
jirimoravcik requested a review from crazy-max June 4, 2026 22:31
CPUSetMems *string `json:"cpuset-mems,omitempty"`
}

func (r *ResourcesConfig) Merge(other *ResourcesConfig) *ResourcesConfig {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should avoid mutating either input and shouldn't return other directly.

Target.Merge uses this while resolving inherited targets. If a base target has resources, the current Merge can share the base target's *ResourcesConfig pointer with the resolved child. If the child also sets one resource field, r.Merge(other) mutates that shared config, so the child value can leak into the base target or into another target inheriting the same base.

Can we make this return a fresh ResourcesConfig (or clone before merging), and add a test with two targets inheriting the same base where only one child overrides a resource field?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It now returns a fresh ResourcesConfig. Added a test (fails with the old logic, passes with the new one)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Port of moby/buildkit#6569 to buildx. Adds --memory, --memory-swap,
--cpu-shares, --cpu-period, --cpu-quota, --cpuset-cpus, and --cpuset-mems
flags to build, plus the equivalent bake target attributes and compose
x-bake fields.

Signed-off-by: Jiří Moravčík <jiri.moravcik@gmail.com>
@jirimoravcik
jirimoravcik force-pushed the feat/per-step-resource-limits branch from 2f56a6b to 80b2293 Compare June 8, 2026 13:39
@jirimoravcik
jirimoravcik requested a review from crazy-max June 8, 2026 13:40

@crazy-max crazy-max left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

PTAL @tonistiigi

@crazy-max
crazy-max requested a review from tonistiigi June 8, 2026 13:59
Comment thread bake/bake.go
} else {
t.Ulimits = o.ArrValue
}
case "resources":

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The override keys seem to be undocumented in docs/reference/bake

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah indeed should be done in https://docs.docker.com/build/bake/overrides/

fmt.Fprintf(tw, "Resource Limits:\t%s\n", out.Config.Ulimit)
}
if out.Config.Memory != "" {
fmt.Fprintf(tw, "Memory:\t%s\n", out.Config.Memory)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These fields should have friendlier printing than just big integer.

Comment thread bake/bake.go
if len(keys) != 3 {
return nil, errors.Errorf("invalid key %s, resources requires name", parts[0])
}
if len(parts) == 2 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this is already guaranteed by the len check in L582

@tonistiigi
tonistiigi merged commit 76703de into docker:master Jun 10, 2026
142 of 144 checks passed
eleboucher pushed a commit to eleboucher/runner that referenced this pull request Jul 9, 2026
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [buildx](https://github.com/docker/buildx) |  | minor | `v0.34.1` → `v0.35.0` |
| [buildx](https://github.com/docker/buildx) | uses-with | minor | `v0.34.1` → `v0.35.0` |

---

### Release Notes

<details>
<summary>docker/buildx (buildx)</summary>

### [`v0.35.0`](https://github.com/docker/buildx/releases/tag/v0.35.0)

[Compare Source](docker/buildx@v0.34.1...v0.35.0-rc2)

buildx 0.35.0

Welcome to the v0.35.0 release of buildx!

Please try out the release binaries and report any issues at
<https://github.com/docker/buildx/issues>.

##### Contributors

- CrazyMax
- Tõnis Tiigi
- Sebastiaan van Stijn
- Areeb Ahmed
- Jiří Moravčík
- Sopho Merkviladze
- Akihiro Suda
- Jonathan A. Sternberg

##### Notable Changes

- Local output now supports a `mode=delete` attribute for build and bake commands. This mode replaces the destination directory with the build result instead of merging it. Similar to the `--delete` flag in rsync. For safety, this mode is only allowed if the destination directory is a subdirectory of the working directory. To export to other destinations, `--allow=buildx.local.delete` needs to be provided or the action confirmed by the user in the TUI. When exporting multi-platform results, this mode requires BuildKit v0.31.0+. [#&#8203;3883](docker/buildx#3883)
- Source policies now support the new exec proxy feature of BuildKit v0.31.0+ that captures the network traffic of your build steps. To opt in to network proxy, your Dockerfile.rego source policy needs to return `caps: { "exec.proxy": true }` in the evaluation decision. After opting in, you can control what network requests are allowed to be made by the run steps with policy rules for regular `input.http` sources, similar to how this was done for direct HTTP build sources before. You can also opt in your whole builder with `--buildkitd-flags '--proxy-network'` in `buildx create`. [#&#8203;3895](docker/buildx#3895)
- Resource limits can now be set for CPU and memory using the `--resource` flag in `build` and the `resource` key in `bake` commands. This feature requires BuildKit v0.31.0+ and Dockerfile v1.25.0+. [#&#8203;3876](docker/buildx#3876) [#&#8203;3900](docker/buildx#3900)
- Fix possible "closed channel" panic. [#&#8203;3886](docker/buildx#3886)

##### Dependency Changes

- **github.com/aws/aws-sdk-go-v2**                                                  v1.41.7 -> v1.42.0
- **github.com/aws/aws-sdk-go-v2/config**                                           v1.32.17 -> v1.32.24
- **github.com/aws/aws-sdk-go-v2/credentials**                                      v1.19.16 -> v1.19.23
- **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**                                 v1.18.23 -> v1.18.29
- **github.com/aws/aws-sdk-go-v2/internal/configsources**                           v1.4.23 -> v1.4.29
- **github.com/aws/aws-sdk-go-v2/internal/endpoints/v2**                            v2.7.23 -> v2.7.29
- **github.com/aws/aws-sdk-go-v2/internal/v4a**                                     v1.4.24 -> v1.4.30
- **github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding**                 v1.13.9 -> v1.13.12
- **github.com/aws/aws-sdk-go-v2/service/internal/presigned-url**                   v1.13.23 -> v1.13.29
- **github.com/aws/aws-sdk-go-v2/service/signin**                                   v1.0.11 -> v1.1.5
- **github.com/aws/aws-sdk-go-v2/service/sso**                                      v1.30.17 -> v1.31.3
- **github.com/aws/aws-sdk-go-v2/service/ssooidc**                                  v1.35.21 -> v1.36.6
- **github.com/aws/aws-sdk-go-v2/service/sts**                                      v1.42.1 -> v1.43.3
- **github.com/aws/smithy-go**                                                      v1.25.1 -> v1.27.2
- **github.com/containerd/containerd/v2**                                           v2.2.3 -> v2.2.4
- **github.com/containerd/continuity**                                              v0.4.5 -> v0.5.0
- **github.com/containerd/platforms**                                               v1.0.0-rc.2 -> v1.0.0-rc.4
- **github.com/containerd/typeurl/v2**                                              v2.2.3 -> v2.3.0
- **github.com/docker/cli**                                                         v29.4.3 -> v29.5.3
- **github.com/docker/distribution**                                                v2.8.3 ***new***
- **github.com/docker/docker-credential-helpers**                                   v0.9.5 -> v0.9.8
- **github.com/go-openapi/analysis**                                                v0.24.3 -> v0.25.2
- **github.com/go-openapi/jsonpointer**                                             v0.22.5 -> v0.23.1
- **github.com/go-openapi/jsonreference**                                           v0.21.5 -> v0.21.6
- **github.com/go-openapi/runtime**                                                 v0.29.3 -> v0.32.3
- **github.com/go-openapi/runtime/server-middleware**                               v0.30.0 ***new***
- **github.com/go-openapi/spec**                                                    v0.22.4 -> v0.22.5
- **github.com/go-openapi/strfmt**                                                  v0.26.1 -> v0.26.3
- **github.com/go-openapi/swag**                                                    v0.25.5 -> v0.26.0
- **github.com/go-openapi/swag/cmdutils**                                           v0.25.5 -> v0.26.0
- **github.com/go-openapi/swag/conv**                                               v0.25.5 -> v0.26.0
- **github.com/go-openapi/swag/fileutils**                                          v0.25.5 -> v0.26.0
- **github.com/go-openapi/swag/jsonname**                                           v0.25.5 -> v0.26.0
- **github.com/go-openapi/swag/jsonutils**                                          v0.25.5 -> v0.26.0
- **github.com/go-openapi/swag/loading**                                            v0.25.5 -> v0.26.0
- **github.com/go-openapi/swag/mangling**                                           v0.25.5 -> v0.26.0
- **github.com/go-openapi/swag/netutils**                                           v0.25.5 -> v0.26.0
- **github.com/go-openapi/swag/stringutils**                                        v0.25.5 -> v0.26.0
- **github.com/go-openapi/swag/typeutils**                                          v0.25.5 -> v0.26.0
- **github.com/go-openapi/swag/yamlutils**                                          v0.25.5 -> v0.26.0
- **github.com/go-openapi/validate**                                                v0.25.2 -> v0.25.3
- **github.com/google/certificate-transparency-go**                                 v1.3.2 -> v1.3.3
- **github.com/google/go-containerregistry**                                        v0.20.7 -> v0.21.6
- **github.com/gorilla/mux**                                                        v1.8.1 ***new***
- **github.com/grpc-ecosystem/grpc-gateway/v2**                                     v2.28.0 -> v2.29.0
- **github.com/in-toto/attestation**                                                v1.1.2 -> v1.2.0
- **github.com/moby/buildkit**                                                      v0.30.0 -> v0.31.0
- **github.com/moby/policy-helpers**                                                [`a39d601`](docker/buildx@a39d60132186) -> [`d5411a9`](docker/buildx@d5411a945cfc)
- **github.com/moby/sys/sequential**                                                v0.6.0 -> v0.7.0
- **github.com/pelletier/go-toml/v2**                                               v2.2.4 -> v2.3.1
- **github.com/prometheus/common**                                                  v0.66.1 -> v0.67.5
- **github.com/prometheus/procfs**                                                  v0.17.0 -> v0.20.1
- **github.com/secure-systems-lab/go-securesystemslib**                             v0.10.0 -> v0.11.0
- **github.com/sigstore/protobuf-specs**                                            v0.5.0 -> v0.5.1
- **github.com/sigstore/rekor**                                                     v1.5.0 -> v1.5.2
- **github.com/sigstore/rekor-tiles/v2**                                            v2.0.1 -> [`5d098a2`](docker/buildx@5d098a2b6443)
- **github.com/sigstore/sigstore**                                                  v1.10.5 -> v1.10.8
- **github.com/sigstore/sigstore-go**                                               v1.1.4 -> v1.2.1
- **github.com/sigstore/timestamp-authority/v2**                                    v2.0.6 -> v2.1.2
- **github.com/theupdateframework/go-tuf/v2**                                       v2.4.1 -> v2.4.2
- **github.com/tonistiigi/fsutil**                                                  [`a2aa163`](docker/buildx@a2aa163d723f) -> [`0257b33`](docker/buildx@0257b3308df4)
- **github.com/transparency-dev/formats**                                           [`404c0d5`](docker/buildx@404c0d5b696c) -> v0.1.1
- **github.com/youmark/pkcs8**                                                      [`a2c0da2`](docker/buildx@a2c0da244d78) ***new***
- **go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc**   v0.68.0 -> v0.69.0
- **go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace**  v0.68.0 -> v0.69.0
- **go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp**                 v0.68.0 -> v0.69.0
- **go.opentelemetry.io/otel**                                                      v1.43.0 -> v1.44.0
- **go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc**             v1.43.0 -> v1.44.0
- **go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp**             v1.43.0 -> v1.44.0
- **go.opentelemetry.io/otel/exporters/otlp/otlptrace**                             v1.43.0 -> v1.44.0
- **go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc**               v1.43.0 -> v1.44.0
- **go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp**               v1.43.0 -> v1.44.0
- **go.opentelemetry.io/otel/exporters/stdout/stdouttrace**                         v1.42.0 -> v1.44.0
- **go.opentelemetry.io/otel/metric**                                               v1.43.0 -> v1.44.0
- **go.opentelemetry.io/otel/sdk**                                                  v1.43.0 -> v1.44.0
- **go.opentelemetry.io/otel/sdk/metric**                                           v1.43.0 -> v1.44.0
- **go.opentelemetry.io/otel/trace**                                                v1.43.0 -> v1.44.0
- **go.yaml.in/yaml/v2**                                                            v2.4.3 -> v2.4.4
- **google.golang.org/genproto/googleapis/api**                                     [`6f92a3b`](docker/buildx@6f92a3bedf2d) -> [`3dc84a4`](docker/buildx@3dc84a4a5aaa)
- **google.golang.org/genproto/googleapis/rpc**                                     [`6f92a3b`](docker/buildx@6f92a3bedf2d) -> [`3dc84a4`](docker/buildx@3dc84a4a5aaa)
- **google.golang.org/grpc**                                                        v1.80.0 -> v1.81.1
- **google.golang.org/grpc/cmd/protoc-gen-go-grpc**                                 v1.5.1 -> v1.6.1
- **k8s.io/klog/v2**                                                                v2.130.1 -> v2.140.0

Previous release can be found at [v0.34.1](https://github.com/docker/buildx/releases/tag/v0.34.1)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM (`* 0-3 * * *`)
- Automerge
  - Between 12:00 AM and 03:59 AM (`* 0-3 * * *`)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNTIuMSIsInVwZGF0ZWRJblZlciI6IjQzLjI1Mi4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJLaW5kL0RlcGVuZGVuY3lVcGRhdGUiLCJydW4tZW5kLXRvLWVuZC10ZXN0cyJdfQ==-->

Reviewed-on: https://code.forgejo.org/forgejo/runner/pulls/1603
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.

3 participants