✦ For everyone, free.

Practical knowledge for real and everyday life

Home

Kubernetes Service Spec Structure

Kubernetes Service Spec Structure defines how services are created and managed, specifying type, selector, and port mappings within a cluster.

Kubernetes Service Spec Structure refers to the schema and field-level composition of the spec block within a Service manifest, defining exactly how selector matching, port mapping, session behavior, and external exposure are expressed as structured YAML fields rather than free-form configuration. Understanding this structure precisely is necessary to author Services correctly, since small structural mistakes, such as mismatched port names, produce Services that appear valid but silently fail to route traffic.


Top-Level Spec Fields

selector

The selector field is a label query matched against pod labels; every pod whose labels satisfy the selector becomes a candidate backend for the Service. A Service with an empty or absent selector is not matched against pods automatically and instead expects its Endpoints to be managed manually or by an external controller.

spec:
  selector:
    app: ledger-api
    tier: backend

type

The type field determines the Service's exposure model and defaults to ClusterIP when omitted. Valid values are ClusterIP, NodePort, LoadBalancer, and ExternalName, each changing how the remaining spec fields are interpreted, most notably externalName, which is only meaningful when type is ExternalName.

spec:
  type: ClusterIP

ports

The ports field is a list of port mapping entries, each of which may specify a name, the externally-facing port, the targetPort on the backing pod, and optionally a protocol (defaulting to TCP). When a Service defines more than one port, every entry must have a unique name, since the name is what higher-level resources such as Ingress use to reference a specific port unambiguously.

spec:
  ports:
    - name: http
      port: 80
      targetPort: 8080
      protocol: TCP
    - name: grpc
      port: 9090
      targetPort: 9090
      protocol: TCP

targetPort as Name or Number

targetPort may reference either a numeric container port or a named port declared in the pod's container spec, and using a named targetPort is generally more resilient, since it allows the actual container port number to change without requiring a corresponding Service update, as long as the pod's named port declaration is updated consistently.

containers:
  - name: ledger-api
    ports:
      - name: api-port
        containerPort: 8080
---
spec:
  ports:
    - port: 80
      targetPort: api-port

Session and Traffic Behavior Fields

sessionAffinity

The sessionAffinity field controls whether repeated requests from the same client are routed to the same backing pod. Its default value, None, distributes each connection independently; setting it to ClientIP pins a client's connections to the same pod for the configured timeout window, which is used when a workload maintains connection-local state that would break if requests were spread across different pods.

spec:
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800

externalTrafficPolicy

For NodePort and LoadBalancer Services, externalTrafficPolicy determines whether external traffic is routed to any node regardless of whether it hosts a backing pod (Cluster, the default, which preserves even load distribution but obscures the original client IP) or only to nodes that actually host a backing pod (Local, which preserves the client's source IP but can produce uneven load distribution).

spec:
  externalTrafficPolicy: Local

Type-Specific Fields

clusterIP and clusterIPs

The clusterIP field can be left unset for automatic allocation, explicitly set to a specific address for a stable, pre-known virtual IP, or set to None to declare a headless Service. The plural clusterIPs field exists to support dual-stack clusters, holding both an IPv4 and IPv6 address simultaneously.

spec:
  clusterIP: None

nodePort

Within each ports entry, an explicit nodePort value can be set for NodePort and LoadBalancer Services to pin a specific external port across all nodes; if omitted, Kubernetes allocates one automatically from the configured node port range.

spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 8080
      nodePort: 30080

externalName

Exclusive to ExternalName Services, this field holds the DNS name that internal lookups of the Service name are aliased to, and no selector, ports, or clusterIP fields are meaningful in this mode.

spec:
  type: ExternalName
  externalName: partner-provider.example.com

Structural Validation Considerations

Port Name Uniqueness Across a Multi-Port Service

Because Ingress and other consumers reference Service ports by name when a Service exposes more than one port, omitting names or duplicating them across entries produces a Service that validates syntactically but cannot be referenced unambiguously by name-based consumers, only by relying on port number, which is more fragile to maintain over time.

Selector and Pod Template Label Alignment

The spec's selector field must be a subset of the labels present on the pod template it targets; extra labels on the pod beyond what the selector requires are harmless, but any selector key absent from the pod's labels results in that pod never being selected as a backend.

spec: selector: matches pod labels type: ClusterIP | NodePort | LoadBalancer | ExternalName ports: [ name, port, targetPort, protocol ] sessionAffinity: None | ClientIP clusterIP: auto | address | None (headless)