Skip to content

daemon: support per-device blkio throttle in ContainerUpdate#52651

Merged
thaJeztah merged 2 commits into
moby:masterfrom
acouvreur:fix/container-update-blkio-device-throttle
Jun 12, 2026
Merged

daemon: support per-device blkio throttle in ContainerUpdate#52651
thaJeztah merged 2 commits into
moby:masterfrom
acouvreur:fix/container-update-blkio-device-throttle

Conversation

@acouvreur

@acouvreur acouvreur commented May 19, 2026

Copy link
Copy Markdown
Contributor

Disclaimer: This was done with the help of Claude Sonnet 4.6.

But I've reviewed and tested manually the change.

Description

POST /containers/{id}/update accepts BlkioWeightDevice, BlkioDeviceReadBps, BlkioDeviceWriteBps, BlkioDeviceReadIOps, and BlkioDeviceWriteIOps in its Resources body, but these five fields were silently ignored — the API returns 200 OK but nothing is written to cgroupv2 io.max or the cgroupv1 blkio throttle files.

Fixes #52650.

Root cause

toContainerdResources in daemon/update_linux.go only mapped BlkioWeight into specs.LinuxBlockIO; the per-device fields were never converted so tsk.UpdateResources had nothing to apply:

// before
if resources.BlkioWeight != 0 {
    r.BlockIO = &specs.LinuxBlockIO{
        Weight: &resources.BlkioWeight,
        // WeightDevice, ThrottleRead/WriteBpsDevice, ThrottleRead/WriteIOPSDevice — missing
    }
}

Fix

Call the existing getBlkioWeightDevices and getBlkioThrottleDevices helpers (already used in oci_linux.go for container creation) to populate all five fields. The function signature gains an error return so that stat(2) failures on invalid device paths are surfaced to the caller rather than being silently dropped.

The Windows stub is updated to match the new signature.

Testing

Verified with a manual test against a running container on cgroupv2 (Colima / Ubuntu 24.04):

# before this fix — io.max is empty after ContainerUpdate with BlkioDeviceReadBps
# after this fix — io.max contains the throttle entry, e.g.:
# 8:0 rbps=5242880 wbps=max riops=max wiops=max
`POST /containers/{id}/update` now supports per-device blkio resource settings.

@acouvreur acouvreur force-pushed the fix/container-update-blkio-device-throttle branch from 0ce2026 to 8a4a5ca Compare May 19, 2026 04:40
@acouvreur

Copy link
Copy Markdown
Contributor Author

Note: I am able and willing to create the associated PR in the CLI if this is merged.

@vvoland vvoland left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks, I think this makes sense!

Comment thread daemon/update_linux.go Outdated
@vvoland vvoland added the kind/enhancement Enhancements are not bugs or new features but can improve usability or performance. label May 19, 2026
@acouvreur acouvreur force-pushed the fix/container-update-blkio-device-throttle branch from 7b20ea9 to 49f984d Compare May 29, 2026 12:59
@acouvreur

Copy link
Copy Markdown
Contributor Author

Hey @vvoland I've applied the initialization pattern based on your review, let me know if it needs further changes!

@vvoland vvoland added this to the 29.6.0 milestone Jun 2, 2026
@vvoland vvoland added impact/changelog area/runtime Runtime kind/feature Functionality or other elements that the project doesn't currently have. Features are new and shiny and removed kind/enhancement Enhancements are not bugs or new features but can improve usability or performance. labels Jun 2, 2026
@vvoland

vvoland commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Wondering if we should gate this by API version.. However, these fields are already present, it's just the daemon which hasn't been respecting them, so I think it's fine to treat this as a daemon enhancement rather than a new API addition..

@thaJeztah @corhere @cpuguy83 @tianon WDYT?

@vvoland

vvoland commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

@acouvreur Could you also add matching docker container update options to the CLI?

@acouvreur

Copy link
Copy Markdown
Contributor Author

@acouvreur Could you also add matching docker container update options to the CLI?

I believe this will be in the dedicated https://github.com/docker/cli repository right ?

I can open up a PR there if you can confirm that's the case.


Also, is there anything I need to do for you to make this easier to merge ? Are the CI failure expected here ?

assert.NilError(t, unix.Stat("/", &st), "stat /")

maj := unix.Major(st.Dev)
min := unix.Minor(st.Dev)

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.

Linter didn't like this because min shadows the min() builtin

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.

Will fix that

@vvoland

vvoland commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Yes it needs a change in https://github.com/docker/cli

Also, we chatted a bit with @thaJeztah and actually we think it should actually be an API version gated change.

Presence of these field in the API field was only a result of sharing structs, but wasn't explcitly called out in the API changelog or the initial API doc: https://github.com/moby/moby/blob/master/api/docs/v1.22.md#update-a-container

@acouvreur

Copy link
Copy Markdown
Contributor Author

Yes it needs a change in https://github.com/docker/cli

Also, we chatted a bit with @thaJeztah and actually we think it should actually be an API version gated change.

Presence of these field in the API field was only a result of sharing structs, but wasn't explcitly called out in the API changelog or the initial API doc: https://github.com/moby/moby/blob/master/api/docs/v1.22.md#update-a-container

Do you need me to do anything ?

I will submit the PR to docker/cli

@acouvreur

Copy link
Copy Markdown
Contributor Author

CLI PR created: docker/cli#7031

But I did not update the moby/moby library to this specific branch version of the library, so even though the parameters are there, they will be ignored until this is merged.

acouvreur added a commit to acouvreur/cli that referenced this pull request Jun 6, 2026
acouvreur added a commit to acouvreur/cli that referenced this pull request Jun 6, 2026
@vvoland

vvoland commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Do you need me to do anything ?

Yes, this needs an API version gate against current version (1.55)
Example:

if versions.LessThan(httputils.VersionFromContext(ctx), "1.40") {
updateConfig.PidsLimit = nil

@vvoland vvoland force-pushed the fix/container-update-blkio-device-throttle branch from d23e941 to 231ceba Compare June 11, 2026 14:13
@vvoland vvoland force-pushed the fix/container-update-blkio-device-throttle branch from 231ceba to d7c326b Compare June 11, 2026 14:14
@vvoland vvoland requested a review from thaJeztah June 11, 2026 14:16
Comment on lines +519 to +529
version := httputils.VersionFromContext(ctx)
if versions.LessThan(version, "1.40") {
updateConfig.PidsLimit = nil
}
if versions.LessThan(version, "1.55") {
updateConfig.BlkioWeightDevice = nil
updateConfig.BlkioDeviceReadBps = nil
updateConfig.BlkioDeviceWriteBps = nil
updateConfig.BlkioDeviceReadIOps = nil
updateConfig.BlkioDeviceWriteIOps = nil
}

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.

No need to change, but if we want to optimise, we could;

	version := httputils.VersionFromContext(ctx)
	if versions.LessThan(version, "1.55") {
		if versions.LessThan(version, "1.40") {
			updateConfig.PidsLimit = nil
		}
		updateConfig.BlkioWeightDevice = nil
		updateConfig.BlkioDeviceReadBps = nil
		updateConfig.BlkioDeviceWriteBps = nil
		updateConfig.BlkioDeviceReadIOps = nil
		updateConfig.BlkioDeviceWriteIOps = nil
	}

Comment thread daemon/container/container_unix.go Outdated
Comment on lines +272 to +286
if len(resources.BlkioWeightDevice) > 0 {
cResources.BlkioWeightDevice = resources.BlkioWeightDevice
}
if len(resources.BlkioDeviceReadBps) > 0 {
cResources.BlkioDeviceReadBps = resources.BlkioDeviceReadBps
}
if len(resources.BlkioDeviceWriteBps) > 0 {
cResources.BlkioDeviceWriteBps = resources.BlkioDeviceWriteBps
}
if len(resources.BlkioDeviceReadIOps) > 0 {
cResources.BlkioDeviceReadIOps = resources.BlkioDeviceReadIOps
}
if len(resources.BlkioDeviceWriteIOps) > 0 {
cResources.BlkioDeviceWriteIOps = resources.BlkioDeviceWriteIOps
}

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.

One thing to look at is if we need a way to reset these (and if that's possible); I know we've had similar cases for some other properties.

Possibly for this that could mean to distinguish and actual nil from a zero-length slice; where the latter would mean "reset".

I think that's somewhat similar to

if updateConfig.PidsLimit != nil && *updateConfig.PidsLimit <= 0 {
// Both `0` and `-1` are accepted to set "unlimited" when updating.
// Historically, any negative value was accepted, so treat them as
// "unlimited" as well.
var unlimited int64
updateConfig.PidsLimit = &unlimited
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah unfortunately that's pre existing issue with this endpoint for other fields, see my comments here: #52651 (comment)

But yeah In this case we could indeed handle nil differently.. I updated the PR, let me know what you think.

@vvoland vvoland force-pushed the fix/container-update-blkio-device-throttle branch from d7c326b to f6362f1 Compare June 11, 2026 18:08

@thaJeztah thaJeztah 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

Comment thread api/docs/CHANGELOG.md
Comment on lines +16 to +18
## v1.55 API changes

* `POST /containers/{id}/update` now supports per-device blkio resource

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 will conflict with #52636, so we can do a quick rebase with "validate-only" after CI completes and the other PR is merged

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

rebased

acouvreur and others added 2 commits June 12, 2026 15:52
The POST /containers/{id}/update API accepts BlkioWeightDevice,
BlkioDeviceReadBps, BlkioDeviceWriteBps, BlkioDeviceReadIOps, and
BlkioDeviceWriteIOps in its Resources body, but these five fields were
silently ignored when updating a running container.

The root cause was in toContainerdResources (daemon/update_linux.go):
only BlkioWeight was mapped into specs.LinuxBlockIO; the per-device
fields were never converted, so tsk.UpdateResources never wrote to
cgroupv2 io.max or the cgroupv1 blkio throttle files.

Fix by calling the existing getBlkioWeightDevices and
getBlkioThrottleDevices helpers (already used in oci_linux.go for
container creation) to populate all five fields. The function signature
is extended to return an error so that stat(2) failures on invalid
device paths are surfaced to the caller instead of being silently
dropped.

The API makes distinction between nil and zero-length slices while
doing. A nil per-device blkio field means the caller did not request an
update for that setting, while a non-nil empty slice means the caller
explicitly requested the setting to be cleared.

The Windows stub is updated to match the new signature.

Signed-off-by: Alexis Couvreur <[email protected]>
Signed-off-by: Paweł Gronowski <[email protected]>
ContainerUpdate only starts applying per-device blkio settings in the
current API version.

The fields existed in the Go request type before that because it shares
`container.Resources` with other endpoints, but they were not documented
as supported for container update and older daemons ignored them.

Clear these fields when handling requests for older API versions so
clients pinned to those versions keep the previous behavior, while v1.55
clients can use the newly supported fields.

Signed-off-by: Paweł Gronowski <[email protected]>
@vvoland vvoland force-pushed the fix/container-update-blkio-device-throttle branch from f6362f1 to dc97f25 Compare June 12, 2026 13:52
@thaJeztah thaJeztah merged commit 6f48430 into moby:master Jun 12, 2026
55 checks passed
@acouvreur

Copy link
Copy Markdown
Contributor Author

Thank you all! 🥳🥳

@thaJeztah thaJeztah moved this from New to Complete in 🔦 Maintainer spotlight Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/daemon Core Engine area/docs area/runtime Runtime area/testing ci/validate-only impact/changelog kind/feature Functionality or other elements that the project doesn't currently have. Features are new and shiny module/api status/4-merge

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

ContainerUpdate silently ignores BlkioDeviceReadBps, BlkioDeviceWriteBps, BlkioDeviceReadIOps, BlkioDeviceWriteIOps, and BlkioWeightDevice

4 participants