mirror of
https://github.com/kata-containers/kata-containers.git
synced 2026-07-02 07:02:16 +00:00
runtime: oci: derive sandbox CPUs from shares only if unconstrained
The shares-based fallback added for cpuManagerPolicy=static fired whenever the quota-based CPU count was 0, including for BestEffort sandboxes that have no CPU request. Those sandboxes still carry the cgroup-floor shares value (2), so the fallback derived ceil(2/1024)=1 and inflated every such sandbox by one vCPU. For peer-pods (static resource management) this changed the VM sizing to default_vcpus+1, regressing the libvirt instance-type CI checks. Gate the fallback on the quota being explicitly unconstrained (< 0), which is the actual cpuManagerPolicy=static signal, instead of on numCPU == 0. BestEffort sandboxes (quota 0/absent) now correctly contribute 0 vCPUs while the static-policy case still recovers the CPU count from shares. Add unit tests covering the static-policy, rounding, BestEffort, and explicit-quota cases. Signed-off-by: Fabiano Fidêncio <ffidencio@nvidia.com>
This commit is contained in:
@@ -1513,9 +1513,16 @@ func CalculateSandboxSizing(spec *specs.Spec) (numCPU float32, memSizeMB uint32)
|
||||
numCPU, memSizeMB = calculateVMResources(period, quota, memory)
|
||||
|
||||
// When cpuManagerPolicy=static is in use, kubelet sets quota=-1
|
||||
// (unconstrained) and assigns CPUs via cpuset instead. Fall back
|
||||
// to deriving the CPU count from shares (1024 shares per CPU).
|
||||
if numCPU == 0 && shares > 0 {
|
||||
// (unconstrained) and assigns CPUs via cpuset instead. In that case
|
||||
// we derive the CPU count from the CPU shares (1024 shares per CPU).
|
||||
//
|
||||
// We must gate this on quota being explicitly unconstrained (< 0)
|
||||
// rather than on numCPU == 0: a quota of 0 (or absent) means a
|
||||
// BestEffort sandbox with no CPU request, which has to contribute 0
|
||||
// vCPUs. Such a sandbox still carries the cgroup-floor shares value
|
||||
// (2), and deriving from it would inflate every sandbox by one vCPU
|
||||
// (e.g. peer-pods would boot default_vcpus+1).
|
||||
if quota < 0 && numCPU == 0 && shares > 0 {
|
||||
numCPU = float32(math.Ceil(float64(shares) / 1024.0))
|
||||
}
|
||||
|
||||
|
||||
@@ -1263,6 +1263,13 @@ func makeSizingAnnotations(memory, quota, period string) *specs.Spec {
|
||||
return &spec
|
||||
}
|
||||
|
||||
func makeSizingAnnotationsWithShares(memory, quota, period, shares string) *specs.Spec {
|
||||
spec := makeSizingAnnotations(memory, quota, period)
|
||||
spec.Annotations[ctrAnnotations.SandboxCPUShares] = shares
|
||||
|
||||
return spec
|
||||
}
|
||||
|
||||
func TestCalculateContainerSizing(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
@@ -1376,6 +1383,42 @@ func TestCalculateSandboxSizing(t *testing.T) {
|
||||
expectedCPU: 4,
|
||||
expectedMem: 4096,
|
||||
},
|
||||
// cpuManagerPolicy=static: kubelet leaves the quota
|
||||
// unconstrained (-1) and pins CPUs via cpuset, so the CPU
|
||||
// count must be derived from the shares (1024 shares per CPU).
|
||||
{
|
||||
spec: makeSizingAnnotationsWithShares("1048576", "-1", "100", "2048"),
|
||||
expectedCPU: 2,
|
||||
expectedMem: 1,
|
||||
},
|
||||
// Shares that don't divide evenly are rounded up.
|
||||
{
|
||||
spec: makeSizingAnnotationsWithShares("0", "-1", "100", "1536"),
|
||||
expectedCPU: 2,
|
||||
expectedMem: 0,
|
||||
},
|
||||
// BestEffort sandbox: no CPU request means quota is 0/absent,
|
||||
// but the cgroup still carries the floor shares value (2). This
|
||||
// must contribute 0 vCPUs, otherwise every sandbox (e.g. a
|
||||
// peer-pod) would be inflated by one vCPU.
|
||||
{
|
||||
spec: makeSizingAnnotationsWithShares("0", "0", "100", "2"),
|
||||
expectedCPU: 0,
|
||||
expectedMem: 0,
|
||||
},
|
||||
// An explicit quota always wins over shares: the shares-based
|
||||
// fallback only applies when the quota is unconstrained.
|
||||
{
|
||||
spec: makeSizingAnnotationsWithShares("0", "200", "100", "8192"),
|
||||
expectedCPU: 2,
|
||||
expectedMem: 0,
|
||||
},
|
||||
// Unconstrained quota but no shares set: nothing to derive from.
|
||||
{
|
||||
spec: makeSizingAnnotationsWithShares("0", "-1", "100", "0"),
|
||||
expectedCPU: 0,
|
||||
expectedMem: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
|
||||
Reference in New Issue
Block a user