moby/moby

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

Open

#52,650 opened on 2026年5月19日

GitHub で見る
 (1 comment) (0 reactions) (0 assignees)Go (71,553 stars) (18,951 forks)batch import
help wantedkind/feature

説明

Disclaimer: Analysis and Issue opened by Claude Sonnet 4.6.

I've read throughout the analysis and the issue and it looks good to me.

The unknown part for me is to know if those values are supported for a live update.

I will submit a pull request for this fix, because if this is just missing data, then it is an easy fix.

Description

POST /containers/{id}/update accepts the following fields in the Resources body, but they are silently dropped and never applied to the running container's cgroup:

  • BlkioWeightDevice
  • BlkioDeviceReadBps
  • BlkioDeviceWriteBps
  • BlkioDeviceReadIOps
  • BlkioDeviceWriteIOps

Only BlkioWeight (the global weight) is actually applied.

Root cause

In daemon/update_linux.go, the toContainerdResources function converts a container.Resources into the subset that is pushed to containerd/runc for the live update:

func toContainerdResources(resources container.Resources) *libcontainerdtypes.Resources {
    var r libcontainerdtypes.Resources

    if resources.BlkioWeight != 0 {
        r.BlockIO = &specs.LinuxBlockIO{
            Weight: &resources.BlkioWeight,
            // ← WeightDevice, ThrottleReadBpsDevice, ThrottleWriteBpsDevice,
            //   ThrottleReadIOPSDevice, ThrottleWriteIOPSDevice are never set
        }
    }
    // CPU, Memory, Pids follow…
    return &r
}

The five per-device fields are never mapped, so tsk.UpdateResources never writes io.max (cgroupv2) or the cgroupv1 blkio throttle files.

Observed behaviour

Calling ContainerUpdate with e.g. BlkioDeviceReadBps: [{Path: "/dev/vda", Rate: 5242880}] on a running container:

  • Returns HTTP 200 with no warnings
  • Does not update HostConfig.BlkioDeviceReadBps (the field is empty on the next inspect)
  • Does not write to /sys/fs/cgroup/docker/{id}/io.max

BlkioWeight behaves correctly: it is written to io.weight and reflected in HostConfig.

The docker update CLI confirms the gap — it exposes --blkio-weight but has no --device-read-bps, --device-write-bps, --device-read-iops, or --device-write-iops flags.

Reproduction

# Start a container
docker run -d --name test alpine sleep 3600

# This works — io.weight is written
docker update --blkio-weight 500 test

# No equivalent flag exists for device throttle; using the API directly:
# POST /containers/test/update  { "BlkioDeviceReadBps": [{"Path":"/dev/vda","Rate":5242880}] }
# → 200 OK, but HostConfig.BlkioDeviceReadBps is empty and io.max is unchanged

Expected behaviour

Per-device blkio throttle settings should be applicable to running containers, either via docker update flags or via the API. The toContainerdResources function should map all five fields into the equivalent specs.LinuxBlockIO fields:

  • WeightDeviceBlkioWeightDevice
  • ThrottleReadBpsDeviceBlkioDeviceReadBps
  • ThrottleWriteBpsDeviceBlkioDeviceWriteBps
  • ThrottleReadIOPSDeviceBlkioDeviceReadIOps
  • ThrottleWriteIOPSDeviceBlkioDeviceWriteIOps

Context

Discovered while implementing scale-mode resource throttling in sablierapp/sablier, which live-updates container resources (without restart) to throttle idle containers and restore them on demand. Per-device IO throttle would be a useful tool for reducing storage pressure on idle containers.

コントリビューターガイド