diff --git a/pkg/apis/core/v1/defaults.go b/pkg/apis/core/v1/defaults.go index e66de8bb432..b2d81d6fa87 100644 --- a/pkg/apis/core/v1/defaults.go +++ b/pkg/apis/core/v1/defaults.go @@ -27,6 +27,7 @@ import ( utilfeature "k8s.io/apiserver/pkg/util/feature" resourcehelper "k8s.io/component-helpers/resource" "k8s.io/kubernetes/pkg/api/v1/service" + corev1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/util/parsers" ) @@ -199,6 +200,7 @@ func SetDefaults_Pod(obj *v1.Pod) { // Pod Requests default values must be applied after container-level default values // have been populated. if utilfeature.DefaultFeatureGate.Enabled(features.PodLevelResources) { + defaultHugePagePodLimits(obj) defaultPodRequests(obj) } @@ -456,7 +458,9 @@ func defaultPodRequests(obj *v1.Pod) { // PodLevelResources feature) and pod-level requests are not set, the pod-level requests // default to the effective requests of all the containers for that resource. for key, aggrCtrLim := range aggrCtrReqs { - if _, exists := podReqs[key]; !exists && resourcehelper.IsSupportedPodLevelResource(key) { + // Defaulting for pod level hugepages requests takes them directly from the pod limit, + // hugepages cannot be overcommited and must have the limit, so we skip them here. + if _, exists := podReqs[key]; !exists && resourcehelper.IsSupportedPodLevelResource(key) && !corev1helper.IsHugePageResourceName(key) { podReqs[key] = aggrCtrLim.DeepCopy() } } @@ -464,6 +468,8 @@ func defaultPodRequests(obj *v1.Pod) { // When no containers specify requests for a resource, the pod-level requests // will default to match the pod-level limits, if pod-level // limits exist for that resource. + // Defaulting for pod level hugepages requests is dependent on defaultHugePagePodLimits, + // if defaultHugePagePodLimits defined the limit, the request will be set here. for key, podLim := range obj.Spec.Resources.Limits { if _, exists := podReqs[key]; !exists && resourcehelper.IsSupportedPodLevelResource(key) { podReqs[key] = podLim.DeepCopy() @@ -476,3 +482,44 @@ func defaultPodRequests(obj *v1.Pod) { obj.Spec.Resources.Requests = podReqs } } + +// defaultHugePagePodLimits applies default values for pod-level limits, only when +// container hugepage limits are set, but not at pod level, in following +// scenario: +// 1. When at least one container (regular, init or sidecar) has hugepage +// limits set: +// The pod-level limit becomes equal to the aggregated hugepages limit of all +// the containers in the pod. +func defaultHugePagePodLimits(obj *v1.Pod) { + // We only populate defaults when the pod-level resources are partly specified already. + if obj.Spec.Resources == nil { + return + } + + if len(obj.Spec.Resources.Limits) == 0 && len(obj.Spec.Resources.Requests) == 0 { + return + } + + var podLims v1.ResourceList + podLims = obj.Spec.Resources.Limits + if podLims == nil { + podLims = make(v1.ResourceList) + } + + aggrCtrLims := resourcehelper.AggregateContainerLimits(obj, resourcehelper.PodResourcesOptions{}) + + // When containers specify limits for hugepages and pod-level limits are not + // set for that resource, the pod-level limit will default to the aggregated + // hugepages limit of all the containers. + for key, aggrCtrLim := range aggrCtrLims { + if _, exists := podLims[key]; !exists && resourcehelper.IsSupportedPodLevelResource(key) && corev1helper.IsHugePageResourceName(key) { + podLims[key] = aggrCtrLim.DeepCopy() + } + } + + // Only set pod-level resource limits in the PodSpec if the requirements map + // contains entries after collecting container-level limits and pod-level limits for hugepages. + if len(podLims) > 0 { + obj.Spec.Resources.Limits = podLims + } +}