mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
docker: clamp CPU shares to minimum of 2 (#26081)
In #25963 we added normalization of CPU shares for large hosts where the total compute was larger than the maximum CPU shares. But if the result after normalization is less than 2, runc will have an integer overflow. We prevent this in the shared executor for the `exec`/`rawexec` driver by clamping to the safe minimum value. Do this for the `docker` driver as well and add test coverage of it for the shared executor too. Fixes: https://github.com/hashicorp/nomad/issues/26080 Ref: https://github.com/hashicorp/nomad/pull/25963
This commit is contained in:
3
.changelog/26081.txt
Normal file
3
.changelog/26081.txt
Normal file
@@ -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
|
||||
```
|
||||
@@ -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,
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -1089,6 +1089,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))
|
||||
|
||||
Reference in New Issue
Block a user