From 5471fc2f03d1d14ceb250bf98f400cee9feb6983 Mon Sep 17 00:00:00 2001 From: Jim Gauld Date: Fri, 3 Sep 2021 15:57:58 -0400 Subject: [PATCH 3/6] kubelet cpumanager infrastructure pods use system reserved CPUs This assigns system infrastructure pods to the "reserved" cpuset to isolate them from the shared pool of CPUs. Infrastructure pods include any pods that belong to the kube-system, armada, cert-manager, vault, platform-deployment-manager, portieris, notification or flux-helm namespaces. The implementation is a bit simplistic, it is assumed that the "reserved" cpuset is large enough to handle all infrastructure pods CPU allocations. This also prevents infrastucture pods from using Guaranteed resources. Signed-off-by: Jim Gauld --- pkg/kubelet/cm/cpumanager/policy_static.go | 44 +++++++++++++++++++ .../cm/cpumanager/policy_static_test.go | 19 +++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/pkg/kubelet/cm/cpumanager/policy_static.go b/pkg/kubelet/cm/cpumanager/policy_static.go index e892d63641b..ab3206c5dc4 100644 --- a/pkg/kubelet/cm/cpumanager/policy_static.go +++ b/pkg/kubelet/cm/cpumanager/policy_static.go @@ -33,6 +33,11 @@ import ( // PolicyStatic is the name of the static policy const PolicyStatic policyName = "static" +// Define namespaces used by platform infrastructure pods +var infraNamespaces = [...]string{ + "kube-system", "armada", "cert-manager", "platform-deployment-manager", "portieris", "vault", "notification", "flux-helm", +} + // staticPolicy is a CPU manager policy that does not change CPU // assignments for exclusively pinned guaranteed containers after the main // container process starts. @@ -233,6 +238,31 @@ func (p *staticPolicy) updateCPUsToReuse(pod *v1.Pod, container *v1.Container, c } func (p *staticPolicy) Allocate(s state.State, pod *v1.Pod, container *v1.Container) error { + // Process infra pods before guaranteed pods + if isKubeInfra(pod) { + // Container belongs in reserved pool. + // We don't want to fall through to the p.guaranteedCPUs() clause below so return either nil or error. + if _, ok := s.GetCPUSet(string(pod.UID), container.Name); ok { + klog.Infof("[cpumanager] static policy: reserved container already present in state, skipping " + + "(namespace: %s, pod UID: %s, pod: %s, container: %s)", + pod.Namespace, string(pod.UID), pod.Name, container.Name) + return nil + } + + cpuset := p.reserved + if cpuset.IsEmpty() { + // If this happens then someone messed up. + return fmt.Errorf("[cpumanager] static policy: reserved container unable to allocate cpus " + + "(namespace: %s, pod UID: %s, pod: %s, container: %s); cpuset=%v, reserved:%v", + pod.Namespace, string(pod.UID), pod.Name, container.Name, cpuset, p.reserved) + } + s.SetCPUSet(string(pod.UID), container.Name, cpuset) + klog.Infof("[cpumanager] static policy: reserved: AddContainer " + + "(namespace: %s, pod UID: %s, pod: %s, container: %s); cpuset=%v", + pod.Namespace, string(pod.UID), pod.Name, container.Name, cpuset) + return nil + } + if numCPUs := p.guaranteedCPUs(pod, container); numCPUs != 0 { klog.Infof("[cpumanager] static policy: Allocate (pod: %s, container: %s)", format.Pod(pod), container.Name) // container belongs in an exclusively allocated pool @@ -322,6 +352,10 @@ func (p *staticPolicy) guaranteedCPUs(pod *v1.Pod, container *v1.Container) int if cpuQuantity.Value()*1000 != cpuQuantity.MilliValue() { return 0 } + // Infrastructure pods use reserved CPUs even if they're in the Guaranteed QoS class + if isKubeInfra(pod) { + return 0 + } // Safe downcast to do for all systems with < 2.1 billion CPUs. // Per the language spec, `int` is guaranteed to be at least 32 bits wide. // https://golang.org/ref/spec#Numeric_types @@ -524,3 +558,13 @@ func (p *staticPolicy) generateCPUTopologyHints(availableCPUs cpuset.CPUSet, reu return hints } + +// check if a given pod is in a platform infrastructure namespace +func isKubeInfra(pod *v1.Pod) bool { + for _, namespace := range infraNamespaces { + if namespace == pod.Namespace { + return true + } + } + return false +} \ No newline at end of file diff --git a/pkg/kubelet/cm/cpumanager/policy_static_test.go b/pkg/kubelet/cm/cpumanager/policy_static_test.go index 9c7e4f146ff..5cfd9a8e24e 100644 --- a/pkg/kubelet/cm/cpumanager/policy_static_test.go +++ b/pkg/kubelet/cm/cpumanager/policy_static_test.go @@ -747,7 +747,8 @@ func TestStaticPolicyStartWithResvList(t *testing.T) { } func TestStaticPolicyAddWithResvList(t *testing.T) { - + infraPod := makePod("fakePod", "fakeContainer2", "200m", "200m") + infraPod.Namespace = "kube-system" testCases := []staticPolicyTestWithResvList{ { description: "GuPodSingleCore, SingleSocketHT, ExpectError", @@ -789,6 +790,22 @@ func TestStaticPolicyAddWithResvList(t *testing.T) { expCPUAlloc: true, expCSet: cpuset.NewCPUSet(4, 5), }, + { + description: "InfraPod, SingleSocketHT, ExpectAllocReserved", + topo: topoSingleSocketHT, + numReservedCPUs: 2, + reserved: cpuset.NewCPUSet(0, 1), + stAssignments: state.ContainerCPUAssignments{ + "fakePod": map[string]cpuset.CPUSet{ + "fakeContainer100": cpuset.NewCPUSet(2, 3, 6, 7), + }, + }, + stDefaultCPUSet: cpuset.NewCPUSet(4, 5), + pod: infraPod, + expErr: nil, + expCPUAlloc: true, + expCSet: cpuset.NewCPUSet(0, 1), + }, } testExcl := true -- 2.17.1