Skip to content

Commit a76a3e0

Browse files
authored
Merge pull request kubernetes#123487 from gauravkghildiyal/kep-4444
Introduce trafficDistribution field for Kubernetes Services
2 parents 229ebab + ec6fd2b commit a76a3e0

30 files changed

+2310
-1024
lines changed

api/openapi-spec/swagger.json

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/openapi-spec/v3/api__v1_openapi.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7447,6 +7447,10 @@
74477447
],
74487448
"description": "sessionAffinityConfig contains the configurations of session affinity."
74497449
},
7450+
"trafficDistribution": {
7451+
"description": "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).",
7452+
"type": "string"
7453+
},
74507454
"type": {
74517455
"description": "type determines how the Service is exposed. Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, NodePort, and LoadBalancer. \"ClusterIP\" allocates a cluster-internal IP address for load-balancing to endpoints. Endpoints are determined by the selector or if that is not specified, by manual construction of an Endpoints object or EndpointSlice objects. If clusterIP is \"None\", no virtual IP is allocated and the endpoints are published as a set of endpoints rather than a virtual IP. \"NodePort\" builds on ClusterIP and allocates a port on every node which routes to the same endpoints as the clusterIP. \"LoadBalancer\" builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the same endpoints as the clusterIP. \"ExternalName\" aliases this service to the specified externalName. Several other fields do not apply to ExternalName services. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types",
74527456
"type": "string"

pkg/apis/core/types.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4163,6 +4163,18 @@ const (
41634163
ServiceExternalTrafficPolicyLocal ServiceExternalTrafficPolicy = "Local"
41644164
)
41654165

4166+
// These are valid values for the TrafficDistribution field of a Service.
4167+
const (
4168+
// Indicates a preference for routing traffic to endpoints that are
4169+
// topologically proximate to the client. The interpretation of "topologically
4170+
// proximate" may vary across implementations and could encompass endpoints
4171+
// within the same node, rack, zone, or even region. Setting this value gives
4172+
// implementations permission to make different tradeoffs, e.g. optimizing for
4173+
// proximity rather than equal distribution of load. Users should not set this
4174+
// value if such tradeoffs are not acceptable.
4175+
ServiceTrafficDistributionPreferClose = "PreferClose"
4176+
)
4177+
41664178
// These are the valid conditions of a service.
41674179
const (
41684180
// LoadBalancerPortsError represents the condition of the requested ports
@@ -4426,6 +4438,15 @@ type ServiceSpec struct {
44264438
// (possibly modified by topology and other features).
44274439
// +optional
44284440
InternalTrafficPolicy *ServiceInternalTrafficPolicy
4441+
4442+
// TrafficDistribution offers a way to express preferences for how traffic is
4443+
// distributed to Service endpoints. Implementations can use this field as a
4444+
// hint, but are not required to guarantee strict adherence. If the field is
4445+
// not set, the implementation will apply its default routing strategy. If set
4446+
// to "PreferClose", implementations should prioritize endpoints that are
4447+
// topologically close (e.g., same zone).
4448+
// +optional
4449+
TrafficDistribution *string
44294450
}
44304451

44314452
// ServicePort represents the port on which the service is exposed

pkg/apis/core/v1/zz_generated.conversion.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/core/validation/validation.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5534,6 +5534,9 @@ func ValidateService(service *core.Service) field.ErrorList {
55345534
// internal traffic policy field
55355535
allErrs = append(allErrs, validateServiceInternalTrafficFieldsValue(service)...)
55365536

5537+
// traffic distribution field
5538+
allErrs = append(allErrs, validateServiceTrafficDistribution(service)...)
5539+
55375540
return allErrs
55385541
}
55395542

@@ -5651,6 +5654,22 @@ func validateServiceInternalTrafficFieldsValue(service *core.Service) field.Erro
56515654
return allErrs
56525655
}
56535656

5657+
// validateServiceTrafficDistribution validates the values for the
5658+
// trafficDistribution field.
5659+
func validateServiceTrafficDistribution(service *core.Service) field.ErrorList {
5660+
allErrs := field.ErrorList{}
5661+
5662+
if service.Spec.TrafficDistribution == nil {
5663+
return allErrs
5664+
}
5665+
5666+
if *service.Spec.TrafficDistribution != v1.ServiceTrafficDistributionPreferClose {
5667+
allErrs = append(allErrs, field.NotSupported(field.NewPath("spec").Child("trafficDistribution"), *service.Spec.TrafficDistribution, []string{v1.ServiceTrafficDistributionPreferClose}))
5668+
}
5669+
5670+
return allErrs
5671+
}
5672+
56545673
// ValidateServiceCreate validates Services as they are created.
56555674
func ValidateServiceCreate(service *core.Service) field.ErrorList {
56565675
return ValidateService(service)

pkg/apis/core/validation/validation_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17121,6 +17121,18 @@ func TestValidateServiceCreate(t *testing.T) {
1712117121
s.Annotations[core.AnnotationTopologyMode] = "different"
1712217122
},
1712317123
numErrs: 1,
17124+
}, {
17125+
name: "valid: trafficDistribution field set to PreferClose",
17126+
tweakSvc: func(s *core.Service) {
17127+
s.Spec.TrafficDistribution = utilpointer.String("PreferClose")
17128+
},
17129+
numErrs: 0,
17130+
}, {
17131+
name: "invalid: trafficDistribution field set to Random",
17132+
tweakSvc: func(s *core.Service) {
17133+
s.Spec.TrafficDistribution = utilpointer.String("Random")
17134+
},
17135+
numErrs: 1,
1712417136
},
1712517137
}
1712617138

pkg/apis/core/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/controller/endpointslice/endpointslice_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ func NewController(ctx context.Context, podInformer coreinformers.PodInformer,
175175
c.topologyCache,
176176
c.eventRecorder,
177177
controllerName,
178+
endpointslicerec.WithTrafficDistributionEnabled(utilfeature.DefaultFeatureGate.Enabled(features.ServiceTrafficDistribution)),
178179
)
179180

180181
return c

pkg/features/kube_features.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,13 @@ const (
738738
// Subdivide the NodePort range for dynamic and static port allocation.
739739
ServiceNodePortStaticSubrange featuregate.Feature = "ServiceNodePortStaticSubrange"
740740

741+
// owner: @gauravkghildiyal @robscott
742+
// kep: https://kep.k8s.io/4444
743+
// alpha: v1.30
744+
//
745+
// Enables trafficDistribution field on Services.
746+
ServiceTrafficDistribution featuregate.Feature = "ServiceTrafficDistribution"
747+
741748
// owner: @gjkim42 @SergeyKanzhelev @matthyx @tzneal
742749
// kep: http://kep.k8s.io/753
743750
// alpha: v1.28
@@ -1139,6 +1146,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
11391146

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

1149+
ServiceTrafficDistribution: {Default: false, PreRelease: featuregate.Alpha},
1150+
11421151
SidecarContainers: {Default: true, PreRelease: featuregate.Beta},
11431152

11441153
SizeMemoryBackedVolumes: {Default: true, PreRelease: featuregate.Beta},

pkg/generated/openapi/zz_generated.openapi.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)