Add Windows support for IPPVS

Added Windows support for InPlacePodVerticalScaling
This commit is contained in:
Fabian Fulga 2023-04-04 14:36:23 +03:00
parent 04292dd94b
commit 2ad4304e8f
3 changed files with 137 additions and 33 deletions

View File

@ -260,14 +260,25 @@ func TestToKubeContainerStatusWithResources(t *testing.T) {
State: runtimeapi.ContainerState_CONTAINER_RUNNING, State: runtimeapi.ContainerState_CONTAINER_RUNNING,
CreatedAt: createdAt, CreatedAt: createdAt,
StartedAt: startedAt, StartedAt: startedAt,
Resources: &runtimeapi.ContainerResources{ Resources: func() *runtimeapi.ContainerResources {
Linux: &runtimeapi.LinuxContainerResources{ if goruntime.GOOS == "windows" {
CpuQuota: 25000, return &runtimeapi.ContainerResources{
CpuPeriod: 100000, Windows: &runtimeapi.WindowsContainerResources{
MemoryLimitInBytes: 524288000, CpuMaximum: 2500,
OomScoreAdj: -998, CpuCount: 1,
}, MemoryLimitInBytes: 524288000,
}, },
}
}
return &runtimeapi.ContainerResources{
Linux: &runtimeapi.LinuxContainerResources{
CpuQuota: 25000,
CpuPeriod: 100000,
MemoryLimitInBytes: 524288000,
OomScoreAdj: -998,
},
}
}(),
}, },
expected: &kubecontainer.Status{ expected: &kubecontainer.Status{
ID: *cid, ID: *cid,
@ -289,12 +300,22 @@ func TestToKubeContainerStatusWithResources(t *testing.T) {
State: runtimeapi.ContainerState_CONTAINER_RUNNING, State: runtimeapi.ContainerState_CONTAINER_RUNNING,
CreatedAt: createdAt, CreatedAt: createdAt,
StartedAt: startedAt, StartedAt: startedAt,
Resources: &runtimeapi.ContainerResources{ Resources: func() *runtimeapi.ContainerResources {
Linux: &runtimeapi.LinuxContainerResources{ if goruntime.GOOS == "windows" {
CpuQuota: 50000, return &runtimeapi.ContainerResources{
CpuPeriod: 100000, Windows: &runtimeapi.WindowsContainerResources{
}, CpuMaximum: 2500,
}, CpuCount: 2,
},
}
}
return &runtimeapi.ContainerResources{
Linux: &runtimeapi.LinuxContainerResources{
CpuQuota: 50000,
CpuPeriod: 100000,
},
}
}(),
}, },
expected: &kubecontainer.Status{ expected: &kubecontainer.Status{
ID: *cid, ID: *cid,
@ -320,6 +341,9 @@ func TestToKubeContainerStatusWithResources(t *testing.T) {
MemoryLimitInBytes: 524288000, MemoryLimitInBytes: 524288000,
OomScoreAdj: -998, OomScoreAdj: -998,
}, },
Windows: &runtimeapi.WindowsContainerResources{
MemoryLimitInBytes: 524288000,
},
}, },
}, },
expected: &kubecontainer.Status{ expected: &kubecontainer.Status{

View File

@ -42,19 +42,24 @@ func (m *kubeGenericRuntimeManager) applyPlatformSpecificContainerConfig(config
// generateContainerResources generates platform specific (windows) container resources config for runtime // generateContainerResources generates platform specific (windows) container resources config for runtime
func (m *kubeGenericRuntimeManager) generateContainerResources(pod *v1.Pod, container *v1.Container) *runtimeapi.ContainerResources { func (m *kubeGenericRuntimeManager) generateContainerResources(pod *v1.Pod, container *v1.Container) *runtimeapi.ContainerResources {
//TODO: Add windows support return &runtimeapi.ContainerResources{
return nil Windows: m.generateWindowsContainerResources(pod, container),
}
} }
// generateWindowsContainerConfig generates windows container config for kubelet runtime v1. // generateWindowsContainerResources generates windows container resources config for runtime
// Refer https://git.k8s.io/design-proposals-archive/node/cri-windows.md. func (m *kubeGenericRuntimeManager) generateWindowsContainerResources(pod *v1.Pod, container *v1.Container) *runtimeapi.WindowsContainerResources {
func (m *kubeGenericRuntimeManager) generateWindowsContainerConfig(container *v1.Container, pod *v1.Pod, uid *int64, username string) (*runtimeapi.WindowsContainerConfig, error) { wcr := m.calculateWindowsResources(container.Resources.Limits.Cpu(), container.Resources.Limits.Memory())
wc := &runtimeapi.WindowsContainerConfig{
Resources: &runtimeapi.WindowsContainerResources{}, return wcr
SecurityContext: &runtimeapi.WindowsContainerSecurityContext{}, }
}
// calculateWindowsResources will create the windowsContainerResources type based on the provided CPU and memory resource requests, limits
func (m *kubeGenericRuntimeManager) calculateWindowsResources(cpuLimit, memoryLimit *resource.Quantity) *runtimeapi.WindowsContainerResources {
resources := runtimeapi.WindowsContainerResources{}
memLimit := memoryLimit.Value()
cpuLimit := container.Resources.Limits.Cpu()
if !cpuLimit.IsZero() { if !cpuLimit.IsZero() {
// Since Kubernetes doesn't have any notion of weight in the Pod/Container API, only limits/reserves, then applying CpuMaximum only // Since Kubernetes doesn't have any notion of weight in the Pod/Container API, only limits/reserves, then applying CpuMaximum only
// will better follow the intent of the user. At one point CpuWeights were set, but this prevented limits from having any effect. // will better follow the intent of the user. At one point CpuWeights were set, but this prevented limits from having any effect.
@ -79,22 +84,32 @@ func (m *kubeGenericRuntimeManager) generateWindowsContainerConfig(container *v1
// https://github.com/kubernetes/kubernetes/blob/56d1c3b96d0a544130a82caad33dd57629b8a7f8/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api.proto#L681-L682 // https://github.com/kubernetes/kubernetes/blob/56d1c3b96d0a544130a82caad33dd57629b8a7f8/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api.proto#L681-L682
// https://github.com/opencontainers/runtime-spec/blob/ad53dcdc39f1f7f7472b10aa0a45648fe4865496/config-windows.md#cpu // https://github.com/opencontainers/runtime-spec/blob/ad53dcdc39f1f7f7472b10aa0a45648fe4865496/config-windows.md#cpu
// If both CpuWeight and CpuMaximum are set - ContainerD catches this invalid case and returns an error instead. // If both CpuWeight and CpuMaximum are set - ContainerD catches this invalid case and returns an error instead.
wc.Resources.CpuMaximum = calculateCPUMaximum(cpuLimit, int64(winstats.ProcessorCount())) resources.CpuMaximum = calculateCPUMaximum(cpuLimit, int64(winstats.ProcessorCount()))
} }
// The processor resource controls are mutually exclusive on // The processor resource controls are mutually exclusive on
// Windows Server Containers, the order of precedence is // Windows Server Containers, the order of precedence is
// CPUCount first, then CPUMaximum. // CPUCount first, then CPUMaximum.
if wc.Resources.CpuCount > 0 { if resources.CpuCount > 0 {
if wc.Resources.CpuMaximum > 0 { if resources.CpuMaximum > 0 {
wc.Resources.CpuMaximum = 0 resources.CpuMaximum = 0
klog.InfoS("Mutually exclusive options: CPUCount priority > CPUMaximum priority on Windows Server Containers. CPUMaximum should be ignored") klog.InfoS("Mutually exclusive options: CPUCount priority > CPUMaximum priority on Windows Server Containers. CPUMaximum should be ignored")
} }
} }
memoryLimit := container.Resources.Limits.Memory().Value() if memLimit != 0 {
if memoryLimit != 0 { resources.MemoryLimitInBytes = memLimit
wc.Resources.MemoryLimitInBytes = memoryLimit }
return &resources
}
// generateWindowsContainerConfig generates windows container config for kubelet runtime v1.
// Refer https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/cri-windows.md.
func (m *kubeGenericRuntimeManager) generateWindowsContainerConfig(container *v1.Container, pod *v1.Pod, uid *int64, username string) (*runtimeapi.WindowsContainerConfig, error) {
wc := &runtimeapi.WindowsContainerConfig{
Resources: m.generateWindowsContainerResources(pod, container),
SecurityContext: &runtimeapi.WindowsContainerSecurityContext{},
} }
// setup security context // setup security context
@ -134,6 +149,27 @@ func calculateCPUMaximum(cpuLimit *resource.Quantity, cpuCount int64) int64 {
} }
func toKubeContainerResources(statusResources *runtimeapi.ContainerResources) *kubecontainer.ContainerResources { func toKubeContainerResources(statusResources *runtimeapi.ContainerResources) *kubecontainer.ContainerResources {
//TODO: Add windows support var cStatusResources *kubecontainer.ContainerResources
return nil runtimeStatusResources := statusResources.GetWindows()
if runtimeStatusResources != nil {
var memLimit, cpuLimit *resource.Quantity
// Used the reversed formula from the calculateCPUMaximum function
if runtimeStatusResources.CpuMaximum > 0 {
cpuLimitValue := runtimeStatusResources.CpuMaximum * int64(winstats.ProcessorCount()) / 10
cpuLimit = resource.NewMilliQuantity(cpuLimitValue, resource.DecimalSI)
}
if runtimeStatusResources.MemoryLimitInBytes > 0 {
memLimit = resource.NewQuantity(runtimeStatusResources.MemoryLimitInBytes, resource.BinarySI)
}
if cpuLimit != nil || memLimit != nil {
cStatusResources = &kubecontainer.ContainerResources{
CPULimit: cpuLimit,
MemoryLimit: memLimit,
}
}
}
return cStatusResources
} }

View File

@ -149,3 +149,47 @@ func TestCalculateCPUMaximum(t *testing.T) {
}) })
} }
} }
func TestCalculateWindowsResources(t *testing.T) {
_, _, fakeRuntimeSvc, err := createTestRuntimeManager()
require.NoError(t, err)
tests := []struct {
name string
cpuLim resource.Quantity
memLim resource.Quantity
expected *runtimeapi.WindowsContainerResources
}{
{
name: "Request128MBLimit256MB",
cpuLim: resource.MustParse("2"),
memLim: resource.MustParse("128Mi"),
expected: &runtimeapi.WindowsContainerResources{
CpuMaximum: 2500,
MemoryLimitInBytes: 134217728,
},
},
{
name: "RequestNoMemory",
cpuLim: resource.MustParse("8"),
memLim: resource.MustParse("0"),
expected: &runtimeapi.WindowsContainerResources{
CpuMaximum: 10000,
MemoryLimitInBytes: 0,
},
},
{
name: "RequestZeroCPU",
cpuLim: resource.MustParse("0"),
memLim: resource.MustParse("128Mi"),
expected: &runtimeapi.WindowsContainerResources{
CpuMaximum: 1,
MemoryLimitInBytes: 134217728,
},
},
}
for _, test := range tests {
windowsContainerResources := fakeRuntimeSvc.calculateWindowsResources(&test.cpuLim, &test.memLim)
assert.Equal(t, test.expected, windowsContainerResources)
}
}