KEP-5495: Add featuregate for IPVS

This commit is contained in:
Adrian Moisey 2026-05-31 17:20:17 +02:00
parent d542c13df8
commit f7265100cb
No known key found for this signature in database
GPG key ID: 41AE4AE32747C7CF
6 changed files with 64 additions and 5 deletions

View file

@ -182,7 +182,7 @@ func (s *ProxyServer) createProxier(ctx context.Context, config *kubeproxyconfig
ipts := utiliptables.NewBestEffort()
logger.Info("Using ipvs Proxier")
message := "The ipvs proxier is now deprecated and may be removed in a future release. Please use 'nftables' instead."
message := "The ipvs proxier has been deprecated and will be disabled by default in Kubernetes 1.40 and removed in Kubernetes 1.43. Migrate to the 'nftables' proxier instead."
logger.Error(nil, message)
s.Recorder.Eventf(s.NodeRef, nil, v1.EventTypeWarning, "IPVSDeprecation", "StartKubeProxy", message)
if dualStack {

View file

@ -470,6 +470,12 @@ const (
// Allows to delegate reconciliation of a Job object to an external controller.
JobManagedBy featuregate.Feature = "JobManagedBy"
// owner: @adrianmoisey @danwinship
// kep: https://kep.k8s.io/5495
//
// Allow use of IPVS mode in kube-proxy
KubeProxyIPVS featuregate.Feature = "KubeProxyIPVS"
// owner: @marquiz
// kep: http://kep.k8s.io/4033
//
@ -1493,6 +1499,10 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.35"), Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.38
},
KubeProxyIPVS: {
{Version: version.MustParse("1.11"), Default: true, PreRelease: featuregate.GA},
},
KubeletCgroupDriverFromCRI: {
{Version: version.MustParse("1.28"), Default: false, PreRelease: featuregate.Alpha},
{Version: version.MustParse("1.31"), Default: true, PreRelease: featuregate.Beta},
@ -2359,6 +2369,8 @@ var defaultKubernetesFeatureGateDependencies = map[featuregate.Feature][]feature
JobManagedBy: {},
KubeProxyIPVS: {},
KubeletCgroupDriverFromCRI: {},
KubeletCrashLoopBackOffMax: {},

View file

@ -30,6 +30,7 @@ import (
logsapi "k8s.io/component-base/logs/api/v1"
"k8s.io/component-base/metrics"
apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
"k8s.io/kubernetes/pkg/features"
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
netutils "k8s.io/utils/net"
)
@ -171,10 +172,13 @@ func validateProxyMode(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) fiel
func validateProxyModeLinux(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) field.ErrorList {
validModes := sets.New[string](
string(kubeproxyconfig.ProxyModeIPTables),
string(kubeproxyconfig.ProxyModeIPVS),
string(kubeproxyconfig.ProxyModeNFTables),
)
if utilfeature.DefaultFeatureGate.Enabled(features.KubeProxyIPVS) {
validModes.Insert(string(kubeproxyconfig.ProxyModeIPVS))
}
if mode == "" || validModes.Has(string(mode)) {
return nil
}

View file

@ -27,8 +27,11 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
utilfeature "k8s.io/apiserver/pkg/util/feature"
componentbaseconfig "k8s.io/component-base/config"
featuregatetesting "k8s.io/component-base/featuregate/testing"
logsapi "k8s.io/component-base/logs/api/v1"
"k8s.io/kubernetes/pkg/features"
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
"k8s.io/utils/ptr"
)
@ -429,8 +432,9 @@ func TestValidateProxyMode(t *testing.T) {
func testValidateProxyModeLinux(t *testing.T) {
newPath := field.NewPath("KubeProxyConfiguration")
for name, testCase := range map[string]struct {
mode kubeproxyconfig.ProxyMode
expectedErrs field.ErrorList
mode kubeproxyconfig.ProxyMode
expectedErrs field.ErrorList
enableKubeProxyIPVS *bool
}{
"blank mode should default": {
mode: kubeproxyconfig.ProxyMode(""),
@ -438,12 +442,38 @@ func testValidateProxyModeLinux(t *testing.T) {
"iptables is allowed": {
mode: kubeproxyconfig.ProxyModeIPTables,
},
"ipvs is allowed": {
"iptables is allowed - with KubeProxyIPVS feature gate enabled": {
mode: kubeproxyconfig.ProxyModeIPTables,
enableKubeProxyIPVS: new(true),
},
"iptables is allowed - with KubeProxyIPVS feature gate disabled": {
mode: kubeproxyconfig.ProxyModeIPTables,
enableKubeProxyIPVS: new(false),
},
"ipvs is allowed - with KubeProxyIPVS feature gate in default state": {
mode: kubeproxyconfig.ProxyModeIPVS,
},
"ipvs is allowed - with KubeProxyIPVS feature gate enabled": {
mode: kubeproxyconfig.ProxyModeIPVS,
enableKubeProxyIPVS: new(true),
},
"ipvs is not allowed - with KubeProxyIPVS feature gate disabled": {
mode: kubeproxyconfig.ProxyModeIPVS,
enableKubeProxyIPVS: new(false),
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ProxyMode"), "ipvs", "must be iptables, nftables or blank (blank means the best-available proxy [currently iptables])")},
},
"nftables is allowed": {
mode: kubeproxyconfig.ProxyModeNFTables,
},
"nftables is allowed - with KubeProxyIPVS feature gate enabled": {
mode: kubeproxyconfig.ProxyModeNFTables,
enableKubeProxyIPVS: new(true),
},
"nftables is allowed - with KubeProxyIPVS feature gate disabled": {
mode: kubeproxyconfig.ProxyModeNFTables,
enableKubeProxyIPVS: new(false),
},
"winkernel is not allowed": {
mode: kubeproxyconfig.ProxyModeKernelspace,
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ProxyMode"), "kernelspace", "must be iptables, ipvs, nftables or blank (blank means the best-available proxy [currently iptables])")},
@ -454,6 +484,12 @@ func testValidateProxyModeLinux(t *testing.T) {
},
} {
t.Run(name, func(t *testing.T) {
if testCase.enableKubeProxyIPVS != nil {
featuregatetesting.SetFeatureGatesDuringTest(t, utilfeature.DefaultFeatureGate, featuregatetesting.FeatureOverrides{
features.KubeProxyIPVS: *testCase.enableKubeProxyIPVS,
})
}
errs := validateProxyMode(testCase.mode, newPath)
assert.Equal(t, testCase.expectedErrs, errs, "did not get expected validation errors")
})

View file

@ -99,6 +99,7 @@
| InformerResourceVersion | :ballot_box_with_check: 1.35+ | | 1.301.34 | | 1.35 | | | [code](https://cs.k8s.io/?q=%5CbInformerResourceVersion%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbInformerResourceVersion%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| JobManagedBy | :ballot_box_with_check: 1.32+ | :closed_lock_with_key: 1.35+ | 1.301.31 | 1.321.34 | 1.35 | | | [code](https://cs.k8s.io/?q=%5CbJobManagedBy%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbJobManagedBy%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| KMSv1 | :ballot_box_with_check: 1.0+ | | | | 1.01.27 | 1.28 | | [code](https://cs.k8s.io/?q=%5CbKMSv1%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbKMSv1%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| KubeProxyIPVS | :ballot_box_with_check: 1.11+ | | | | 1.11 | | | [code](https://cs.k8s.io/?q=%5CbKubeProxyIPVS%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbKubeProxyIPVS%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| KubeletCgroupDriverFromCRI | :ballot_box_with_check: 1.31+ | :closed_lock_with_key: 1.34+ | 1.281.30 | 1.311.33 | 1.34 | | | [code](https://cs.k8s.io/?q=%5CbKubeletCgroupDriverFromCRI%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbKubeletCgroupDriverFromCRI%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| KubeletCrashLoopBackOffMax | :ballot_box_with_check: 1.35+ | | 1.321.34 | 1.35 | | | | [code](https://cs.k8s.io/?q=%5CbKubeletCrashLoopBackOffMax%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbKubeletCrashLoopBackOffMax%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| KubeletEnsureSecretPulledImages | :ballot_box_with_check: 1.35+ | | 1.331.34 | 1.35 | | | | [code](https://cs.k8s.io/?q=%5CbKubeletEnsureSecretPulledImages%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbKubeletEnsureSecretPulledImages%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |

View file

@ -983,6 +983,12 @@
lockToDefault: true
preRelease: GA
version: "1.34"
- name: KubeProxyIPVS
versionedSpecs:
- default: true
lockToDefault: false
preRelease: GA
version: "1.11"
- name: ListFromCacheSnapshot
versionedSpecs:
- default: false