Skip to content

Backport of docker: clamp CPU shares to minimum of 2 into release/1.10.x #26082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/26081.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
docker: Fixed a bug where very low resources.cpu values could generate invalid cpu weights on hosts with very large client.cpu_total_compute values
```
10 changes: 9 additions & 1 deletion drivers/docker/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -951,17 +951,25 @@ func memoryLimits(driverHardLimitMB int64, taskMemory drivers.MemoryResources) (
// maxCPUShares is the maximum value for cpu_shares in cgroups v1
// https://github.com/torvalds/linux/blob/v6.15/kernel/sched/sched.h#L503
const maxCPUShares = 262_144
const minCPUShares = 2

// cpuResources normalizes the requested CPU shares when the total compute
// available on the node is larger than the largest share value allowed by the
// kernel. On cgroups v2, Docker will re-normalize this to be within the
// acceptable range for cpu.weight [1-10000].
func (d *Driver) cpuResources(requested int64) int64 {
if requested < minCPUShares {
return minCPUShares
}
if d.compute.TotalCompute < maxCPUShares {
return requested
}

return int64(float64(requested) / float64(d.compute.TotalCompute) * maxCPUShares)
result := int64(float64(requested) / float64(d.compute.TotalCompute) * maxCPUShares)
if result < minCPUShares {
return minCPUShares
}
return result
}

func (d *Driver) createContainerConfig(task *drivers.TaskConfig, driverConfig *TaskConfig,
Expand Down
6 changes: 6 additions & 0 deletions drivers/docker/driver_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ func TestDockerDriver_NormalizeCPUShares(t *testing.T) {
driver.compute.TotalCompute = maxCPUShares + 1
must.Eq(t, 262143, driver.cpuResources(maxCPUShares))

driver.compute.TotalCompute = maxCPUShares + 1
must.Eq(t, 2, driver.cpuResources(2))

driver.compute.TotalCompute = maxCPUShares + 1
must.Eq(t, 2, driver.cpuResources(1))

driver.compute.TotalCompute = maxCPUShares * 2
must.Eq(t, 500, driver.cpuResources(1000))
must.Eq(t, maxCPUShares/2, driver.cpuResources(maxCPUShares))
Expand Down
3 changes: 3 additions & 0 deletions drivers/shared/executor/executor_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,9 @@ func TestExecutor_clampCPUShares(t *testing.T) {
le.compute.TotalCompute = MaxCPUShares + 1
must.Eq(t, 262143, le.clampCpuShares(MaxCPUShares))

le.compute.TotalCompute = MaxCPUShares + 1
must.Eq(t, 2, le.clampCpuShares(1))

le.compute = cpustats.Compute{TotalCompute: MaxCPUShares * 2}
must.Eq(t, 500, le.clampCpuShares(1000))
must.Eq(t, MaxCPUShares/2, le.clampCpuShares(MaxCPUShares))
Expand Down