mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
kubelet: modify KubeletConfiguration API with image pull policies
Also adds PreloadedImagesVerificationAllowlist to API exceptions list for missing list type as this is not a part of the REST API.
This commit is contained in:
parent
ad96b3aed5
commit
47827f4d9a
@ -243,6 +243,7 @@ var (
|
|||||||
"ImageGCLowThresholdPercent",
|
"ImageGCLowThresholdPercent",
|
||||||
"ImageMinimumGCAge.Duration",
|
"ImageMinimumGCAge.Duration",
|
||||||
"ImageMaximumGCAge.Duration",
|
"ImageMaximumGCAge.Duration",
|
||||||
|
"ImagePullCredentialsVerificationPolicy",
|
||||||
"KernelMemcgNotification",
|
"KernelMemcgNotification",
|
||||||
"KubeAPIBurst",
|
"KubeAPIBurst",
|
||||||
"KubeAPIQPS",
|
"KubeAPIQPS",
|
||||||
@ -268,6 +269,7 @@ var (
|
|||||||
"PodPidsLimit",
|
"PodPidsLimit",
|
||||||
"PodsPerCore",
|
"PodsPerCore",
|
||||||
"Port",
|
"Port",
|
||||||
|
"PreloadedImagesVerificationAllowlist[*]",
|
||||||
"ProtectKernelDefaults",
|
"ProtectKernelDefaults",
|
||||||
"ProviderID",
|
"ProviderID",
|
||||||
"ReadOnlyPort",
|
"ReadOnlyPort",
|
||||||
|
@ -155,6 +155,25 @@ type KubeletConfiguration struct {
|
|||||||
// pulls to burst to this number, while still not exceeding registryPullQPS.
|
// pulls to burst to this number, while still not exceeding registryPullQPS.
|
||||||
// Only used if registryPullQPS > 0.
|
// Only used if registryPullQPS > 0.
|
||||||
RegistryBurst int32
|
RegistryBurst int32
|
||||||
|
// imagePullCredentialsVerificationPolicy determines how credentials should be
|
||||||
|
// verified when pod requests an image that is already present on the node:
|
||||||
|
// - NeverVerify
|
||||||
|
// - anyone on a node can use any image present on the node
|
||||||
|
// - NeverVerifyPreloadedImages
|
||||||
|
// - images that were pulled to the node by something else than the kubelet
|
||||||
|
// can be used without reverifying pull credentials
|
||||||
|
// - NeverVerifyAllowlistedImages
|
||||||
|
// - like "NeverVerifyPreloadedImages" but only node images from
|
||||||
|
// `preloadedImagesVerificationAllowlist` don't require reverification
|
||||||
|
// - AlwaysVerify
|
||||||
|
// - all images require credential reverification
|
||||||
|
ImagePullCredentialsVerificationPolicy string
|
||||||
|
// preloadedImagesVerificationAllowlist specifies a list of images that are
|
||||||
|
// exempted from credential reverification for the "NeverVerifyAllowlistedImages"
|
||||||
|
// `imagePullCredentialsVerificationPolicy`.
|
||||||
|
// The list accepts a full path segment wildcard suffix "/*".
|
||||||
|
// Only use image specs without an image tag or digest.
|
||||||
|
PreloadedImagesVerificationAllowlist []string
|
||||||
// eventRecordQPS is the maximum event creations per second. If 0, there
|
// eventRecordQPS is the maximum event creations per second. If 0, there
|
||||||
// is no limit enforced.
|
// is no limit enforced.
|
||||||
EventRecordQPS int32
|
EventRecordQPS int32
|
||||||
@ -770,6 +789,25 @@ type CrashLoopBackOffConfig struct {
|
|||||||
MaxContainerRestartPeriod *metav1.Duration
|
MaxContainerRestartPeriod *metav1.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImagePullCredentialsVerificationPolicy is an enum for the policy that is enforced
|
||||||
|
// when pod is requesting an image that appears on the system
|
||||||
|
type ImagePullCredentialsVerificationPolicy string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// NeverVerify will never require credential verification for images that
|
||||||
|
// already exist on the node
|
||||||
|
NeverVerify ImagePullCredentialsVerificationPolicy = "NeverVerify"
|
||||||
|
// NeverVerifyPreloadedImages does not require credential verification for images
|
||||||
|
// pulled outside the kubelet process
|
||||||
|
NeverVerifyPreloadedImages ImagePullCredentialsVerificationPolicy = "NeverVerifyPreloadedImages"
|
||||||
|
// NeverVerifyAllowlistedImages does not require credential verification for
|
||||||
|
// a list of images that were pulled outside the kubelet process
|
||||||
|
NeverVerifyAllowlistedImages ImagePullCredentialsVerificationPolicy = "NeverVerifyAllowlistedImages"
|
||||||
|
// AlwaysVerify requires credential verification for accessing any image on the
|
||||||
|
// node irregardless how it was pulled
|
||||||
|
AlwaysVerify ImagePullCredentialsVerificationPolicy = "AlwaysVerify"
|
||||||
|
)
|
||||||
|
|
||||||
// ImagePullIntent is a record of the kubelet attempting to pull an image.
|
// ImagePullIntent is a record of the kubelet attempting to pull an image.
|
||||||
//
|
//
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
@ -313,4 +313,10 @@ func SetDefaults_KubeletConfiguration(obj *kubeletconfigv1beta1.KubeletConfigura
|
|||||||
obj.CrashLoopBackOff.MaxContainerRestartPeriod = &metav1.Duration{Duration: MaxContainerBackOff}
|
obj.CrashLoopBackOff.MaxContainerRestartPeriod = &metav1.Duration{Duration: MaxContainerBackOff}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if localFeatureGate.Enabled(features.KubeletEnsureSecretPulledImages) {
|
||||||
|
if obj.ImagePullCredentialsVerificationPolicy == "" {
|
||||||
|
obj.ImagePullCredentialsVerificationPolicy = kubeletconfigv1beta1.NeverVerifyPreloadedImages
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
|
|||||||
NodeLeaseDurationSeconds: 40,
|
NodeLeaseDurationSeconds: 40,
|
||||||
ImageMinimumGCAge: metav1.Duration{Duration: 2 * time.Minute},
|
ImageMinimumGCAge: metav1.Duration{Duration: 2 * time.Minute},
|
||||||
ImageMaximumGCAge: metav1.Duration{},
|
ImageMaximumGCAge: metav1.Duration{},
|
||||||
|
ImagePullCredentialsVerificationPolicy: "",
|
||||||
ImageGCHighThresholdPercent: ptr.To[int32](85),
|
ImageGCHighThresholdPercent: ptr.To[int32](85),
|
||||||
ImageGCLowThresholdPercent: ptr.To[int32](80),
|
ImageGCLowThresholdPercent: ptr.To[int32](80),
|
||||||
ContainerRuntimeEndpoint: "unix:///run/containerd/containerd.sock",
|
ContainerRuntimeEndpoint: "unix:///run/containerd/containerd.sock",
|
||||||
@ -168,74 +169,75 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
|
|||||||
CacheUnauthorizedTTL: zeroDuration,
|
CacheUnauthorizedTTL: zeroDuration,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
RegistryPullQPS: ptr.To[int32](0),
|
RegistryPullQPS: ptr.To[int32](0),
|
||||||
RegistryBurst: 0,
|
RegistryBurst: 0,
|
||||||
EventRecordQPS: ptr.To[int32](0),
|
EventRecordQPS: ptr.To[int32](0),
|
||||||
EventBurst: 0,
|
EventBurst: 0,
|
||||||
EnableDebuggingHandlers: ptr.To(false),
|
EnableDebuggingHandlers: ptr.To(false),
|
||||||
EnableContentionProfiling: false,
|
EnableContentionProfiling: false,
|
||||||
HealthzPort: ptr.To[int32](0),
|
HealthzPort: ptr.To[int32](0),
|
||||||
HealthzBindAddress: "",
|
HealthzBindAddress: "",
|
||||||
OOMScoreAdj: ptr.To[int32](0),
|
OOMScoreAdj: ptr.To[int32](0),
|
||||||
ClusterDomain: "",
|
ClusterDomain: "",
|
||||||
ClusterDNS: []string{},
|
ClusterDNS: []string{},
|
||||||
StreamingConnectionIdleTimeout: zeroDuration,
|
StreamingConnectionIdleTimeout: zeroDuration,
|
||||||
NodeStatusUpdateFrequency: zeroDuration,
|
NodeStatusUpdateFrequency: zeroDuration,
|
||||||
NodeStatusReportFrequency: zeroDuration,
|
NodeStatusReportFrequency: zeroDuration,
|
||||||
NodeLeaseDurationSeconds: 0,
|
NodeLeaseDurationSeconds: 0,
|
||||||
ContainerRuntimeEndpoint: "unix:///run/containerd/containerd.sock",
|
ContainerRuntimeEndpoint: "unix:///run/containerd/containerd.sock",
|
||||||
ImageMinimumGCAge: zeroDuration,
|
ImageMinimumGCAge: zeroDuration,
|
||||||
ImageGCHighThresholdPercent: ptr.To[int32](0),
|
ImagePullCredentialsVerificationPolicy: "",
|
||||||
ImageGCLowThresholdPercent: ptr.To[int32](0),
|
ImageGCHighThresholdPercent: ptr.To[int32](0),
|
||||||
VolumeStatsAggPeriod: zeroDuration,
|
ImageGCLowThresholdPercent: ptr.To[int32](0),
|
||||||
KubeletCgroups: "",
|
VolumeStatsAggPeriod: zeroDuration,
|
||||||
SystemCgroups: "",
|
KubeletCgroups: "",
|
||||||
CgroupRoot: "",
|
SystemCgroups: "",
|
||||||
CgroupsPerQOS: ptr.To(false),
|
CgroupRoot: "",
|
||||||
CgroupDriver: "",
|
CgroupsPerQOS: ptr.To(false),
|
||||||
CPUManagerPolicy: "",
|
CgroupDriver: "",
|
||||||
CPUManagerPolicyOptions: map[string]string{},
|
CPUManagerPolicy: "",
|
||||||
CPUManagerReconcilePeriod: zeroDuration,
|
CPUManagerPolicyOptions: map[string]string{},
|
||||||
MemoryManagerPolicy: "",
|
CPUManagerReconcilePeriod: zeroDuration,
|
||||||
TopologyManagerPolicy: "",
|
MemoryManagerPolicy: "",
|
||||||
TopologyManagerScope: "",
|
TopologyManagerPolicy: "",
|
||||||
QOSReserved: map[string]string{},
|
TopologyManagerScope: "",
|
||||||
RuntimeRequestTimeout: zeroDuration,
|
QOSReserved: map[string]string{},
|
||||||
HairpinMode: "",
|
RuntimeRequestTimeout: zeroDuration,
|
||||||
MaxPods: 0,
|
HairpinMode: "",
|
||||||
PodCIDR: "",
|
MaxPods: 0,
|
||||||
PodPidsLimit: ptr.To[int64](0),
|
PodCIDR: "",
|
||||||
ResolverConfig: ptr.To(""),
|
PodPidsLimit: ptr.To[int64](0),
|
||||||
RunOnce: false,
|
ResolverConfig: ptr.To(""),
|
||||||
CPUCFSQuota: ptr.To(false),
|
RunOnce: false,
|
||||||
CPUCFSQuotaPeriod: &zeroDuration,
|
CPUCFSQuota: ptr.To(false),
|
||||||
NodeStatusMaxImages: ptr.To[int32](0),
|
CPUCFSQuotaPeriod: &zeroDuration,
|
||||||
MaxOpenFiles: 0,
|
NodeStatusMaxImages: ptr.To[int32](0),
|
||||||
ContentType: "",
|
MaxOpenFiles: 0,
|
||||||
KubeAPIQPS: ptr.To[int32](0),
|
ContentType: "",
|
||||||
KubeAPIBurst: 0,
|
KubeAPIQPS: ptr.To[int32](0),
|
||||||
SerializeImagePulls: ptr.To(false),
|
KubeAPIBurst: 0,
|
||||||
MaxParallelImagePulls: nil,
|
SerializeImagePulls: ptr.To(false),
|
||||||
EvictionHard: map[string]string{},
|
MaxParallelImagePulls: nil,
|
||||||
EvictionSoft: map[string]string{},
|
EvictionHard: map[string]string{},
|
||||||
EvictionSoftGracePeriod: map[string]string{},
|
EvictionSoft: map[string]string{},
|
||||||
EvictionPressureTransitionPeriod: zeroDuration,
|
EvictionSoftGracePeriod: map[string]string{},
|
||||||
EvictionMaxPodGracePeriod: 0,
|
EvictionPressureTransitionPeriod: zeroDuration,
|
||||||
EvictionMinimumReclaim: map[string]string{},
|
EvictionMaxPodGracePeriod: 0,
|
||||||
MergeDefaultEvictionSettings: ptr.To(false),
|
EvictionMinimumReclaim: map[string]string{},
|
||||||
PodsPerCore: 0,
|
MergeDefaultEvictionSettings: ptr.To(false),
|
||||||
EnableControllerAttachDetach: ptr.To(false),
|
PodsPerCore: 0,
|
||||||
ProtectKernelDefaults: false,
|
EnableControllerAttachDetach: ptr.To(false),
|
||||||
MakeIPTablesUtilChains: ptr.To(false),
|
ProtectKernelDefaults: false,
|
||||||
IPTablesMasqueradeBit: ptr.To[int32](0),
|
MakeIPTablesUtilChains: ptr.To(false),
|
||||||
IPTablesDropBit: ptr.To[int32](0),
|
IPTablesMasqueradeBit: ptr.To[int32](0),
|
||||||
FeatureGates: map[string]bool{},
|
IPTablesDropBit: ptr.To[int32](0),
|
||||||
FailSwapOn: ptr.To(false),
|
FeatureGates: map[string]bool{},
|
||||||
MemorySwap: v1beta1.MemorySwapConfiguration{SwapBehavior: ""},
|
FailSwapOn: ptr.To(false),
|
||||||
ContainerLogMaxSize: "",
|
MemorySwap: v1beta1.MemorySwapConfiguration{SwapBehavior: ""},
|
||||||
ContainerLogMaxFiles: ptr.To[int32](0),
|
ContainerLogMaxSize: "",
|
||||||
ContainerLogMaxWorkers: ptr.To[int32](1),
|
ContainerLogMaxFiles: ptr.To[int32](0),
|
||||||
ContainerLogMonitorInterval: &metav1.Duration{Duration: 10 * time.Second},
|
ContainerLogMaxWorkers: ptr.To[int32](1),
|
||||||
|
ContainerLogMonitorInterval: &metav1.Duration{Duration: 10 * time.Second},
|
||||||
ConfigMapAndSecretChangeDetectionStrategy: v1beta1.WatchChangeDetectionStrategy,
|
ConfigMapAndSecretChangeDetectionStrategy: v1beta1.WatchChangeDetectionStrategy,
|
||||||
SystemReserved: map[string]string{},
|
SystemReserved: map[string]string{},
|
||||||
KubeReserved: map[string]string{},
|
KubeReserved: map[string]string{},
|
||||||
@ -307,6 +309,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
|
|||||||
ImageMinimumGCAge: metav1.Duration{Duration: 2 * time.Minute},
|
ImageMinimumGCAge: metav1.Duration{Duration: 2 * time.Minute},
|
||||||
ImageGCHighThresholdPercent: ptr.To[int32](0),
|
ImageGCHighThresholdPercent: ptr.To[int32](0),
|
||||||
ImageGCLowThresholdPercent: ptr.To[int32](0),
|
ImageGCLowThresholdPercent: ptr.To[int32](0),
|
||||||
|
ImagePullCredentialsVerificationPolicy: "",
|
||||||
VolumeStatsAggPeriod: metav1.Duration{Duration: time.Minute},
|
VolumeStatsAggPeriod: metav1.Duration{Duration: time.Minute},
|
||||||
CgroupsPerQOS: ptr.To(false),
|
CgroupsPerQOS: ptr.To(false),
|
||||||
CgroupDriver: "cgroupfs",
|
CgroupDriver: "cgroupfs",
|
||||||
@ -407,54 +410,55 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
|
|||||||
CacheUnauthorizedTTL: metav1.Duration{Duration: 60 * time.Second},
|
CacheUnauthorizedTTL: metav1.Duration{Duration: 60 * time.Second},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
RegistryPullQPS: ptr.To[int32](1),
|
RegistryPullQPS: ptr.To[int32](1),
|
||||||
RegistryBurst: 1,
|
RegistryBurst: 1,
|
||||||
EventRecordQPS: ptr.To[int32](1),
|
EventRecordQPS: ptr.To[int32](1),
|
||||||
EventBurst: 1,
|
EventBurst: 1,
|
||||||
EnableDebuggingHandlers: ptr.To(true),
|
EnableDebuggingHandlers: ptr.To(true),
|
||||||
EnableContentionProfiling: true,
|
EnableContentionProfiling: true,
|
||||||
HealthzPort: ptr.To[int32](1),
|
HealthzPort: ptr.To[int32](1),
|
||||||
HealthzBindAddress: "127.0.0.2",
|
HealthzBindAddress: "127.0.0.2",
|
||||||
OOMScoreAdj: ptr.To[int32](1),
|
OOMScoreAdj: ptr.To[int32](1),
|
||||||
ClusterDomain: "cluster-domain",
|
ClusterDomain: "cluster-domain",
|
||||||
ClusterDNS: []string{"192.168.1.3"},
|
ClusterDNS: []string{"192.168.1.3"},
|
||||||
StreamingConnectionIdleTimeout: metav1.Duration{Duration: 60 * time.Second},
|
StreamingConnectionIdleTimeout: metav1.Duration{Duration: 60 * time.Second},
|
||||||
NodeStatusUpdateFrequency: metav1.Duration{Duration: 60 * time.Second},
|
NodeStatusUpdateFrequency: metav1.Duration{Duration: 60 * time.Second},
|
||||||
NodeStatusReportFrequency: metav1.Duration{Duration: 60 * time.Second},
|
NodeStatusReportFrequency: metav1.Duration{Duration: 60 * time.Second},
|
||||||
NodeLeaseDurationSeconds: 1,
|
NodeLeaseDurationSeconds: 1,
|
||||||
ContainerRuntimeEndpoint: "unix:///run/containerd/containerd.sock",
|
ContainerRuntimeEndpoint: "unix:///run/containerd/containerd.sock",
|
||||||
ImageMinimumGCAge: metav1.Duration{Duration: 60 * time.Second},
|
ImageMinimumGCAge: metav1.Duration{Duration: 60 * time.Second},
|
||||||
ImageGCHighThresholdPercent: ptr.To[int32](1),
|
ImageGCHighThresholdPercent: ptr.To[int32](1),
|
||||||
ImageGCLowThresholdPercent: ptr.To[int32](1),
|
ImageGCLowThresholdPercent: ptr.To[int32](1),
|
||||||
VolumeStatsAggPeriod: metav1.Duration{Duration: 60 * time.Second},
|
PreloadedImagesVerificationAllowlist: []string{"test.test/repo/image"},
|
||||||
KubeletCgroups: "kubelet-cgroup",
|
VolumeStatsAggPeriod: metav1.Duration{Duration: 60 * time.Second},
|
||||||
SystemCgroups: "system-cgroup",
|
KubeletCgroups: "kubelet-cgroup",
|
||||||
CgroupRoot: "root-cgroup",
|
SystemCgroups: "system-cgroup",
|
||||||
CgroupsPerQOS: ptr.To(true),
|
CgroupRoot: "root-cgroup",
|
||||||
CgroupDriver: "systemd",
|
CgroupsPerQOS: ptr.To(true),
|
||||||
CPUManagerPolicy: "cpu-manager-policy",
|
CgroupDriver: "systemd",
|
||||||
CPUManagerPolicyOptions: map[string]string{"key": "value"},
|
CPUManagerPolicy: "cpu-manager-policy",
|
||||||
CPUManagerReconcilePeriod: metav1.Duration{Duration: 60 * time.Second},
|
CPUManagerPolicyOptions: map[string]string{"key": "value"},
|
||||||
MemoryManagerPolicy: v1beta1.StaticMemoryManagerPolicy,
|
CPUManagerReconcilePeriod: metav1.Duration{Duration: 60 * time.Second},
|
||||||
TopologyManagerPolicy: v1beta1.RestrictedTopologyManagerPolicy,
|
MemoryManagerPolicy: v1beta1.StaticMemoryManagerPolicy,
|
||||||
TopologyManagerScope: v1beta1.PodTopologyManagerScope,
|
TopologyManagerPolicy: v1beta1.RestrictedTopologyManagerPolicy,
|
||||||
QOSReserved: map[string]string{"memory": "10%"},
|
TopologyManagerScope: v1beta1.PodTopologyManagerScope,
|
||||||
RuntimeRequestTimeout: metav1.Duration{Duration: 60 * time.Second},
|
QOSReserved: map[string]string{"memory": "10%"},
|
||||||
HairpinMode: v1beta1.HairpinVeth,
|
RuntimeRequestTimeout: metav1.Duration{Duration: 60 * time.Second},
|
||||||
MaxPods: 1,
|
HairpinMode: v1beta1.HairpinVeth,
|
||||||
PodCIDR: "192.168.1.0/24",
|
MaxPods: 1,
|
||||||
PodPidsLimit: ptr.To[int64](1),
|
PodCIDR: "192.168.1.0/24",
|
||||||
ResolverConfig: ptr.To("resolver-config"),
|
PodPidsLimit: ptr.To[int64](1),
|
||||||
RunOnce: true,
|
ResolverConfig: ptr.To("resolver-config"),
|
||||||
CPUCFSQuota: ptr.To(true),
|
RunOnce: true,
|
||||||
CPUCFSQuotaPeriod: &metav1.Duration{Duration: 60 * time.Second},
|
CPUCFSQuota: ptr.To(true),
|
||||||
NodeStatusMaxImages: ptr.To[int32](1),
|
CPUCFSQuotaPeriod: &metav1.Duration{Duration: 60 * time.Second},
|
||||||
MaxOpenFiles: 1,
|
NodeStatusMaxImages: ptr.To[int32](1),
|
||||||
ContentType: "application/protobuf",
|
MaxOpenFiles: 1,
|
||||||
KubeAPIQPS: ptr.To[int32](1),
|
ContentType: "application/protobuf",
|
||||||
KubeAPIBurst: 1,
|
KubeAPIQPS: ptr.To[int32](1),
|
||||||
SerializeImagePulls: ptr.To(true),
|
KubeAPIBurst: 1,
|
||||||
MaxParallelImagePulls: ptr.To[int32](5),
|
SerializeImagePulls: ptr.To(true),
|
||||||
|
MaxParallelImagePulls: ptr.To[int32](5),
|
||||||
EvictionHard: map[string]string{
|
EvictionHard: map[string]string{
|
||||||
"memory.available": "1Mi",
|
"memory.available": "1Mi",
|
||||||
"nodefs.available": "1%",
|
"nodefs.available": "1%",
|
||||||
@ -563,54 +567,55 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
|
|||||||
CacheUnauthorizedTTL: metav1.Duration{Duration: 60 * time.Second},
|
CacheUnauthorizedTTL: metav1.Duration{Duration: 60 * time.Second},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
RegistryPullQPS: ptr.To[int32](1),
|
RegistryPullQPS: ptr.To[int32](1),
|
||||||
RegistryBurst: 1,
|
RegistryBurst: 1,
|
||||||
EventRecordQPS: ptr.To[int32](1),
|
EventRecordQPS: ptr.To[int32](1),
|
||||||
EventBurst: 1,
|
EventBurst: 1,
|
||||||
EnableDebuggingHandlers: ptr.To(true),
|
EnableDebuggingHandlers: ptr.To(true),
|
||||||
EnableContentionProfiling: true,
|
EnableContentionProfiling: true,
|
||||||
HealthzPort: ptr.To[int32](1),
|
HealthzPort: ptr.To[int32](1),
|
||||||
HealthzBindAddress: "127.0.0.2",
|
HealthzBindAddress: "127.0.0.2",
|
||||||
OOMScoreAdj: ptr.To[int32](1),
|
OOMScoreAdj: ptr.To[int32](1),
|
||||||
ClusterDomain: "cluster-domain",
|
ClusterDomain: "cluster-domain",
|
||||||
ClusterDNS: []string{"192.168.1.3"},
|
ClusterDNS: []string{"192.168.1.3"},
|
||||||
StreamingConnectionIdleTimeout: metav1.Duration{Duration: 60 * time.Second},
|
StreamingConnectionIdleTimeout: metav1.Duration{Duration: 60 * time.Second},
|
||||||
NodeStatusUpdateFrequency: metav1.Duration{Duration: 60 * time.Second},
|
NodeStatusUpdateFrequency: metav1.Duration{Duration: 60 * time.Second},
|
||||||
NodeStatusReportFrequency: metav1.Duration{Duration: 60 * time.Second},
|
NodeStatusReportFrequency: metav1.Duration{Duration: 60 * time.Second},
|
||||||
NodeLeaseDurationSeconds: 1,
|
NodeLeaseDurationSeconds: 1,
|
||||||
ContainerRuntimeEndpoint: "unix:///run/containerd/containerd.sock",
|
ContainerRuntimeEndpoint: "unix:///run/containerd/containerd.sock",
|
||||||
ImageMinimumGCAge: metav1.Duration{Duration: 60 * time.Second},
|
ImageMinimumGCAge: metav1.Duration{Duration: 60 * time.Second},
|
||||||
ImageGCHighThresholdPercent: ptr.To[int32](1),
|
ImageGCHighThresholdPercent: ptr.To[int32](1),
|
||||||
ImageGCLowThresholdPercent: ptr.To[int32](1),
|
ImageGCLowThresholdPercent: ptr.To[int32](1),
|
||||||
VolumeStatsAggPeriod: metav1.Duration{Duration: 60 * time.Second},
|
PreloadedImagesVerificationAllowlist: []string{"test.test/repo/image"},
|
||||||
KubeletCgroups: "kubelet-cgroup",
|
VolumeStatsAggPeriod: metav1.Duration{Duration: 60 * time.Second},
|
||||||
SystemCgroups: "system-cgroup",
|
KubeletCgroups: "kubelet-cgroup",
|
||||||
CgroupRoot: "root-cgroup",
|
SystemCgroups: "system-cgroup",
|
||||||
CgroupsPerQOS: ptr.To(true),
|
CgroupRoot: "root-cgroup",
|
||||||
CgroupDriver: "systemd",
|
CgroupsPerQOS: ptr.To(true),
|
||||||
CPUManagerPolicy: "cpu-manager-policy",
|
CgroupDriver: "systemd",
|
||||||
CPUManagerPolicyOptions: map[string]string{"key": "value"},
|
CPUManagerPolicy: "cpu-manager-policy",
|
||||||
CPUManagerReconcilePeriod: metav1.Duration{Duration: 60 * time.Second},
|
CPUManagerPolicyOptions: map[string]string{"key": "value"},
|
||||||
MemoryManagerPolicy: v1beta1.StaticMemoryManagerPolicy,
|
CPUManagerReconcilePeriod: metav1.Duration{Duration: 60 * time.Second},
|
||||||
TopologyManagerPolicy: v1beta1.RestrictedTopologyManagerPolicy,
|
MemoryManagerPolicy: v1beta1.StaticMemoryManagerPolicy,
|
||||||
TopologyManagerScope: v1beta1.PodTopologyManagerScope,
|
TopologyManagerPolicy: v1beta1.RestrictedTopologyManagerPolicy,
|
||||||
QOSReserved: map[string]string{"memory": "10%"},
|
TopologyManagerScope: v1beta1.PodTopologyManagerScope,
|
||||||
RuntimeRequestTimeout: metav1.Duration{Duration: 60 * time.Second},
|
QOSReserved: map[string]string{"memory": "10%"},
|
||||||
HairpinMode: v1beta1.HairpinVeth,
|
RuntimeRequestTimeout: metav1.Duration{Duration: 60 * time.Second},
|
||||||
MaxPods: 1,
|
HairpinMode: v1beta1.HairpinVeth,
|
||||||
PodCIDR: "192.168.1.0/24",
|
MaxPods: 1,
|
||||||
PodPidsLimit: ptr.To[int64](1),
|
PodCIDR: "192.168.1.0/24",
|
||||||
ResolverConfig: ptr.To("resolver-config"),
|
PodPidsLimit: ptr.To[int64](1),
|
||||||
RunOnce: true,
|
ResolverConfig: ptr.To("resolver-config"),
|
||||||
CPUCFSQuota: ptr.To(true),
|
RunOnce: true,
|
||||||
CPUCFSQuotaPeriod: &metav1.Duration{Duration: 60 * time.Second},
|
CPUCFSQuota: ptr.To(true),
|
||||||
NodeStatusMaxImages: ptr.To[int32](1),
|
CPUCFSQuotaPeriod: &metav1.Duration{Duration: 60 * time.Second},
|
||||||
MaxOpenFiles: 1,
|
NodeStatusMaxImages: ptr.To[int32](1),
|
||||||
ContentType: "application/protobuf",
|
MaxOpenFiles: 1,
|
||||||
KubeAPIQPS: ptr.To[int32](1),
|
ContentType: "application/protobuf",
|
||||||
KubeAPIBurst: 1,
|
KubeAPIQPS: ptr.To[int32](1),
|
||||||
SerializeImagePulls: ptr.To(true),
|
KubeAPIBurst: 1,
|
||||||
MaxParallelImagePulls: ptr.To[int32](5),
|
SerializeImagePulls: ptr.To(true),
|
||||||
|
MaxParallelImagePulls: ptr.To[int32](5),
|
||||||
EvictionHard: map[string]string{
|
EvictionHard: map[string]string{
|
||||||
"memory.available": "1Mi",
|
"memory.available": "1Mi",
|
||||||
"nodefs.available": "1%",
|
"nodefs.available": "1%",
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
tracingapi "k8s.io/component-base/tracing/api/v1"
|
tracingapi "k8s.io/component-base/tracing/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/images"
|
||||||
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
|
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
|
||||||
utilfs "k8s.io/kubernetes/pkg/util/filesystem"
|
utilfs "k8s.io/kubernetes/pkg/util/filesystem"
|
||||||
utiltaints "k8s.io/kubernetes/pkg/util/taints"
|
utiltaints "k8s.io/kubernetes/pkg/util/taints"
|
||||||
@ -286,6 +287,32 @@ func ValidateKubeletConfiguration(kc *kubeletconfig.KubeletConfiguration, featur
|
|||||||
allErrors = append(allErrors, fmt.Errorf("invalid configuration: option %q specified for hairpinMode (--hairpin-mode). Valid options are %q, %q or %q",
|
allErrors = append(allErrors, fmt.Errorf("invalid configuration: option %q specified for hairpinMode (--hairpin-mode). Valid options are %q, %q or %q",
|
||||||
kc.HairpinMode, kubeletconfig.HairpinNone, kubeletconfig.HairpinVeth, kubeletconfig.PromiscuousBridge))
|
kc.HairpinMode, kubeletconfig.HairpinNone, kubeletconfig.HairpinVeth, kubeletconfig.PromiscuousBridge))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if localFeatureGate.Enabled(features.KubeletEnsureSecretPulledImages) {
|
||||||
|
switch kc.ImagePullCredentialsVerificationPolicy {
|
||||||
|
case string(kubeletconfig.NeverVerify),
|
||||||
|
string(kubeletconfig.NeverVerifyPreloadedImages),
|
||||||
|
string(kubeletconfig.NeverVerifyAllowlistedImages),
|
||||||
|
string(kubeletconfig.AlwaysVerify):
|
||||||
|
default:
|
||||||
|
allErrors = append(allErrors, fmt.Errorf("invalid configuration: option %q specified for imagePullCredentialsVerificationPolicy. Valid options are %q, %q, %q or %q",
|
||||||
|
kc.ImagePullCredentialsVerificationPolicy, kubeletconfig.NeverVerify, kubeletconfig.NeverVerifyPreloadedImages, kubeletconfig.NeverVerifyAllowlistedImages, kubeletconfig.AlwaysVerify))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(kc.PreloadedImagesVerificationAllowlist) > 0 && kc.ImagePullCredentialsVerificationPolicy != string(kubeletconfig.NeverVerifyAllowlistedImages) {
|
||||||
|
allErrors = append(allErrors, fmt.Errorf("invalid configuration: can't set `preloadedImagesVerificationAllowlist` if `imagePullCredentialsVertificationPolicy` is not \"NeverVerifyAllowlistedImages\""))
|
||||||
|
} else if err := images.ValidateAllowlistImagesPatterns(kc.PreloadedImagesVerificationAllowlist); err != nil {
|
||||||
|
allErrors = append(allErrors, fmt.Errorf("invalid configuration: invalid image pattern in `preloadedImagesVerificationAllowlist`: %w", err))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(kc.ImagePullCredentialsVerificationPolicy) > 0 {
|
||||||
|
allErrors = append(allErrors, fmt.Errorf("invalid configuration: `imagePullCredentialsVerificationPolicy` must not be set if KubeletEnsureSecretPulledImages feature gate is not enabled"))
|
||||||
|
}
|
||||||
|
if len(kc.PreloadedImagesVerificationAllowlist) > 0 {
|
||||||
|
allErrors = append(allErrors, fmt.Errorf("invalid configuration: `preloadedImagesVerificationAllowlist` must not be set if KubeletEnsureSecretPulledImages feature gate is not enabled"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if kc.ReservedSystemCPUs != "" {
|
if kc.ReservedSystemCPUs != "" {
|
||||||
// --reserved-cpus does not support --system-reserved-cgroup or --kube-reserved-cgroup
|
// --reserved-cpus does not support --system-reserved-cgroup or --kube-reserved-cgroup
|
||||||
if kc.SystemReservedCgroup != "" || kc.KubeReservedCgroup != "" {
|
if kc.SystemReservedCgroup != "" || kc.KubeReservedCgroup != "" {
|
||||||
|
@ -728,6 +728,39 @@ func TestValidateKubeletConfiguration(t *testing.T) {
|
|||||||
return conf
|
return conf
|
||||||
},
|
},
|
||||||
errMsg: "logging.format: Invalid value: \"invalid\": Unsupported log format",
|
errMsg: "logging.format: Invalid value: \"invalid\": Unsupported log format",
|
||||||
|
}, {
|
||||||
|
name: "invalid imagePullCredentialsVerificationPolicy configuration",
|
||||||
|
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||||
|
conf.FeatureGates = map[string]bool{"KubeletEnsureSecretPulledImages": true}
|
||||||
|
conf.ImagePullCredentialsVerificationPolicy = "invalid"
|
||||||
|
return conf
|
||||||
|
},
|
||||||
|
errMsg: `option "invalid" specified for imagePullCredentialsVerificationPolicy. Valid options are "NeverVerify", "NeverVerifyPreloadedImages", "NeverVerifyAllowlistedImages" or "AlwaysVerify"]`,
|
||||||
|
}, {
|
||||||
|
name: "invalid PreloadedImagesVerificationAllowlist configuration - featuregate enabled",
|
||||||
|
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||||
|
conf.FeatureGates = map[string]bool{"KubeletEnsureSecretPulledImages": true}
|
||||||
|
conf.ImagePullCredentialsVerificationPolicy = string(kubeletconfig.NeverVerify)
|
||||||
|
conf.PreloadedImagesVerificationAllowlist = []string{"test.test/repo"}
|
||||||
|
return conf
|
||||||
|
},
|
||||||
|
errMsg: "can't set `preloadedImagesVerificationAllowlist` if `imagePullCredentialsVertificationPolicy` is not \"NeverVerifyAllowlistedImages\"]",
|
||||||
|
}, {
|
||||||
|
name: "invalid PreloadedImagesVerificationAllowlist configuration - featuregate disabled",
|
||||||
|
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||||
|
conf.FeatureGates = map[string]bool{"KubeletEnsureSecretPulledImages": false}
|
||||||
|
conf.ImagePullCredentialsVerificationPolicy = string(kubeletconfig.NeverVerify)
|
||||||
|
return conf
|
||||||
|
},
|
||||||
|
errMsg: "invalid configuration: `imagePullCredentialsVerificationPolicy` must not be set if KubeletEnsureSecretPulledImages feature gate is not enabled",
|
||||||
|
}, {
|
||||||
|
name: "invalid PreloadedImagesVerificationAllowlist configuration",
|
||||||
|
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||||
|
conf.FeatureGates = map[string]bool{"KubeletEnsureSecretPulledImages": false}
|
||||||
|
conf.PreloadedImagesVerificationAllowlist = []string{"test.test/repo"}
|
||||||
|
return conf
|
||||||
|
},
|
||||||
|
errMsg: "invalid configuration: `preloadedImagesVerificationAllowlist` must not be set if KubeletEnsureSecretPulledImages feature gate is not enabled",
|
||||||
}, {
|
}, {
|
||||||
name: "invalid FeatureGate",
|
name: "invalid FeatureGate",
|
||||||
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration {
|
||||||
|
@ -83,6 +83,25 @@ const (
|
|||||||
StaticMemoryManagerPolicy = "Static"
|
StaticMemoryManagerPolicy = "Static"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ImagePullCredentialsVerificationPolicy is an enum for the policy that is enforced
|
||||||
|
// when pod is requesting an image that appears on the system
|
||||||
|
type ImagePullCredentialsVerificationPolicy string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// NeverVerify will never require credential verification for images that
|
||||||
|
// already exist on the node
|
||||||
|
NeverVerify ImagePullCredentialsVerificationPolicy = "NeverVerify"
|
||||||
|
// NeverVerifyPreloadedImages does not require credential verification for images
|
||||||
|
// pulled outside the kubelet process
|
||||||
|
NeverVerifyPreloadedImages ImagePullCredentialsVerificationPolicy = "NeverVerifyPreloadedImages"
|
||||||
|
// NeverVerifyAllowlistedImages does not require credential verification for
|
||||||
|
// a list of images that were pulled outside the kubelet process
|
||||||
|
NeverVerifyAllowlistedImages ImagePullCredentialsVerificationPolicy = "NeverVerifyAllowlistedImages"
|
||||||
|
// AlwaysVerify requires credential verification for accessing any image on the
|
||||||
|
// node irregardless how it was pulled
|
||||||
|
AlwaysVerify ImagePullCredentialsVerificationPolicy = "AlwaysVerify"
|
||||||
|
)
|
||||||
|
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
// KubeletConfiguration contains the configuration for the Kubelet
|
// KubeletConfiguration contains the configuration for the Kubelet
|
||||||
@ -210,6 +229,28 @@ type KubeletConfiguration struct {
|
|||||||
// Default: 10
|
// Default: 10
|
||||||
// +optional
|
// +optional
|
||||||
RegistryBurst int32 `json:"registryBurst,omitempty"`
|
RegistryBurst int32 `json:"registryBurst,omitempty"`
|
||||||
|
// imagePullCredentialsVerificationPolicy determines how credentials should be
|
||||||
|
// verified when pod requests an image that is already present on the node:
|
||||||
|
// - NeverVerify
|
||||||
|
// - anyone on a node can use any image present on the node
|
||||||
|
// - NeverVerifyPreloadedImages
|
||||||
|
// - images that were pulled to the node by something else than the kubelet
|
||||||
|
// can be used without reverifying pull credentials
|
||||||
|
// - NeverVerifyAllowlistedImages
|
||||||
|
// - like "NeverVerifyPreloadedImages" but only node images from
|
||||||
|
// `preloadedImagesVerificationAllowlist` don't require reverification
|
||||||
|
// - AlwaysVerify
|
||||||
|
// - all images require credential reverification
|
||||||
|
// +optional
|
||||||
|
ImagePullCredentialsVerificationPolicy ImagePullCredentialsVerificationPolicy `json:"imagePullCredentialsVerificationPolicy,omitempty"`
|
||||||
|
// preloadedImagesVerificationAllowlist specifies a list of images that are
|
||||||
|
// exempted from credential reverification for the "NeverVerifyAllowlistedImages"
|
||||||
|
// `imagePullCredentialsVerificationPolicy`.
|
||||||
|
// The list accepts a full path segment wildcard suffix "/*".
|
||||||
|
// Only use image specs without an image tag or digest.
|
||||||
|
// +optional
|
||||||
|
// +listType=set
|
||||||
|
PreloadedImagesVerificationAllowlist []string `json:"preloadedImagesVerificationAllowlist,omitempty"`
|
||||||
// eventRecordQPS is the maximum event creations per second. If 0, there
|
// eventRecordQPS is the maximum event creations per second. If 0, there
|
||||||
// is no limit enforced. The value cannot be a negative number.
|
// is no limit enforced. The value cannot be a negative number.
|
||||||
// Default: 50
|
// Default: 50
|
||||||
|
Loading…
Reference in New Issue
Block a user