EndpointSlice sync does not translate kubernetes.io/service-name for custom-managed EndpointSlices
What happened?
With vCluster 0.33.1, some EndpointSlices synced from the virtual cluster to the host cluster keep the virtual Service name in the kubernetes.io/service-name label instead of using the translated host-side Service name.
This causes the synced EndpointSlice to no longer be associated with its corresponding host-side Service.
The issue was initially detected with MariaDB Operator *-secondary Services.
For example, inside the virtual cluster the Service is:
Namespace: example-prod
Service: example-db-secondaryvCluster correctly translates the Service on the host cluster to:
Namespace: example
Service: example-db-secondary-x-example-prod-x-vcluster
ClusterIP: 10.15.108.114The corresponding EndpointSlice is also synced to the host with the translated resource name:
example-db-secondary-x-example-prod-x-vclusterHowever, the EndpointSlice contains:
kubernetes.io/service-name=example-db-secondaryinstead of:
kubernetes.io/service-name=example-db-secondary-x-example-prod-x-vclusterExample host-side EndpointSlice:
Name: example-db-secondary-x-example-prod-x-vcluster
Namespace: example
Labels:
endpointslice.kubernetes.io/managed-by=mariadb-operator.k8s.mariadb.com
kubernetes.io/service-name=example-db-secondary
vcluster.loft.sh/managed-by=vcluster
vcluster.loft.sh/namespace=example-prod
Annotations:
vcluster.loft.sh/object-host-name: example-db-secondary-x-example-prod-x-vcluster
vcluster.loft.sh/object-host-namespace: example
vcluster.loft.sh/object-kind: discovery.k8s.io/v1, Kind=EndpointSlice
vcluster.loft.sh/object-name: example-db-secondary
vcluster.loft.sh/object-namespace: example-prod
AddressType: IPv4
Ports:
mariadb 3306/TCP
Endpoints:
10.15.104.41 Ready=true Pod/example-db-1-x-example-prod-x-vcluster
10.15.107.9 Ready=true Pod/example-db-0-x-example-prod-x-vclusterNotice that other references, including the EndpointSlice name and Pod targetRefs, are translated correctly. Only the kubernetes.io/service-name label remains the virtual Service name.
Because of this:
kubectl -n example get endpointslice \
-l kubernetes.io/service-name=example-db-secondary-x-example-prod-x-vclusterreturns no EndpointSlices.
Impact
The host cluster uses Cilium with kube-proxy replacement.
Because Cilium cannot associate the EndpointSlice with the translated host Service, the ClusterIP is not installed in the Cilium service/LB maps.
For example:
cilium-dbg service list | grep 10.15.108.114returned nothing on freshly started Cilium agents.
Direct connectivity to both endpoint Pod IPs worked, so the backend networking itself was healthy.
After manually fixing the EndpointSlice label:
kubectl -n example label endpointslice \
example-db-secondary-x-example-prod-x-vcluster \
kubernetes.io/service-name=example-db-secondary-x-example-prod-x-vcluster \
--overwriteCilium immediately created the Service on multiple nodes without any restart:
10.15.108.114:3306/TCP ClusterIP
1 => 10.15.104.41:3306/TCP (active)
2 => 10.15.107.9:3306/TCP (active)This demonstrates that the only required change was correcting the kubernetes.io/service-name label.
The inspected broken EndpointSlice is managed by:
endpointslice.kubernetes.io/managed-by=mariadb-operator.k8s.mariadb.comThis suggests the problem may specifically affect EndpointSlices created by an external/custom controller rather than EndpointSlices generated by Kubernetes' normal Service EndpointSlice controller.
What did you expect to happen?
When vCluster translates a Service from:
example-prod/example-db-secondaryto:
example/example-db-secondary-x-example-prod-x-vclusterthe corresponding EndpointSlice should also be translated from:
metadata:
labels:
kubernetes.io/service-name: example-db-secondaryto:
metadata:
labels:
kubernetes.io/service-name: example-db-secondary-x-example-prod-x-vclusterThe label should reference the actual translated Service name in the host cluster.
How can we reproduce it (as minimally and precisely as possible)?
Install vCluster 0.33.1.
Enable Service and EndpointSlice syncing:
sync:
toHost:
endpointSlices:
enabled: true
endpoints:
enabled: true
services:
enabled: true- Inside the vCluster, create/use a controller that manages an EndpointSlice directly. In our case this is MariaDB Operator and its secondary Service.
Example virtual Service:
example-prod/example-db-secondary- Check the translated Service on the host:
kubectl -n example get svc \
example-db-secondary-x-example-prod-x-vcluster- Check the translated EndpointSlice:
kubectl -n example describe endpointslice \
example-db-secondary-x-example-prod-x-vcluster- Observe that the resource name is translated but the Service reference is not:
EndpointSlice name:
example-db-secondary-x-example-prod-x-vcluster
kubernetes.io/service-name:
example-db-secondary- Manually change the label to the translated Service name:
kubectl -n example label endpointslice \
example-db-secondary-x-example-prod-x-vcluster \
kubernetes.io/service-name=example-db-secondary-x-example-prod-x-vcluster \
--overwriteThe EndpointSlice is then correctly associated with the host Service and downstream Service consumers immediately see the correct backends.
Anything else we need to know?
https://github.com/mariadb-operator/mariadb-operatorMariaDB operator version: 25.10.2
Host cluster Kubernetes version
$ kubectl version
Client Version: v1.33.7
Kustomize Version: v5.6.0
Server Version: v1.33.7vcluster version
Installed with helm, running 0.33.1.
VCluster Config
sync:
toHost:
endpointSlices:
enabled: true
endpoints:
enabled: true
services:
enabled: true
namespaces:
enabled: false
mappingsOnly: falseSource: loft-sh/vcluster