Skip to main content
This guide explains how to expose Kubernetes Services across clusters using Cilium’s Cluster Mesh and Global Services. It covers default behavior, how to enable a global service, per-cluster sharing control, affinity options, and practical examples. Overview
  • By default, a Kubernetes Service load-balances only to endpoints (Pods) in the same cluster.
  • Cilium Cluster Mesh can expose Services across clusters. Enabling a global service allows cross-cluster load balancing and failover.
  • To create a global service, deploy identical Service resources (same name, namespace, and ports) in each cluster where the Service should be reachable, and add the global annotation to enable cross-cluster behavior.
Ensure the Service resource (name, namespace, ports) is identical on each cluster. Only the annotations differ when you want to control sharing or affinity per-cluster.

How global services work (high level)

  • Each cluster advertises Services via Cluster Mesh when the Service is marked global.
  • A Service is considered global only when the same Service (name + namespace + ports) exists across clusters and is annotated appropriately.
  • Clients in any cluster can be load-balanced across local and remote endpoints depending on sharing and affinity configuration.
  • If local endpoints disappear, traffic will fail over to available remote endpoints that advertise the Service.

Default behavior (no global service)

When a frontend Pod in cluster A sends traffic to a Service that is not global, the Service routes only to endpoints in cluster A. There is no cross-cluster load balancing by default.

Enable a global service

To enable cross-cluster load balancing, create the same Service in every cluster where the Service should be reachable and add the global annotation:
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: default
  annotations:
    service.cilium.io/global: "true"
spec:
  type: LoadBalancer
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 80
Behavior:
  • Once the Service exists with service.cilium.io/global: "true" across the clusters, the Service becomes global.
  • A frontend Pod in cluster A will have its traffic load-balanced across back-end Pods in both local and remote clusters.
  • If all local endpoints are unavailable, traffic automatically fails over to remote endpoints advertising the Service.

Per-cluster sharing control (service.cilium.io/shared)

You can control whether a cluster advertises its endpoints to other clusters by setting the service.cilium.io/shared annotation on the local Service. Cluster A (do not advertise endpoints to other clusters):
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: default
  annotations:
    service.cilium.io/global: "true"
    service.cilium.io/shared: "false"
spec:
  type: LoadBalancer
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 80
Cluster B (advertise by default - omit shared or set to “true”):
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: default
  annotations:
    service.cilium.io/global: "true"
spec:
  type: LoadBalancer
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 80
Behavior:
  • Frontend Pods in cluster A will still observe endpoints from all clusters because cluster A has a local Service marked global (even if cluster A does not share its endpoints).
  • Frontend Pods in cluster B will see only endpoints advertised by clusters that set shared: "true" (or omitted the annotation). If cluster A set shared: "false", B will not see cluster A’s endpoints.

Affinity: bias load-balancing to local or remote endpoints

Use service.cilium.io/affinity to prefer local or remote endpoints. Preference is soft: traffic fails over if preferred endpoints are unavailable. Affinity: local (prefer local endpoints, fallback to remote)
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: default
  annotations:
    service.cilium.io/global: "true"
    service.cilium.io/affinity: "local"
spec:
  type: LoadBalancer
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 80
Behavior:
  • The Service prefers local endpoints for lower latency.
  • If no local endpoints are available, traffic will fail over to remote endpoints advertising the Service.
Affinity: remote (prefer remote endpoints, fallback to local)
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: default
  annotations:
    service.cilium.io/global: "true"
    service.cilium.io/affinity: "remote"
spec:
  type: LoadBalancer
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 80
Behavior:
  • The Service prefers remote endpoints.
  • If remote endpoints are unavailable, traffic falls back to local endpoints.

Annotations quick reference

AnnotationPurposeExample value
service.cilium.io/globalMark Service as global and advertise it via Cluster Mesh”true”
service.cilium.io/sharedControl whether this cluster advertises its endpoints to other clusters”true” / “false”
service.cilium.io/affinityBias load-balancing to local or remote endpoints”local” / “remote”

Practical notes and troubleshooting

  • Ensure the Service name, namespace, and ports are identical across clusters; mismatched Service specs prevent global behavior.
  • Use kubectl get svc -n <ns> -o yaml on each cluster to confirm annotations and spec parity.
  • If a cluster’s Service is global but marked shared: "false", that cluster will consume remote endpoints but will not advertise its own endpoints to others.
Test global services using simple client Pods in each cluster. Verify endpoint lists and traffic flows with kubectl describe svc and by curling the Service from a test Pod to observe cross-cluster responses.

Summary

  • Default: Services route only to endpoints in the same cluster.
  • To enable cross-cluster load balancing, add service.cilium.io/global: "true" to the identical Service on each cluster that should participate.
  • Control advertising of endpoints with service.cilium.io/shared: "false".
  • Bias traffic toward local or remote endpoints using service.cilium.io/affinity: "local" or "remote", with automatic fallback when preferred endpoints are unavailable.
Links and references

Watch Video