mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-05 07:27:21 +00:00
dual stack services (#91824)
* api: structure change * api: defaulting, conversion, and validation * [FIX] validation: auto remove second ip/family when service changes to SingleStack * [FIX] api: defaulting, conversion, and validation * api-server: clusterIPs alloc, printers, storage and strategy * [FIX] clusterIPs default on read * alloc: auto remove second ip/family when service changes to SingleStack * api-server: repair loop handling for clusterIPs * api-server: force kubernetes default service into single stack * api-server: tie dualstack feature flag with endpoint feature flag * controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service * [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service * kube-proxy: feature-flag, utils, proxier, and meta proxier * [FIX] kubeproxy: call both proxier at the same time * kubenet: remove forced pod IP sorting * kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy * e2e: fix tests that depends on IPFamily field AND add dual stack tests * e2e: fix expected error message for ClusterIP immutability * add integration tests for dualstack the third phase of dual stack is a very complex change in the API, basically it introduces Dual Stack services. Main changes are: - It pluralizes the Service IPFamily field to IPFamilies, and removes the singular field. - It introduces a new field IPFamilyPolicyType that can take 3 values to express the "dual-stack(mad)ness" of the cluster: SingleStack, PreferDualStack and RequireDualStack - It pluralizes ClusterIP to ClusterIPs. The goal is to add coverage to the services API operations, taking into account the 6 different modes a cluster can have: - single stack: IP4 or IPv6 (as of today) - dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4 * [FIX] add integration tests for dualstack * generated data * generated files Co-authored-by: Antonio Ojea <aojea@redhat.com>
This commit is contained in:
committed by
GitHub
parent
d0e06cf3e0
commit
6675eba3ef
@@ -27,7 +27,6 @@ import (
|
||||
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
utilnet "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
||||
@@ -137,32 +136,36 @@ func SetDefaults_Service(obj *v1.Service) {
|
||||
obj.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeCluster
|
||||
}
|
||||
|
||||
// if dualstack feature gate is on then we need to default
|
||||
// Spec.IPFamily correctly. This is to cover the case
|
||||
// when an existing cluster have been converted to dualstack
|
||||
// i.e. it already contain services with Spec.IPFamily==nil
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) &&
|
||||
obj.Spec.Type != v1.ServiceTypeExternalName &&
|
||||
obj.Spec.ClusterIP != "" && /*has an ip already set*/
|
||||
obj.Spec.ClusterIP != "None" && /* not converting from ExternalName to other */
|
||||
obj.Spec.IPFamily == nil /* family was not previously set */ {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) {
|
||||
// Default obj.Spec.IPFamilyPolicy if we *know* we can, otherwise it will
|
||||
// be handled later in allocation.
|
||||
if obj.Spec.Type != v1.ServiceTypeExternalName {
|
||||
if obj.Spec.IPFamilyPolicy == nil {
|
||||
if len(obj.Spec.ClusterIPs) == 2 || len(obj.Spec.IPFamilies) == 2 {
|
||||
requireDualStack := v1.IPFamilyPolicyRequireDualStack
|
||||
obj.Spec.IPFamilyPolicy = &requireDualStack
|
||||
}
|
||||
}
|
||||
|
||||
// there is a change that the ClusterIP (set by user) is unparsable.
|
||||
// in this case, the family will be set mistakenly to ipv4 (because
|
||||
// the util function does not parse errors *sigh*). The error
|
||||
// will be caught in validation which asserts the validity of the
|
||||
// IP and the service object will not be persisted with the wrong IP
|
||||
// family
|
||||
// If the user demanded dual-stack, but only specified one family, we add
|
||||
// the other.
|
||||
if obj.Spec.IPFamilyPolicy != nil && *(obj.Spec.IPFamilyPolicy) == v1.IPFamilyPolicyRequireDualStack && len(obj.Spec.IPFamilies) == 1 {
|
||||
if obj.Spec.IPFamilies[0] == v1.IPv4Protocol {
|
||||
obj.Spec.IPFamilies = append(obj.Spec.IPFamilies, v1.IPv6Protocol)
|
||||
} else {
|
||||
obj.Spec.IPFamilies = append(obj.Spec.IPFamilies, v1.IPv4Protocol)
|
||||
}
|
||||
|
||||
ipv6 := v1.IPv6Protocol
|
||||
ipv4 := v1.IPv4Protocol
|
||||
if utilnet.IsIPv6String(obj.Spec.ClusterIP) {
|
||||
obj.Spec.IPFamily = &ipv6
|
||||
} else {
|
||||
obj.Spec.IPFamily = &ipv4
|
||||
// Any other dual-stack defaulting depends on cluster configuration.
|
||||
// Further IPFamilies, IPFamilyPolicy defaulting is in ClusterIP alloc/reserve logic
|
||||
// NOTE: strategy handles cases where ClusterIPs is used (but not ClusterIP).
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// any other defaulting depends on cluster configuration.
|
||||
// further IPFamilies, IPFamilyPolicy defaulting is in ClusterIP alloc/reserve logic
|
||||
// note: conversion logic handles cases where ClusterIPs is used (but not ClusterIP).
|
||||
}
|
||||
}
|
||||
func SetDefaults_Pod(obj *v1.Pod) {
|
||||
// If limits are specified, but requests are not, default requests to limits
|
||||
|
||||
Reference in New Issue
Block a user