Careful!
You are browsing documentation for the next version of Kuma. Use this version at your own risk.
MeshService
MeshService represents a destination for traffic within the mesh. It defines which data plane proxies serve traffic for a service, exposes ports, and tracks health status. Think of it as the Kuma equivalent of a Kubernetes Service.
Kuma automatically generates MeshService resources:
- Kubernetes: From
Serviceresources, reusing ClusterIPs and DNS names - Universal: From
Dataplaneinbounds withkuma.io/servicetags
For concepts, migration guidance, and usage patterns, see the MeshService guide.
Spec fields
| Field | Description |
|---|---|
selector |
Defines which data plane proxies belong to this service. Use either dataplaneTags or dataplaneRef. |
selector.dataplaneTags |
Match proxies by tags on their inbounds. All specified tags must match. |
selector.dataplaneRef.name |
Match a specific proxy by name. Used for headless services. |
ports |
List of ports exposed by this service. |
ports[].port |
Service port number (required). |
ports[].targetPort |
Port on the data plane proxy. Can be a number or inbound name. Defaults to port value. |
ports[].name |
Optional port name for referencing in policies via sectionName. |
ports[].appProtocol |
Protocol hint: tcp (default), http, http2, grpc. |
identities |
Service identities (auto-populated). Contains ServiceTag or SpiffeID entries. |
state |
Service availability: Available (healthy endpoints exist) or Unavailable. |
Examples
Basic MeshService
apiVersion: kuma.io/v1alpha1
kind: MeshService
metadata:
name: redis
namespace: kuma-demo
labels:
kuma.io/mesh: default
spec:
selector:
dataplaneTags:
app: redis
k8s.kuma.io/namespace: kuma-demo
ports:
- port: 6379
targetPort: 6379
appProtocol: tcp
MeshService with multiple ports
apiVersion: kuma.io/v1alpha1
kind: MeshService
metadata:
name: backend
namespace: app
labels:
kuma.io/mesh: default
spec:
selector:
dataplaneTags:
app: backend
k8s.kuma.io/namespace: app
ports:
- name: http
port: 80
targetPort: 8080
appProtocol: http
- name: grpc
port: 9000
targetPort: 9000
appProtocol: grpc
- name: metrics
port: 9090
targetPort: 9090
appProtocol: http
MeshService with named targetPort
Reference inbound ports by name instead of number:
apiVersion: kuma.io/v1alpha1
kind: MeshService
metadata:
name: api
namespace: app
labels:
kuma.io/mesh: default
spec:
selector:
dataplaneTags:
app: api
k8s.kuma.io/namespace: app
ports:
- name: main
port: 80
targetPort: http-port # references inbound name
appProtocol: http
MeshService for headless service (single pod)
Use dataplaneRef to target a specific proxy instance:
apiVersion: kuma.io/v1alpha1
kind: MeshService
metadata:
name: postgres-0
namespace: database
labels:
kuma.io/mesh: default
k8s.kuma.io/is-headless-service: "true"
spec:
selector:
dataplaneRef:
name: postgres-0 # specific pod name
ports:
- port: 5432
targetPort: 5432
appProtocol: tcp
MeshService with custom labels
Add labels for policy targeting and organization:
apiVersion: kuma.io/v1alpha1
kind: MeshService
metadata:
name: payment-service
namespace: payments
labels:
kuma.io/mesh: default
team: payments
tier: backend
pci-compliant: "true"
spec:
selector:
dataplaneTags:
app: payment-service
k8s.kuma.io/namespace: payments
ports:
- port: 443
targetPort: 8443
appProtocol: http2
Label propagation
In Universal zones, non-reserved Dataplane inbound tags and Dataplane resource labels are propagated into the generated MeshService’s metadata.labels. This lets you select generated MeshServices (for example with MeshMultiZoneService) by custom labels such as team or version without patching each MeshService manually. It does not apply to Kubernetes zones, where MeshServices are generated from Services.
For example, a Dataplane carrying a custom team label:
type: Dataplane
mesh: default
name: backend-1
labels:
team: payments
networking:
address: 10.0.0.1
inbound:
- port: 80
tags:
kuma.io/service: backend
produces a generated MeshService that carries the same label:
type: MeshService
name: backend
mesh: default
labels:
team: payments
spec:
selector:
dataplaneTags:
kuma.io/service: backend
This is opt-in. Enable it via the control plane configuration:
experimental:
meshServiceLabelPropagation:
enabled: true
allowedLabelKeys: [] # empty = propagate all non-reserved keys
Rules:
kuma.io/*andk8s.kuma.io/*keys are never propagated. The generator writes system labels (kuma.io/mesh,kuma.io/zone,kuma.io/origin,kuma.io/managed-by,kuma.io/display-name,kuma.io/env) itself, andDataplanetags or labels cannot override them.allowedLabelKeysrestricts propagation to an explicit set of keys. When empty, all non-reserved keys are propagated.- Keys and values must be valid Kubernetes label keys and values (63-character limit, restricted character set). Invalid entries are skipped and logged. They do not fail
Dataplanevalidation. - Label removal propagates: removing a tag or label from the backing
Dataplanesremoves it from the generatedMeshService. Removal only takes effect once the lastDataplanecarrying the value is gone.
Conflict resolution
When the Dataplanes backing one MeshService disagree on the value of a non-reserved key:
- Within a single
Dataplane(its inbounds disagree on a tag): the generator drops the key, logs a warning, and incrementscomponent_meshservice_generator_dropped_labels_total. Disagreement between inbounds on the sameDataplaneis a configuration error. - Across different
Dataplanes: per-key majority wins. - Ties: the newest
Dataplanewins by creation time. On identical timestamps, the lexicographically smallest value wins.
With only two backing Dataplanes, every key conflict is a tie, so the propagated value tracks whichever Dataplane was created most recently and can flip when a Dataplane is replaced. During a rolling deploy the value switches at the ~50% crossover point. If you use these labels as MeshMultiZoneService selectors, update the selectors in lockstep, or give workloads that must be routed separately distinct kuma.io/service values so they generate separate MeshServices.
Targeting MeshService in policies
In policy targetRef
Target a specific port using sectionName:
spec:
to:
- targetRef:
kind: MeshService
name: backend
namespace: app # Kubernetes only
sectionName: http # port name
In route backendRefs
Direct traffic to a MeshService:
spec:
to:
- targetRef:
kind: MeshService
name: frontend
namespace: app
rules:
- default:
backendRefs:
- kind: MeshService
name: backend
namespace: app
port: 80
Using labels for cross-zone targeting
Select MeshServices across zones:
spec:
to:
- targetRef:
kind: MeshService
labels:
kuma.io/display-name: backend
kuma.io/zone: east
Naming constraints
MeshService names must:
- Be 63 characters or fewer
- Conform to DNS-1035 (lowercase alphanumeric, hyphens allowed, cannot start/end with hyphen)
See also
- MeshService guide - concepts and migration
- MeshMultiZoneService - aggregate services across zones
- HostnameGenerator - DNS hostname generation
- Service discovery - how proxies discover services
- MeshHTTPRoute - HTTP traffic routing
- MeshTCPRoute - TCP traffic routing