kubernetes/kubernetes
Service
A stable network identity for a (changing) set of Pods. The Service object is the API; kube-proxy is the data plane. EndpointSlice is what connects the two.
Where it lives
| Concern | Path |
|---|---|
| Public type | staging/src/k8s.io/api/core/v1/types.go (type Service struct {...}) |
| Validation | pkg/apis/core/validation/validation.go |
| REST registry | pkg/registry/core/service/ |
| Strategy | pkg/registry/core/service/strategy.go |
| Storage (with VIP and node-port allocators) | pkg/registry/core/service/storage/ |
| ClusterIP allocator | pkg/registry/core/service/ipallocator/ |
| NodePort allocator | pkg/registry/core/service/portallocator/ |
| Endpoints registry | pkg/registry/core/endpoint/ |
| EndpointSlice registry | pkg/registry/discovery/endpointslice/ |
| EndpointSlice controller | pkg/controller/endpointslice/ |
| Mirror controller | pkg/controller/endpointslicemirroring/ |
| Proxy backends | pkg/proxy/{iptables,nftables,ipvs,winkernel}/ |
Fields
A typical Service:
apiVersion: v1
kind: Service
metadata: { name: web, namespace: shop }
spec:
type: ClusterIP # ClusterIP | NodePort | LoadBalancer | ExternalName
ipFamilyPolicy: SingleStack # SingleStack | PreferDualStack | RequireDualStack
ipFamilies: [IPv4]
clusterIPs: [10.96.0.42] # allocated by the apiserver
selector: { app: web }
ports:
- name: http
port: 80 # service port
targetPort: 8080 # pod port
protocol: TCP
internalTrafficPolicy: Cluster # Cluster | Local
externalTrafficPolicy: Cluster # for NodePort/LB only
sessionAffinity: None
status:
loadBalancer: {} # populated by the cloud-controller-manager for type=LoadBalancerClusterIP allocation
The apiserver allocates a unique ClusterIP at create time. The allocator is:
- Bitmap allocator (legacy) in
pkg/registry/core/service/ipallocator/bitmap.go— single in-memory bitmap protected by leader-elected reconciliation. - Multi-CIDR allocator in
pkg/registry/core/service/ipallocator/cidrallocator.go— backed byServiceCIDRresources, allowing dynamic addition of new ranges.
The ServiceCIDR controller (pkg/controller/servicecidrs/) reconciles in-flight CIDRs with the allocator state.
NodePort allocation
pkg/registry/core/service/portallocator/ allocates a unique port in the configured range (default 30000-32767). The same allocator pattern as ClusterIP — bitmap with periodic reconciliation against the database of existing Services.
EndpointSlice computation
When a Service has a selector, the EndpointSlice controller (pkg/controller/endpointslice/) computes the Pods that match and emits EndpointSlice resources:
graph LR
Service -->|selector| Pods
Pods -->|filter Ready| Eligible[Eligible endpoints]
Eligible -->|topology hints| Slice[EndpointSlice]
Slice -->|published| API[kube-apiserver]
API --> Proxy[kube-proxy on each node]Slices are bounded at 100 endpoints by default. Large Services produce many slices; updates only rewrite the affected slice.
Topology-aware routing
Each EndpointSlice endpoint can carry Hints.ForZones. kube-proxy reads the hints and prefers same-zone endpoints when:
- The hints population is "sufficient" (> 50% of endpoints have hints).
- Cluster-wide endpoint distribution is "balanced enough" (heuristic in
pkg/proxy/topology.go).
When the heuristic fails (e.g., one zone has zero endpoints), the proxy falls back to cluster-wide routing.
Service types
| Type | Behaviour | Implementation |
|---|---|---|
ClusterIP |
In-cluster VIP only | kube-proxy only |
NodePort |
ClusterIP + a port on every node | kube-proxy programs the node port |
LoadBalancer |
NodePort + an external LB | Cloud-controller-manager creates the LB |
ExternalName |
DNS CNAME | Resolved by CoreDNS only |
type=LoadBalancer is special: the cloud-controller-manager's service controller (staging/src/k8s.io/cloud-provider/controllers/service) creates the LB and writes the LB's external IP/hostname to status.loadBalancer.ingress.
Headless Services
spec.clusterIP: None makes a Service headless. There's no VIP and no kube-proxy programming. CoreDNS responds to <service>.<ns>.svc.<cluster-domain> with A records for every endpoint. StatefulSets use this for stable per-Pod DNS via a parent headless Service.
Validation highlights
- Port names unique within a Service.
targetPortmay be a number or a name (resolved to the container's named port).clusterIPsandipFamiliesconsistent in length and ordering.externalTrafficPolicy=Localonly valid for NodePort and LoadBalancer.internalTrafficPolicymay not equalLocalfor NodePort/LoadBalancer.
Key source files
| File | Purpose |
|---|---|
staging/src/k8s.io/api/core/v1/types.go |
Public Service type |
pkg/registry/core/service/strategy.go |
Service REST strategy |
pkg/registry/core/service/storage/storage.go |
Service storage with allocators |
pkg/registry/core/service/ipallocator/cidrallocator.go |
Multi-CIDR ClusterIP allocator |
pkg/registry/core/service/portallocator/ |
NodePort allocator |
pkg/controller/endpointslice/endpointslice_controller.go |
Endpoint slicing |
pkg/proxy/topology.go |
Topology-aware routing |
staging/src/k8s.io/cloud-provider/controllers/service/controller.go |
Service LB controller |
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.