Skip to content

Commit

Permalink
Add new field trafficDistribution to Service spec
Browse files Browse the repository at this point in the history
  • Loading branch information
gauravkghildiyal committed Mar 4, 2024
1 parent 8c80c07 commit 996d11d
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 1 deletion.
21 changes: 21 additions & 0 deletions pkg/apis/core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4163,6 +4163,18 @@ const (
ServiceExternalTrafficPolicyLocal ServiceExternalTrafficPolicy = "Local"
)

// These are valid values for the TrafficDistribution field of a Service.
const (
// Indicates a preference for routing traffic to endpoints that are
// topologically proximate to the client. The interpretation of "topologically
// proximate" may vary across implementations and could encompass endpoints
// within the same node, rack, zone, or even region. Setting this value gives
// implementations permission to make different tradeoffs, e.g. optimizing for
// proximity rather than equal distribution of load. Users should not set this
// value if such tradeoffs are not acceptable.
ServiceTrafficDistributionPreferClose = "PreferClose"
)

// These are the valid conditions of a service.
const (
// LoadBalancerPortsError represents the condition of the requested ports
Expand Down Expand Up @@ -4426,6 +4438,15 @@ type ServiceSpec struct {
// (possibly modified by topology and other features).
// +optional
InternalTrafficPolicy *ServiceInternalTrafficPolicy

// TrafficDistribution offers a way to express preferences for how traffic is
// distributed to Service endpoints. Implementations can use this field as a
// hint, but are not required to guarantee strict adherence. If the field is
// not set, the implementation will apply its default routing strategy. If set
// to "PreferClose", implementations should prioritize endpoints that are
// topologically close (e.g., same zone).
// +optional
TrafficDistribution *string
}

// ServicePort represents the port on which the service is exposed
Expand Down
19 changes: 19 additions & 0 deletions pkg/apis/core/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -5494,6 +5494,9 @@ func ValidateService(service *core.Service) field.ErrorList {
// internal traffic policy field
allErrs = append(allErrs, validateServiceInternalTrafficFieldsValue(service)...)

// traffic distribution field
allErrs = append(allErrs, validateServiceTrafficDistribution(service)...)

return allErrs
}

Expand Down Expand Up @@ -5611,6 +5614,22 @@ func validateServiceInternalTrafficFieldsValue(service *core.Service) field.Erro
return allErrs
}

// validateServiceTrafficDistribution validates the values for the
// trafficDistribution field.
func validateServiceTrafficDistribution(service *core.Service) field.ErrorList {
allErrs := field.ErrorList{}

if service.Spec.TrafficDistribution == nil {
return allErrs
}

if *service.Spec.TrafficDistribution != v1.ServiceTrafficDistributionPreferClose {
allErrs = append(allErrs, field.NotSupported(field.NewPath("spec").Child("trafficDistribution"), *service.Spec.TrafficDistribution, []string{v1.ServiceTrafficDistributionPreferClose}))
}

return allErrs
}

// ValidateServiceCreate validates Services as they are created.
func ValidateServiceCreate(service *core.Service) field.ErrorList {
return ValidateService(service)
Expand Down
12 changes: 12 additions & 0 deletions pkg/apis/core/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16740,6 +16740,18 @@ func TestValidateServiceCreate(t *testing.T) {
s.Annotations[core.AnnotationTopologyMode] = "different"
},
numErrs: 1,
}, {
name: "valid: trafficDistribution field set to PreferClose",
tweakSvc: func(s *core.Service) {
s.Spec.TrafficDistribution = utilpointer.String("PreferClose")
},
numErrs: 0,
}, {
name: "invalid: trafficDistribution field set to Random",
tweakSvc: func(s *core.Service) {
s.Spec.TrafficDistribution = utilpointer.String("Random")
},
numErrs: 1,
},
}

Expand Down
9 changes: 9 additions & 0 deletions pkg/features/kube_features.go
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,13 @@ const (
// Subdivide the NodePort range for dynamic and static port allocation.
ServiceNodePortStaticSubrange featuregate.Feature = "ServiceNodePortStaticSubrange"

// owner: @gauravkghildiyal @robscott
// kep: https://kep.k8s.io/4444
// alpha: v1.30
//
// Enables trafficDistribution field on Services.
ServiceTrafficDistribution featuregate.Feature = "ServiceTrafficDistribution"

// owner: @gjkim42 @SergeyKanzhelev @matthyx @tzneal
// kep: http://kep.k8s.io/753
// alpha: v1.28
Expand Down Expand Up @@ -1128,6 +1135,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS

ServiceNodePortStaticSubrange: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.29; remove in 1.31

ServiceTrafficDistribution: {Default: false, PreRelease: featuregate.Alpha},

SidecarContainers: {Default: true, PreRelease: featuregate.Beta},

SizeMemoryBackedVolumes: {Default: true, PreRelease: featuregate.Beta},
Expand Down
6 changes: 5 additions & 1 deletion pkg/registry/core/service/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,11 @@ func (svcStrategy) AllowUnconditionalUpdate() bool {
// newSvc.Spec.MyFeature = nil
// }
func dropServiceDisabledFields(newSvc *api.Service, oldSvc *api.Service) {

// Drop condition for TrafficDistribution field.
isTrafficDistributionInUse := (oldSvc != nil && oldSvc.Spec.TrafficDistribution != nil)
if !utilfeature.DefaultFeatureGate.Enabled(features.ServiceTrafficDistribution) && !isTrafficDistributionInUse {
newSvc.Spec.TrafficDistribution = nil
}
}

type serviceStatusStrategy struct {
Expand Down
21 changes: 21 additions & 0 deletions staging/src/k8s.io/api/core/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4908,6 +4908,18 @@ const (
ServiceExternalTrafficPolicyTypeCluster = ServiceExternalTrafficPolicyCluster
)

// These are valid values for the TrafficDistribution field of a Service.
const (
// Indicates a preference for routing traffic to endpoints that are
// topologically proximate to the client. The interpretation of "topologically
// proximate" may vary across implementations and could encompass endpoints
// within the same node, rack, zone, or even region. Setting this value gives
// implementations permission to make different tradeoffs, e.g. optimizing for
// proximity rather than equal distribution of load. Users should not set this
// value if such tradeoffs are not acceptable.
ServiceTrafficDistributionPreferClose = "PreferClose"
)

// These are the valid conditions of a service.
const (
// LoadBalancerPortsError represents the condition of the requested ports
Expand Down Expand Up @@ -5252,6 +5264,15 @@ type ServiceSpec struct {
// (possibly modified by topology and other features).
// +optional
InternalTrafficPolicy *ServiceInternalTrafficPolicy `json:"internalTrafficPolicy,omitempty" protobuf:"bytes,22,opt,name=internalTrafficPolicy"`

// TrafficDistribution offers a way to express preferences for how traffic is
// distributed to Service endpoints. Implementations can use this field as a
// hint, but are not required to guarantee strict adherence. If the field is
// not set, the implementation will apply its default routing strategy. If set
// to "PreferClose", implementations should prioritize endpoints that are
// topologically close (e.g., same zone).
// +optional
TrafficDistribution *string `json:"trafficDistribution,omitempty" protobuf:"bytes,23,opt,name=trafficDistribution"`
}

// ServicePort contains information on service's port.
Expand Down

0 comments on commit 996d11d

Please sign in to comment.