Check OS for PodLevelResources in kubelet

Reject pods with PodLevelResources running on Windows nodes
at kubelet admission phase
This commit is contained in:
Anna Song
2025-07-02 00:39:06 +00:00
committed by Tsubasa Nagasawa
parent e2c308aff9
commit c2b26617be
6 changed files with 137 additions and 1 deletions

View File

@@ -248,6 +248,7 @@ var (
lifecycle.OutOfMemory,
lifecycle.OutOfEphemeralStorage,
lifecycle.OutOfPods,
lifecycle.PodLevelResourcesNotAdmittedReason,
tainttoleration.ErrReasonNotMatch,
eviction.Reason,
sysctl.ForbiddenReason,
@@ -1011,6 +1012,8 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
handlers = append(handlers, lifecycle.NewAppArmorAdmitHandler(klet.appArmorValidator))
}
handlers = append(handlers, lifecycle.NewPodFeaturesAdmitHandler())
leaseDuration := time.Duration(kubeCfg.NodeLeaseDurationSeconds) * time.Second
renewInterval := time.Duration(float64(leaseDuration) * nodeLeaseRenewIntervalFraction)
klet.nodeLeaseController = lease.NewController(

View File

@@ -3373,6 +3373,15 @@ func TestRecordAdmissionRejection(t *testing.T) {
kubelet_admission_rejections_total{reason="OutOfExtendedResources"} 1
`,
},
{
name: "PodLevelResources",
reason: lifecycle.PodLevelResourcesNotAdmittedReason,
wants: `
# HELP kubelet_admission_rejections_total [ALPHA] Cumulative number pod admission rejections by the Kubelet.
# TYPE kubelet_admission_rejections_total counter
kubelet_admission_rejections_total{reason="PodLevelResourcesNotSupported"} 1
`,
},
{
name: "OtherReason",
reason: "OtherReason",

View File

@@ -0,0 +1,39 @@
//go:build linux
// +build linux
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package lifecycle
import (
v1 "k8s.io/api/core/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/component-helpers/resource"
"k8s.io/kubernetes/pkg/features"
)
func isPodLevelResourcesSupported(pod *v1.Pod) PodAdmitResult {
podLevelResourcesEnabled := utilfeature.DefaultFeatureGate.Enabled(features.PodLevelResources)
if resource.IsPodLevelResourcesSet(pod) && !podLevelResourcesEnabled {
return PodAdmitResult{
Admit: false,
Reason: PodLevelResourcesNotAdmittedReason,
Message: "PodLevelResources feature gate is disabled",
}
}
return PodAdmitResult{Admit: true}
}

View File

@@ -0,0 +1,36 @@
//go:build !linux && !windows
// +build !linux,!windows
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package lifecycle
import (
v1 "k8s.io/api/core/v1"
"k8s.io/component-helpers/resource"
)
func isPodLevelResourcesSupported(pod *v1.Pod) PodAdmitResult {
if resource.IsPodLevelResourcesSet(pod) {
return PodAdmitResult{
Admit: false,
Reason: PodLevelResourcesNotAdmittedReason,
Message: "pod-level resources are not supported on the node",
}
}
return PodAdmitResult{Admit: true}
}

View File

@@ -0,0 +1,36 @@
//go:build windows
// +build windows
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package lifecycle
import (
v1 "k8s.io/api/core/v1"
"k8s.io/component-helpers/resource"
)
func isPodLevelResourcesSupported(pod *v1.Pod) PodAdmitResult {
if resource.IsPodLevelResourcesSet(pod) {
return PodAdmitResult{
Admit: false,
Reason: PodLevelResourcesNotAdmittedReason,
Message: "pod-level resources are not supported on Windows",
}
}
return PodAdmitResult{Admit: true}
}

View File

@@ -45,7 +45,8 @@ import (
const (
maxRespBodyLength = 10 * 1 << 10 // 10KB
AppArmorNotAdmittedReason = "AppArmor"
AppArmorNotAdmittedReason = "AppArmor"
PodLevelResourcesNotAdmittedReason = "PodLevelResourcesNotSupported"
)
type handlerRunner struct {
@@ -241,3 +242,15 @@ func isHTTPResponseError(err error) bool {
}
return strings.Contains(urlErr.Err.Error(), "server gave HTTP response to HTTPS client")
}
// NewPodFeaturesAdmitHandler returns a PodAdmitHandler which is used to evaluate
// if a pod can be admitted from the perspective of pod features compatibility.
func NewPodFeaturesAdmitHandler() PodAdmitHandler {
return &podFeaturesAdmitHandler{}
}
type podFeaturesAdmitHandler struct{}
func (h *podFeaturesAdmitHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult {
return isPodLevelResourcesSupported(attrs.Pod)
}