Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/crd-base/multicluster.x-k8s.io_serviceexports.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ metadata:
# The revision is updated on each CRD change and reset back to 0 on every new version.
# It can be used together with the version label when installing those CRDs
# and prevent any downgrades.
multicluster.x-k8s.io/crd-schema-revision: "0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

multicluster.x-k8s.io/crd-schema-revision: "1"
spec:
group: multicluster.x-k8s.io
scope: Namespaced
Expand Down
2 changes: 1 addition & 1 deletion config/crd-base/multicluster.x-k8s.io_serviceimports.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ metadata:
# The revision is updated on each CRD change and reset back to 0 on every new version.
# It can be used together with the version label when installing those CRDs
# and prevent any downgrades.
multicluster.x-k8s.io/crd-schema-revision: "0"
multicluster.x-k8s.io/crd-schema-revision: "1"
spec:
group: multicluster.x-k8s.io
scope: Namespaced
Expand Down
2 changes: 1 addition & 1 deletion config/crd/multicluster.x-k8s.io_serviceexports.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ metadata:
# The revision is updated on each CRD change and reset back to 0 on every new version.
# It can be used together with the version label when installing those CRDs
# and prevent any downgrades.
multicluster.x-k8s.io/crd-schema-revision: "0"
multicluster.x-k8s.io/crd-schema-revision: "1"
spec:
group: multicluster.x-k8s.io
scope: Namespaced
Expand Down
20 changes: 19 additions & 1 deletion config/crd/multicluster.x-k8s.io_serviceimports.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ metadata:
# The revision is updated on each CRD change and reset back to 0 on every new version.
# It can be used together with the version label when installing those CRDs
# and prevent any downgrades.
multicluster.x-k8s.io/crd-schema-revision: "0"
multicluster.x-k8s.io/crd-schema-revision: "1"
spec:
group: multicluster.x-k8s.io
scope: Namespaced
Expand Down Expand Up @@ -78,6 +78,15 @@ spec:
- ports
- type
properties:
internalTrafficPolicy:
description: |-
InternalTrafficPolicy describes how nodes distribute service traffic they
receive on the ClusterIP. If set to "Local", the proxy will assume that pods
only want to talk to endpoints of the service on the same node as the pod,
dropping the traffic if there are no local endpoints. The default value,
"Cluster", uses the standard behavior of routing to all endpoints evenly
(possibly modified by topology and other features).
type: string
ipFamilies:
description: IPFamilies identifies all the IPFamilies assigned for this ServiceImport.
type: array
Expand Down Expand Up @@ -160,6 +169,15 @@ spec:
Default value is 10800(for 3 hours).
type: integer
format: int32
trafficDistribution:
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 in the same zone.
type: string
type:
description: |-
type defines the type of this service.
Expand Down
33 changes: 33 additions & 0 deletions conformance/service_import.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
"sigs.k8s.io/mcs-api/pkg/apis/v1alpha1"
)

Expand Down Expand Up @@ -179,6 +180,38 @@ func testClusterIPServiceImport() {
})
})

Context("", func() {
BeforeEach(func() {
t.helloService.Spec.InternalTrafficPolicy = ptr.To(corev1.ServiceInternalTrafficPolicyCluster)
})
Specify("The InternalTrafficPolicy for a ClusterSetIP ServiceImport should match the exported service's InternalTrafficPolicy",
Label(RequiredLabel), func() {
AddReportEntry(SpecRefReportEntry, "https://github.com/kubernetes/enhancements/tree/master/keps/sig-multicluster/1645-multi-cluster-services-api#internal-traffic-policy")

t.awaitServiceImport(&clients[0], helloServiceName, false, func(g Gomega, serviceImport *v1alpha1.ServiceImport) {
g.Expect(serviceImport.Spec.InternalTrafficPolicy).To(Equal(t.helloService.Spec.InternalTrafficPolicy), reportNonConformant(
"The InternalTrafficPolicy of the ServiceImport does not match the exported Service's InternalTrafficPolicy"))
})
},
)
})

Context("", func() {
BeforeEach(func() {
t.helloService.Spec.TrafficDistribution = ptr.To(corev1.ServiceTrafficDistributionPreferClose)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a heads up, this API is in a bit of flux for Service, see KEP-3015 and kubernetes/kubernetes#130844

Copy link
Member Author

@MrFreezeex MrFreezeex Oct 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fine no? It's already graduating to stable in kube 1.35 and was already beta/enabled by default in kube 1.34.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is graduating, but also being replaced by PreferSameZone and PreferSameNode is being added for more explicit semantics.

})
Specify("The TrafficDistribution for a ClusterSetIP ServiceImport should match the exported service's TrafficDistribution",
Label(RequiredLabel), func() {
AddReportEntry(SpecRefReportEntry, "https://github.com/kubernetes/enhancements/tree/master/keps/sig-multicluster/1645-multi-cluster-services-api#traffic-distribution")

t.awaitServiceImport(&clients[0], helloServiceName, false, func(g Gomega, serviceImport *v1alpha1.ServiceImport) {
g.Expect(serviceImport.Spec.TrafficDistribution).To(Equal(t.helloService.Spec.TrafficDistribution), reportNonConformant(
"The TrafficDistribution of the ServiceImport does not match the exported Service's TrafficDistribution"))
})
},
)
})

Specify("An IP should be allocated for a ClusterSetIP ServiceImport", Label(RequiredLabel), func() {
AddReportEntry(SpecRefReportEntry, "https://github.com/kubernetes/enhancements/tree/master/keps/sig-multicluster/1645-multi-cluster-services-api#clustersetip")

Expand Down
2 changes: 1 addition & 1 deletion hack/verify-crd-bump-revision.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ BASE_REF="${PULL_BASE_SHA:-master}"
crd_changed="$(git diff --name-only "${BASE_REF}" | grep -c "^config/crd/.*\.yaml$")"
version_label_changed="$(git diff -U0 "${BASE_REF}" -- "config/crd-base/" | grep -c "multicluster.x-k8s.io/crd-schema-revision")"

if [ "${crd_changed}" -gt 0 ] && [ "${version_label_changed}" -ne 2 ]; then
if [ "${crd_changed}" -gt 0 ] && [ "${version_label_changed}" -ne 4 ]; then
echo "❌ CRDs were modified, but the CRD revision labels were not changed in 'config/crd-base/'. Please bump the CRDs revision."
exit 1
fi
8 changes: 8 additions & 0 deletions pkg/apis/v1alpha1/serviceexport.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,14 @@ const (
// annotations.
ServiceExportReasonAnnotationsConflict ServiceExportConditionReason = "AnnotationsConflict"

// ServiceExportReasonInternalTrafficPolicyConflict is used with the "Conflict"
// condition when the exported service has a conflict related to internal traffic policy.
ServiceExportReasonInternalTrafficPolicyConflict ServiceExportConditionReason = "InternalTrafficPolicyConflict"

// ServiceExportReasonTrafficDistributionConflict is used with the "Conflict"
// condition when the exported service has a conflict related to traffic distribution.
ServiceExportReasonTrafficDistributionConflict ServiceExportConditionReason = "TrafficDistributionConflict"

// ServiceExportReasonNoConflicts is used with the "Conflict" condition
// when the condition is False.
ServiceExportReasonNoConflicts ServiceExportConditionReason = "NoConflicts"
Expand Down
18 changes: 18 additions & 0 deletions pkg/apis/v1alpha1/serviceimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,24 @@ type ServiceImportSpec struct {
// +kubebuilder:validation:MaxItems:=2
// +optional
IPFamilies []v1.IPFamily `json:"ipFamilies,omitempty"`

// InternalTrafficPolicy describes how nodes distribute service traffic they
// receive on the ClusterIP. If set to "Local", the proxy will assume that pods
// only want to talk to endpoints of the service on the same node as the pod,
// dropping the traffic if there are no local endpoints. The default value,
// "Cluster", uses the standard behavior of routing to all endpoints evenly
// (possibly modified by topology and other features).
// +optional
InternalTrafficPolicy *v1.ServiceInternalTrafficPolicy `json:"internalTrafficPolicy,omitempty"`

// 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 in the same zone.
// +optional
TrafficDistribution *string `json:"trafficDistribution,omitempty"`
}

// ServicePort represents the port on which the service is exposed
Expand Down
10 changes: 10 additions & 0 deletions pkg/apis/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.