Merge pull request #137293 from adrianmoisey/adrian-kep-5707

KEP-5707: Deprecate Service.spec.externalIPs
This commit is contained in:
Kubernetes Prow Robot 2026-03-18 05:19:54 +05:30 committed by GitHub
commit 547b17cc13
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 42 additions and 1 deletions

View file

@ -57,6 +57,11 @@ func GetWarningsForService(service, oldService *api.Service) []string {
warnings = append(warnings, utilvalidation.GetWarningsForIP(field.NewPath("spec").Child("externalIPs").Index(i), externalIP)...)
}
// Warn about using externalIPs
if len(service.Spec.ExternalIPs) > 0 && !isHeadlessService(service) && service.Spec.Type != api.ServiceTypeExternalName { //nolint:staticcheck // SA1019 testing deprecated field
warnings = append(warnings, "spec.externalIPs is deprecated and may no longer be implemented in some clusters")
}
if len(service.Spec.LoadBalancerIP) > 0 {
warnings = append(warnings, utilvalidation.GetWarningsForIP(field.NewPath("spec").Child("loadBalancerIP"), service.Spec.LoadBalancerIP)...)
}

View file

@ -47,7 +47,7 @@ func TestGetWarningsForService(t *testing.T) {
name: "externalIPs set when type is ExternalName",
tweakSvc: func(s *api.Service) {
s.Spec.Type = api.ServiceTypeExternalName
s.Spec.ExternalIPs = []string{"1.2.3.4"}
s.Spec.ExternalIPs = []string{"1.2.3.4"} //nolint:staticcheck // SA1019 testing deprecated field
},
numWarnings: 1,
}, {
@ -115,6 +115,12 @@ func TestGetWarningsForService(t *testing.T) {
s.Spec.TrafficDistribution = ptr.To(api.ServiceTrafficDistributionPreferClose)
},
numWarnings: 1,
}, {
name: "ExternalIPs set on ClusterIP service",
tweakSvc: func(s *api.Service) {
s.Spec.ExternalIPs = []string{"1.2.3.4"} //nolint:staticcheck // SA1019 testing deprecated field
},
numWarnings: 1,
}}
for _, tc := range testCases {
@ -241,6 +247,7 @@ func TestGetWarningsForServiceClusterIPs(t *testing.T) {
`spec.clusterIPs[1]: non-standard IP address "192.012.2.2" is invalid: use "192.12.2.2"`,
`spec.externalIPs[0]: IPv6 address "2001:db8:1:0::2" should be in RFC 5952 canonical format ("2001:db8:1::2")`,
`spec.externalIPs[1]: non-standard IP address "10.012.2.2" is invalid: use "10.12.2.2"`,
`spec.externalIPs is deprecated and may no longer be implemented in some clusters`,
`spec.loadBalancerIP: non-standard IP address "10.001.1.1" is invalid: use "10.1.1.1"`,
`spec.loadBalancerSourceRanges[0]: IPv6 CIDR value "2001:db8:1:0::/64" should be in RFC 5952 canonical format ("2001:db8:1::/64")`,
`spec.loadBalancerSourceRanges[1]: non-standard CIDR value "10.012.2.0/24" is invalid: use "10.12.2.0/24"`,

View file

@ -5120,6 +5120,8 @@ type ServiceSpec struct {
// ExternalIPs are used by external load balancers, or can be set by
// users to handle external traffic that arrives at a node.
//
// Deprecated: ExternalIPs is deprecated and may be removed in a future version.
// +optional
ExternalIPs []string

View file

@ -56,6 +56,14 @@ const (
// Allow spec.terminationGracePeriodSeconds to be overridden by MaxPodGracePeriodSeconds in soft evictions.
AllowOverwriteTerminationGracePeriodSeconds featuregate.Feature = "AllowOverwriteTerminationGracePeriodSeconds"
// owner: @adrianmoisey
// kep: https://kep.k8s.io/5707
//
// When enabled, kube-proxy will program iptables/nftables/ipvs rules for Service.spec.externalIPs.
// When disabled, kube-proxy will not program rules for externalIPs, effectively disabling this
// deprecated feature.
AllowServiceExternalIPs featuregate.Feature = "AllowServiceExternalIPs"
// owner: @bswartz
//
// Enables usage of any object for volume data source in PVCs
@ -1173,6 +1181,10 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.35"), Default: false, PreRelease: featuregate.Deprecated, LockToDefault: true}, // remove in 1.38
},
AllowServiceExternalIPs: {
{Version: version.MustParse("1.0"), Default: true, PreRelease: featuregate.GA},
},
AnyVolumeDataSource: {
{Version: version.MustParse("1.18"), Default: false, PreRelease: featuregate.Alpha},
{Version: version.MustParse("1.24"), Default: true, PreRelease: featuregate.Beta},
@ -2255,6 +2267,8 @@ var defaultKubernetesFeatureGateDependencies = map[featuregate.Feature][]feature
AllowOverwriteTerminationGracePeriodSeconds: {},
AllowServiceExternalIPs: {},
AnyVolumeDataSource: {},
AuthorizeNodeWithSelectors: {genericfeatures.AuthorizeWithSelectors},

View file

@ -23,8 +23,10 @@ import (
"strings"
v1 "k8s.io/api/core/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/klog/v2"
apiservice "k8s.io/kubernetes/pkg/api/v1/service"
"k8s.io/kubernetes/pkg/features"
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
netutils "k8s.io/utils/net"
)
@ -136,6 +138,10 @@ func (bsvcPortInfo *BaseServicePortInfo) NodePort() int {
// ExternalIPs is part of ServicePort interface.
func (bsvcPortInfo *BaseServicePortInfo) ExternalIPs() []net.IP {
// Only program rules for externalIPs if the feature gate is enabled
if !utilfeature.DefaultFeatureGate.Enabled(features.AllowServiceExternalIPs) {
return []net.IP{}
}
return bsvcPortInfo.externalIPs
}

View file

@ -14,6 +14,7 @@
| AllowInsecureKubeletCertificateSigningRequests | :ballot_box_with_check: 1.0+ | | | | 1.01.30 | 1.31 | | [code](https://cs.k8s.io/?q=%5CbAllowInsecureKubeletCertificateSigningRequests%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAllowInsecureKubeletCertificateSigningRequests%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| AllowOverwriteTerminationGracePeriodSeconds | :ballot_box_with_check: 1.0+ | :closed_lock_with_key: 1.35+ | | | 1.01.31 | 1.32 | | [code](https://cs.k8s.io/?q=%5CbAllowOverwriteTerminationGracePeriodSeconds%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAllowOverwriteTerminationGracePeriodSeconds%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| AllowParsingUserUIDFromCertAuth | :ballot_box_with_check: 1.33+ | | | 1.33 | | | | [code](https://cs.k8s.io/?q=%5CbAllowParsingUserUIDFromCertAuth%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAllowParsingUserUIDFromCertAuth%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| AllowServiceExternalIPs | :ballot_box_with_check: 1.0+ | | | | 1.0 | | | [code](https://cs.k8s.io/?q=%5CbAllowServiceExternalIPs%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAllowServiceExternalIPs%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| AllowUnsafeMalformedObjectDeletion | | | 1.32 | | | | | [code](https://cs.k8s.io/?q=%5CbAllowUnsafeMalformedObjectDeletion%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAllowUnsafeMalformedObjectDeletion%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| AnonymousAuthConfigurableEndpoints | :ballot_box_with_check: 1.32+ | :closed_lock_with_key: 1.34+ | 1.31 | 1.321.33 | 1.34 | | | [code](https://cs.k8s.io/?q=%5CbAnonymousAuthConfigurableEndpoints%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAnonymousAuthConfigurableEndpoints%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| AnyVolumeDataSource | :ballot_box_with_check: 1.24+ | :closed_lock_with_key: 1.33+ | 1.181.23 | 1.241.32 | 1.33 | | | [code](https://cs.k8s.io/?q=%5CbAnyVolumeDataSource%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAnyVolumeDataSource%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |

View file

@ -55,6 +55,12 @@
lockToDefault: false
preRelease: Beta
version: "1.33"
- name: AllowServiceExternalIPs
versionedSpecs:
- default: true
lockToDefault: false
preRelease: GA
version: "1.0"
- name: AllowUnsafeMalformedObjectDeletion
versionedSpecs:
- default: false