What Is a Service in Kubernetes?

What Is a Service in Kubernetes?

A plain-English guide to the object that gives your applications a stable name and address: why Pods need it, how it finds the right containers, how traffic is spread between them, and how to expose your app safely to the world.

Imagine you build an online shop from small programs. One program shows products, one handles the shopping cart, and one takes payments. The cart program needs to call the payment program many times a second. In Kubernetes, each program runs inside a Pod, and here is the awkward truth: Pods are temporary. They crash, they are replaced during updates, they move to other machines, and each new Pod gets a brand-new network address. So how can the cart program ever know where to send a payment request?

The answer is a Kubernetes Service. It is one of the first objects every beginner meets, and one of the most misunderstood. In this guide you will learn what a Service is, why it exists, how it picks the right Pods, how traffic reaches them, what the different Service types do, how names and discovery work, how to expose an app to the internet, and how to secure, watch, and troubleshoot it. Every new word is explained the first time it appears, and no earlier Kubernetes knowledge is needed.

1What Is a Service? The Short Answer

A Service is a stable name and address in front of a changing group of Pods, with built-in load balancing.

The two ideas inside one object

A Kubernetes Service does two jobs at once. First, it gives a group of Pods one steady identity: a fixed internal address and a fixed name that never change while the Service exists. Second, it spreads incoming requests across all the healthy Pods in that group, so no single Pod is overloaded and a failed Pod is skipped automatically. Callers only ever learn the Service’s name. They never need to know how many Pods stand behind it, where those Pods run, or whether they were replaced a minute ago.

Everyday Analogy

Think of a company’s main phone number. When you call it, a receptionist connects you to whichever employee is free. Employees come and go, change desks, and take holidays, yet the main number stays the same for years. A Service is that main number, and the Pods are the employees. Customers dial one number and always reach someone available.

A few words to know first

  • Pod: the smallest unit Kubernetes runs, holding one or more containers that share a network address.
  • Label: a small tag, like a colored sticker, attached to an object. A Pod might carry the label “app equals cart.”
  • Selector: a rule that says “pick every Pod with this label.” A Service uses a selector to find its Pods.
  • Load balancing: sharing work between several identical workers so that none is overwhelmed.
  • Cluster: the group of machines that Kubernetes manages as one system.
flowchart LR
    C["Cart program - the caller"] -->|calls one steady name| S["Service: payments - stable name and address"]
    S --> P1["Payment Pod 1"]
    S --> P2["Payment Pod 2"]
    S --> P3["Payment Pod 3"]
Figure 1. The caller talks to one stable Service, which shares the work between the Pods behind it.
i
Tip

Remember this one sentence: Pods come and go, but the Service stays. Almost every design choice about Services follows from it.

2Why Services Exist: The Problem They Solve

To see why Services matter, look at what life is like without one.

Pods are mortal, and their addresses die with them

Every Pod in a cluster receives its own network address, called an IP address. Two Pods can talk directly using these addresses, and Kubernetes promises that this works even across different machines. That sounds convenient, but there is a catch. Kubernetes treats Pods as disposable. If a Pod crashes, a replacement is created with a new address. If you deploy a new version, the old Pods are removed and new ones appear. If the cluster adds machines or removes them, Pods move. An address that was correct in the morning may point to nothing by the afternoon.

Why not just write the address down?

Suppose the cart program stored the payment Pod’s address in a settings file. The first time that Pod restarted, every payment would fail. Suppose instead the cart program asked the cluster for the current list of payment Pods before each request. That would work, but now every program in your company would need special code to talk to Kubernetes, choose between Pods, and handle failures. It would be repetitive, error-prone, and impossible to share with programs that know nothing about Kubernetes.

The Service as the clean solution

A Service moves this whole problem into the platform. Programs use an ordinary name, the same way a website uses a domain name, and the cluster quietly keeps the list of Pods up to date behind the scenes. Your code needs no Kubernetes knowledge at all. It just calls a name.

1
stable name and address for many changing Pods
4
main Service types: ClusterIP, NodePort, LoadBalancer, ExternalName
0
changes needed in your code to find Pods
Everyday Analogy

Consider a taxi company. You never memorize the mobile numbers of individual drivers, because drivers change shifts, cars, and even jobs. You call the dispatch number, and dispatch sends whichever car is nearby and free. If a car breaks down, dispatch simply sends another, and you may never learn there was a problem. The Service is the dispatch line.

Five gifts a Service gives you

Gift 1

A stable address

The Service’s internal address stays the same for its whole life, no matter how often Pods change.

Gift 2

A friendly name

Every Service automatically gets a name in the cluster’s own phone book, so programs call “payments” instead of a number.

Gift 3

Load balancing

Requests are shared across all matching Pods, so capacity grows simply by adding Pods.

Gift 4

Health awareness

Only Pods that report themselves as ready receive traffic. Sick or starting Pods are skipped.

Gift 5

Controlled exposure

You choose who can reach the app: only other Pods, other machines on the network, or the whole internet.

3Core Concepts: Selectors, Ports, and Endpoints

Five small ideas explain how a Service is described and how it knows where to send traffic.

1. The selector: which Pods belong to me?

A Service does not create Pods and does not own them. It only points at them. The pointing is done with a selector, a label rule. If the Service says “select Pods labeled app equals payments,” then every Pod in the same namespace carrying that label becomes a member, and any Pod losing the label leaves the group. This loose connection is powerful: you can add, remove, or replace Pods freely, and the Service adapts without any edits.

2. Ports: the doors

A machine offers many numbered network doors called ports. A Service has a few port settings, and beginners often mix them up, so here they are in plain words:

SettingMeaningAnalogy
portThe door number the Service itself listens onThe extension number callers dial
targetPortThe door number on the Pod where the app actually listensThe desk phone that actually rings
nodePortA door opened on every machine, only for NodePort and LoadBalancer typesA side entrance to the building
protocolThe kind of traffic, usually TCP, sometimes UDPPhone call versus text message

3. The cluster IP: the virtual address

Most Services receive a cluster IP, an internal address taken from a range reserved for Services. It is called virtual because no machine or network card really owns it. It exists only as a rule inside the cluster’s networking, which redirects any traffic sent to it toward a real Pod. That is why it can stay fixed while the Pods behind it change.

4. Endpoints and EndpointSlices: the current member list

Somebody must keep track of which Pods currently match the selector and are ready. That list is stored in objects called EndpointSlices, which hold the addresses and ports of the healthy Pods. A controller in the cluster creates and updates them automatically. The older Endpoints object did the same job for all Pods at once, and it is being phased out because one huge list was slow to update in big clusters. Slices break the list into smaller pieces, roughly a hundred addresses each by default.

5. Readiness: only healthy Pods get traffic

Each Pod can define a readiness check, a small test that says “I am ready for customers.” While the test fails, for example because the app is still loading data, the Pod stays out of the member list. When it passes, the Pod is added. This is what makes rolling updates and restarts smooth.

Reading a Service definition in plain words

When you write a Service as a configuration file, it usually holds only a handful of facts, and you can read them like a short form. It has a name, which becomes the DNS name. It has a namespace, the room it lives in. It has a type, which decides who can reach it, and if you leave the type out it becomes ClusterIP. It has a selector, the label rule that finds its Pods. And it has a list of ports, each with the number callers use and the number the app listens on. That is nearly everything. A Service definition is one of the shortest and most readable objects in Kubernetes, which is one reason it is a good first object to learn.

A tip for choosing labels: use names that describe the role of the app, not its version. If a Service selects “version two,” it stops matching the moment you release “version three.” Labels for the role stay stable, while a separate label for the version can be added for other purposes, such as gradual rollouts.

?
Good to know

A Service works only inside its own namespace when it comes to selecting Pods. A Service in one namespace cannot pick up Pods that live in another. Other namespaces can still call the Service by using its full name.

4Architecture and Components

A Service looks like a single object, but several cluster components cooperate to make it work.

flowchart TB
    USER["You create a Service"] --> API["API Server - stores the Service"]
    API --> ESC["EndpointSlice controller - watches Pods and Services"]
    ESC -->|writes member list| API
    API --> KP1["kube-proxy on Node 1 - programs traffic rules"]
    API --> KP2["kube-proxy on Node 2 - programs traffic rules"]
    API --> DNS["CoreDNS - adds the Service name to cluster DNS"]
    KP1 --> POD1["Pod on Node 1"]
    KP2 --> POD2["Pod on Node 2"]
Figure 2. The components that turn one Service object into working network behavior.

The cast of characters

Storage

API Server

Receives your Service definition, checks it, saves it in the cluster database, and tells watchers about it. It also allocates the cluster IP.

Bookkeeper

EndpointSlice controller

Watches Services and Pods. Whenever a matching Pod appears, disappears, or changes readiness, it updates the member list.

Traffic cop

kube-proxy

Runs on every worker machine. It watches Services and their member lists and writes the network rules that redirect traffic from the virtual address to real Pods.

Phone book

CoreDNS

The cluster’s name server. It answers questions like “what is the address of payments?” using the Services stored in the API.

Roads

Network plugin

Gives each Pod an address and makes sure Pods on different machines can reach each other. Services rely on it.

Cloud bridge

Cloud controller

For LoadBalancer Services, it asks the cloud provider to create a real load balancer and reports the resulting address.

i
Tip

Notice that there is no single program called “the Service.” It is a shared agreement stored in the API server, and many independent helpers read it and act. That is why Services keep working even if one helper restarts.

5Internal Working: How Traffic Really Flows

The virtual address is a clever illusion. Here is how the trick is done.

sequenceDiagram
    participant C as Cart Pod
    participant D as CoreDNS
    participant N as Node networking rules
    participant P as Payment Pod
    C->>D: What is the address of payments?
    D-->>C: The Service cluster IP
    C->>N: Send request to the cluster IP and port
    N->>N: Pick one ready Pod from the member list
    N->>P: Forward request to the chosen Pod address
    P-->>C: Reply travels back to the cart
Figure 3. A request from one Pod to another through a Service.
1

The caller uses the name

The cart program asks for “payments.” Cluster DNS answers with the Service’s virtual address. Nothing about individual Pods is revealed.

2

The packet leaves toward the virtual address

The cart’s request is sent to the virtual address and the Service port, as if a real machine lived there.

3

The local machine rewrites the destination

Before the packet leaves the machine, rules installed by kube-proxy notice the virtual address. They pick one Pod from the ready list and replace the destination with that Pod’s real address. This trick is called destination network address translation, or DNAT.

4

The network delivers it

The cluster network carries the packet to the chosen Pod, wherever it runs.

5

The reply is translated back

The machine remembers the rewrite, so the reply appears to come from the Service address, and the caller never notices the swap.

Why the same connection keeps going to the same Pod

You might wonder what stops the next packet of the same conversation from being sent to a different Pod. The answer is the Linux connection tracking table. The first packet of a new connection triggers the choice of a Pod, and the kernel writes a note saying “this connection belongs to that Pod.” Every later packet in the same connection follows the note, and the replies are translated back using the same note. This is why the balancing decision happens once per connection, not once per request, and why a long-lived connection sticks to one Pod for its whole life. It also explains why a Pod that disappears in the middle of a connection can cause errors: the note still points at it until the connection ends or times out.

kube-proxy modes: three ways to write the rules

ModeHow it worksStrengthsWatch out for
iptablesWrites a chain of packet-filter rules in the Linux kernel; a rule picks a random backendSimple, reliable, the long-time defaultRule lists grow long with thousands of Services and can slow updates
IPVSUses the kernel’s built-in load balancer with hash tables and several balancing methodsFaster lookups at large scale, more balancing choicesNeeds extra kernel modules and more setup
nftablesUses the newer Linux packet-filter system to hold rules more efficientlyBetter performance than iptables for large rule setsNewer, so check support in your Kubernetes version and operating system

Replacing kube-proxy altogether

Some network plugins, most famously Cilium, use a Linux technology called eBPF to perform Service routing directly inside the kernel, without kube-proxy at all. This can be faster and gives better visibility. Google’s GKE Dataplane V2 is built on this idea, and other managed services offer similar options. From your point of view as an application developer, nothing changes: you still create a Service and call its name.

!
Watch out

The virtual address does not answer ping requests in the usual way, because no machine truly owns it. Only the ports defined in the Service work. Beginners often think the Service is broken when a ping fails, even though the app is perfectly reachable.

6ClusterIP: The Default Service Type

Every Service has a type that decides who can reach it. The first type, and the default, is ClusterIP.

What it does

A ClusterIP Service gets a virtual address that works only inside the cluster. Other Pods can call it, and so can programs running on the cluster’s own machines, but nobody outside can reach it directly. This is the right choice for most internal parts of an application: databases, payment engines, background workers, and internal APIs. It follows a good security habit: keep things private unless there is a reason to expose them.

Everyday Analogy

ClusterIP is the internal extension number of an office phone system. Colleagues inside the building can dial 214 to reach the accounting team, but someone on the street cannot dial it. It is simple, private, and reliable, which is exactly what you want for internal conversations.

A Service you already use without knowing

Every cluster contains a Service named kubernetes in the default namespace. It is the stable internal address of the API server itself. Programs running in Pods, such as controllers and monitoring tools, use it to find the cluster’s front door without knowing which control plane machine is currently active. This is a perfect example of the idea in action.

Where the virtual address comes from

When the cluster is created, the administrator reserves a block of private addresses just for Services, called the Service address range. The API server hands out one address from this block to every new Service and records it so that no two Services share one. The block is separate from the range used for Pod addresses, which is why Service addresses and Pod addresses never collide. You can ask for a particular address when you create a Service, but it is almost always better to let the cluster choose. If the range is too small, you can run out of addresses in a very large cluster, so platform teams choose it with growth in mind.

When to use ClusterIP

  • Any component that is called only by other components in the cluster.
  • Databases and caches that should never be public.
  • Services placed behind an Ingress or Gateway, which handles the outside world.
  • Anything you are unsure about, since private is the safe default.

Strengths

  • Simple and stable
  • Private by default
  • No cost beyond the cluster itself
  • Works everywhere Kubernetes runs

Limits

  • Not reachable from outside the cluster
  • Needs Ingress or a Gateway for public web traffic
  • Cluster IP cannot be pinged

7NodePort and LoadBalancer: Opening the Doors

When people outside the cluster must reach your app, two more Service types come into play. They build on each other like layers.

flowchart LR
    U["Customer on the internet"] --> LB["Cloud load balancer - public address"]
    LB --> NP1["NodePort door on Node 1"]
    LB --> NP2["NodePort door on Node 2"]
    NP1 --> CIP["ClusterIP - virtual address"]
    NP2 --> CIP
    CIP --> A["Pod A"]
    CIP --> B["Pod B"]
    CIP --> C["Pod C"]
Figure 4. The layers of a LoadBalancer Service: each one wraps the one below it.

NodePort: a side entrance on every machine

A NodePort Service does everything a ClusterIP Service does, and additionally opens the same port number on every worker machine. By default this number comes from the range 30000 to 32767. Anyone who can reach any machine’s address on that port is forwarded to the Service, and from there to a Pod, even if that Pod runs on a different machine. It is a quick way to test an app from outside, and it is the building block that other types use.

In real production use, NodePort has drawbacks. The port numbers are unfamiliar and high. You must know the addresses of your machines, and those may change. Firewalls must be opened for the whole range. And there is no health-checking front layer that stops sending traffic to a machine that has failed. For these reasons, it is mainly used for learning, small tests, or as a hidden layer beneath a load balancer.

LoadBalancer: a proper public front door

A LoadBalancer Service goes one step further. It does all the work of NodePort and then asks the cloud provider, through the cloud controller, to create a real external load balancer with its own public address. The provider’s load balancer checks the health of the machines and spreads traffic across them. When the address is ready, Kubernetes writes it into the Service, and you can point your website name at it.

Everyday Analogy

Picture a shopping mall. The ClusterIP is the internal corridor that only staff use. The NodePort adds a side door at every wing of the mall. The LoadBalancer is the grand main entrance on the street, with a greeter who directs each visitor to a side door that is currently open and quiet, then through the corridor to the right shop.

Internal load balancers

A LoadBalancer Service does not have to face the internet. Most clouds let you ask for an internal load balancer, which receives an address only on your private network. This is useful when a Service must be reachable from other clusters, from virtual machines outside Kubernetes, or from your company network over a private link, but never from the public internet. Requesting it usually means adding a provider-specific annotation to the Service, which is one more reason to review annotations carefully when you move between clouds.

What you need to know about LoadBalancer

  • It costs money. Each Service of this type usually creates its own cloud load balancer, and you pay for each one every hour, plus data transfer.
  • It depends on the cloud. On AWS, Google Cloud, and Azure, it works out of the box. In a private data center, or on a laptop, there is no cloud to answer, so the address stays “pending” unless you install a helper such as MetalLB.
  • Settings live in annotations. Details such as internal versus public, or which kind of load balancer to build, are usually chosen with provider-specific annotations, so they are not fully portable.
  • It works at the network level. A LoadBalancer Service moves raw connections and does not understand website addresses or paths. For that, use Ingress or Gateway (Chapter 11).
TypeWho can reach itTypical useMain drawback
ClusterIPOnly things inside the clusterInternal services and databasesNo outside access
NodePortAnyone who can reach a machine on the high portTesting and building blocksAwkward and less safe for production
LoadBalancerThe internet, or a private network, through a cloud load balancerExposing one app or protocol directlyOne paid load balancer per Service
!
Watch out

Every LoadBalancer Service you create can quietly add a new bill line. A team that exposes twenty small apps this way can end up with twenty load balancers. Put many web apps behind one shared Ingress or Gateway instead.

8ExternalName, Headless, and Selector-less Services

Not every Service points at ordinary Pods. Three special forms handle unusual needs.

ExternalName: a nickname for something outside

An ExternalName Service does not select Pods at all. Instead, it makes a name inside the cluster point to a name outside it. When a Pod asks for the Service, cluster DNS answers with an alias to the outside name, such as the address of a managed database run by a cloud provider. No proxying or load balancing happens; it is only a nickname. Its advantage is that your applications use a stable in-cluster name, and if you later move the database, you change one Service instead of every application.

Headless Services: the phone book without a receptionist

Sometimes load balancing is exactly what you do not want. A database cluster needs each member to find the others by name, and a client may need to connect to a particular member. A headless Service is created by setting the cluster IP to “None.” It gets no virtual address and no load balancing. Instead, DNS returns the individual addresses of all the ready Pods, and the caller decides which to use.

Headless Services are the partner of StatefulSets, the Kubernetes tool for running stateful programs such as databases. Together they give each Pod a stable, predictable name, like database-0, database-1, and database-2, which survives restarts.

Everyday Analogy

A normal Service is a company switchboard that picks who answers. A headless Service is a staff directory pinned in the lobby: it simply lists every employee’s direct line, and you choose whom to call. A team that must talk to each other by name, like surgeons in an operating room, needs the directory, not the switchboard.

Services without selectors: pointing at anything

If you create a Service without a selector, Kubernetes does not create a member list for you. You supply the addresses yourself. This lets you give a friendly in-cluster name to something that is not a Pod, for example an old database server in your data center, or an application in another cluster. Applications inside the cluster call the Service name, and you control where it points.

Alias

ExternalName

Use to give an outside service an in-cluster nickname. Watch for outside names that use their own security certificates, since the name the client sees may differ.

Directory

Headless

Use for databases, message brokers, and any program where members need to find each other or clients need a specific member.

Manual

No selector

Use to wrap something outside Kubernetes in a Service, with addresses you maintain yourself.

9Service Discovery: Finding Services by Name

A Service is only useful if others can find it. Kubernetes gives you two mechanisms, and one of them is far better.

DNS: the recommended way

The cluster runs its own name server, CoreDNS. Whenever you create a Service, it automatically gains a name of the form service-name.namespace.svc.cluster.local. So a Service called payments in the namespace shop is known as payments.shop.svc.cluster.local. Every Pod is configured to search sensible shortcuts, so the ways you can call it depend on where you are:

Where the caller livesName the caller can useWhy it works
Same namespacepaymentsThe Pod’s search list adds its own namespace
Different namespacepayments.shopAdds the namespace but leaves the rest to the search list
Anywhere, most explicitpayments.shop.svc.cluster.localThe full, fully qualified name

DNS also supports named ports, which lets callers look up not only the address but also which port carries a particular protocol. For headless Services, DNS returns the list of Pod addresses instead of a single virtual address.

A hidden cost: the search list

The convenience of short names comes with a small price. Each Pod is configured with a list of suffixes to try, such as its own namespace, the general Service suffix, and the cluster suffix. It also has a setting that treats any name with fewer than five dots as “probably local,” so it tries the suffixes first. When your program looks up a real outside website like a payment provider, the Pod may first ask DNS several wrong questions, such as the outside name with the cluster suffix added, before it gets to the correct one. In a busy application this can multiply the load on CoreDNS and add small delays. Teams that notice this often add a trailing dot to outside names, which marks them as complete, or adjust the setting for their Pods, or run a local DNS cache on every machine.

Environment variables: the older way

When a Pod starts, Kubernetes also places details of the Services that already exist into its environment variables, for example the host and port of a Service named payments. This works, but it has a trap: only Services created before the Pod starts appear. Creating things in the wrong order leads to confusing behavior. For this reason, teams rely on DNS.

Everyday Analogy

DNS is a live phone book that is updated the moment a new listing appears. Environment variables are a printed directory handed to you on your first day, which cannot include anyone who joined after you. Use the live phone book.

i
Tip

In shared code and configuration, use the short name for calls inside a namespace and the name with the namespace for calls between namespaces. This keeps configuration files portable between development, staging, and production namespaces.

10Data Flow and Lifecycle

The most important behavior of a Service happens during change: updates, crashes, and scaling.

Life of a Service

1

Created

You submit the Service. The API server saves it and allocates a cluster IP. DNS gains a new name.

2

Populated

The EndpointSlice controller finds Pods matching the selector and records those that are ready.

3

Programmed

Every kube-proxy sees the new Service and writes the rules that redirect its address to real Pods.

4

Serving

Traffic flows. As Pods come and go, the member list and rules keep updating automatically.

5

Deleted

The rules, the DNS name, and any cloud load balancer are removed. The Pods themselves are not touched, because a Service never owned them.

What happens during a rolling update

sequenceDiagram
    participant D as Deployment
    participant NP as New Pod
    participant OP as Old Pod
    participant E as EndpointSlice
    participant K as kube-proxy
    D->>NP: Start a new version Pod
    NP->>E: Becomes ready, so its address is added
    E->>K: Member list changed
    K->>K: Add new Pod to traffic rules
    D->>OP: Begin shutting down an old Pod
    OP->>E: Marked as terminating, so removed from new traffic
    E->>K: Member list changed
    K->>K: Remove old Pod from traffic rules
    OP->>OP: Finish in-flight requests and exit
Figure 5. How the Service adds new Pods and drains old ones during an update.

Watch the order. A new Pod receives traffic only after its readiness check passes. An old Pod is taken out of the member list when it starts terminating, and only then is it stopped. In an ideal update, no customer request is sent to a Pod that is not ready or that has already gone.

Scaling up and down behind a Service

The Service makes scaling almost invisible. When traffic grows, an autoscaler raises the number of Pods in the Deployment. Each new Pod starts, passes its readiness check, and only then joins the member list. From that moment the Service shares traffic with it, and the caller sees nothing but faster answers. When traffic falls, the autoscaler removes Pods, and each leaving Pod is taken out of the member list before it stops. Because callers only know the Service name, they never have to be told that the number of workers changed. This separation, where callers depend on a name and the platform manages the workers, is the central idea of the Service, and it is why a small team can run an application that grows a hundred times bigger without rewriting how its parts find each other.

One practical point: a new Pod that takes a long time to become ready will not help during a sudden spike, because it receives no traffic until it passes its check. Applications that start quickly, or that keep a few spare Pods warm, cope with spikes better than ones that need a minute to load data.

The race that catches beginners

There is a small timing gap. The signal to shut down a Pod and the update of network rules on every machine happen at the same time, not one after the other. A few machines may still send a request to the old Pod for a fraction of a second after the Pod has started closing. If the app exits instantly, those requests fail. The fix is to give the app a graceful shutdown: keep serving for a short while after the shutdown signal, finish work already in progress, and then exit. Many teams add a short pause in a “pre-stop” step to cover the gap.

!
Common mistake

Forgetting to define a readiness check. Without one, Kubernetes considers a Pod ready as soon as its container starts, even if the app inside is still loading. Users then get errors during every deployment, and the Service is blamed for a problem it was never told about.

11Service, Ingress, and Gateway: Who Does What

A common beginner puzzle is how these three fit together. They are layers, not competitors.

flowchart LR
    U["Customer browser"] --> DNSX["DNS for the website name"]
    DNSX --> CLB["Cloud load balancer"]
    CLB --> IC["Ingress controller or Gateway - reads host and path"]
    IC -->|shop.example.com| S1["Service: storefront"]
    IC -->|shop.example.com/api| S2["Service: catalog"]
    IC -->|pay.example.com| S3["Service: payments"]
    S1 --> P1["Storefront Pods"]
    S2 --> P2["Catalog Pods"]
    S3 --> P3["Payment Pods"]
Figure 6. One shared entry point sends web traffic to many internal Services.
Layer 1

Service

Gives a group of Pods a stable address and balances the load. Understands connections and ports, not websites.

Layer 2

Ingress

A set of web routing rules, such as “requests for this website name and path go to that Service.” A separate program, the Ingress controller, carries them out. Also handles security certificates for HTTPS.

Layer 2, newer

Gateway API

The modern, more expressive successor to Ingress. It separates the roles of the platform team, who own the gateway, and app teams, who attach their own routes, and supports more protocols and traffic rules.

How to choose

  • For internal calls between programs, use a ClusterIP Service.
  • For web applications reached by website names and paths, use Ingress or Gateway in front of ClusterIP Services.
  • For non-web protocols such as a database port, a game server, or a message broker that must be public, use a LoadBalancer Service directly.
  • For a quick test, use NodePort or a temporary port-forward to one Pod.
?
Good to know

Ingress controllers and gateways are products maintained by different projects and vendors, and their support status changes over time. Before you choose one for a long-lived system, check that it is actively maintained, and read its own documentation for supported features.

12Advanced Traffic Control

Once the basics feel comfortable, a few extra settings let you fine-tune how a Service treats traffic.

Stickiness

Session affinity

By default each new connection may go to a different Pod. Setting session affinity to client address sends a given caller to the same Pod for a period, three hours by default. Useful for old apps that keep visitor data in memory, but it makes load less even.

Source address

External traffic policy

With the default setting, traffic entering at any machine may hop to a Pod on another machine and lose the original client address. Setting the policy to “Local” keeps traffic on the receiving machine, which preserves the client address and saves a hop, but can unbalance load and only works where Pods exist.

Inside

Internal traffic policy

Restricts calls from Pods to use only Pods on the same machine, which cuts network delay for helper programs such as log collectors.

Zones

Topology-aware routing

Prefers Pods in the caller’s own availability zone, lowering delay and cross-zone data charges. It needs balanced Pod placement to work well.

Not ready

Publishing unready addresses

An option for programs like clustered databases whose members must find one another before any is fully ready.

Versions

Dual-stack

Lets a Service carry both older and newer kinds of network addresses, IPv4 and IPv6, at the same time.

Everyday Analogy

Session affinity is like asking the bank to always send you to the same teller because she knows your case. Topology-aware routing is asking to be served at the branch nearest your home instead of the one across town. Both save effort for you but can make the bank’s queues less even, which is the trade-off to remember.

Choosing the right balance

Each of these switches trades simplicity for efficiency or control. Start with defaults. Turn on a special setting only when you have a measured reason, such as a legal need to see real client addresses, or a bill showing large cross-zone transfer costs. Then test, because a setting that fits one workload can quietly harm another.

13Advantages, Disadvantages, and Trade-offs

Services solve a big problem elegantly, but they have limits worth knowing.

Advantages

  • Stable names and addresses for changing Pods
  • Automatic load balancing and health awareness
  • Works without any change to application code
  • Portable across laptops, data centers, and clouds
  • Built-in DNS discovery
  • Simple building block for larger designs like Ingress and service meshes

Disadvantages

  • Balancing is simple: connection-level, not request-aware
  • Long-lived connections may stick to old Pods
  • Large numbers of Services can slow older proxy modes
  • LoadBalancer Services can multiply cloud costs
  • Cloud-specific behavior hides in annotations
  • Misconfigured selectors fail silently

When you might not need a Service

Not every Pod needs a Service. A batch job that reads from a queue and writes to a database receives no incoming calls, so no Service is required. A program that only sends requests out never needs an address of its own. Creating Services for things that do not receive traffic adds clutter and, in very large clusters, extra rules for the machines to maintain. A helpful question is “does anyone need to call this by name?” If the answer is no, leave the Service out.

Key trade-offs at a glance

ChoiceYou gainYou give up
One LoadBalancer per appSimplicity and isolationHigher cost and many public addresses
Shared Ingress or GatewayOne entry point, lower cost, central certificatesA shared component to run and protect
Headless ServiceDirect Pod access and stable identitiesBuilt-in load balancing
Session affinityConsistent Pod per visitorEven load and easy scaling
Local external traffic policyReal client address, fewer hopsUniform balance across machines
Service mesh on topSmart request-level routing, retries, encrypted trafficMore components, more resource use, more learning

A useful rule of thumb: start with plain ClusterIP Services and one shared entry point. Add complexity, such as a service mesh or special policies, only when a real need appears. Simple designs are easier to understand at two in the morning when something breaks.

14Securing Services

A Service decides who can reach your application, which makes it one of the most security-sensitive objects you create.

Everyday Analogy

Think of each Service as a door in an office building. The question is not only “does the door work?” but “who has a key, and which rooms does it open?” Leaving the back door propped open to the street because it is convenient is how most break-ins happen, and most Kubernetes exposure incidents come from a door opened wider than the team realized.

Layers of protection

Default

Keep it private

Use ClusterIP unless outside access is truly needed. A Service that is not exposed cannot be attacked from the internet.

Rules

Network policies

By default, any Pod can call any Service. Network policies add rules such as “only the cart may call payments.” They need a network plugin that enforces them.

Edge

Restrict public load balancers

Where the cloud supports it, limit which source address ranges may reach a LoadBalancer Service, or make it internal-only so only your private network can connect.

Encryption

TLS in transit

Terminate HTTPS at the Ingress or Gateway for outside traffic, and consider encrypting traffic between Services too, using a service mesh or application-level encryption.

Doors

Avoid raw NodePorts

Opening a high port on every machine widens your attack surface. Firewall it, or avoid it in production.

Identity

Prove who is calling

Do not rely only on network location. Use tokens or mutual TLS so a Service can verify that the caller is really who it claims to be.

Common ways Services are exposed by accident

  • A LoadBalancer Service created “temporarily” for a test and never removed, exposing an admin page or database to the internet.
  • A database exposed as a public LoadBalancer for convenience during a migration.
  • Selectors that are too broad, so a Service accidentally forwards traffic to Pods that were never meant to receive it.
  • Cloud firewall rules opened wide to make NodePort work.
  • A monitoring or dashboard Service exposed publicly without sign-in.
!
Common mistake

Assuming that “inside the cluster” means “safe.” If one Pod is compromised, an attacker there can try every Service in the cluster. Network policies and per-Service authentication limit how far one break-in can spread.

Segmenting with namespaces and policies

Use namespaces to group related Services, and combine them with network policies so that traffic between groups must be explicitly allowed. A good starting rule is “deny everything, then allow what each app needs.” It takes an afternoon to set up and pays back the first time something goes wrong.

15Monitoring, Logging, Metrics, and Troubleshooting

Because a Service is a set of rules and lists, not a running program, you watch it indirectly, through the parts that make it work.

What to watch

SignalWhere it comes fromWhat it tells you
Number of ready endpointsEndpointSlices, cluster state metricsHow many Pods can really serve traffic; zero means an outage
Request rate, errors, latencyApplication metrics, Ingress or mesh metricsWhat customers actually experience
DNS query volume and failuresCoreDNS metrics and logsWhether names resolve quickly and reliably
Rule update timekube-proxy metricsHow fast changes reach the machines; long times mean stale routes
Load balancer healthCloud provider metricsWhether the outside entrance is healthy and which machines it trusts
Pod restarts and readiness flapsCluster events and Pod statusInstability that causes traffic to jump on and off
Dropped connectionsNetwork plugin or mesh metricsNetwork policies or capacity problems

Logs and events

Services themselves do not write logs, but the components around them do. CoreDNS logs show name lookups. Ingress controllers log every web request, which is often the best record of customer traffic. Cloud load balancers can write access logs. Kubernetes events, for example about a load balancer that could not be created, appear on the Service object and are the first place to look when something is stuck in a pending state.

A calm way to troubleshoot

When “the Service does not work,” walk down the path from the caller to the Pod, one step at a time. Most problems are found in the first three questions.

flowchart TD
    START["Requests to the Service fail"] --> Q1{"Does the name resolve in DNS?"}
    Q1 -->|No| F1["Check spelling, namespace and CoreDNS health"]
    Q1 -->|Yes| Q2{"Does the Service list ready endpoints?"}
    Q2 -->|No| F2["Check selector labels, Pod readiness and Pod status"]
    Q2 -->|Yes| Q3{"Does targetPort match the app port?"}
    Q3 -->|No| F3["Correct the port numbers"]
    Q3 -->|Yes| Q4{"Do network policies allow the traffic?"}
    Q4 -->|No| F4["Add or fix the allow rule"]
    Q4 -->|Yes| F5["Check app logs, kube-proxy and network plugin health"]
Figure 7. A step-by-step path for finding why a Service is not working.

The usual suspects

  • Selector mismatch: a typo means zero Pods match, so the Service has no endpoints and every call fails.
  • Wrong target port: the app listens on one number and the Service forwards to another.
  • Pods not ready: the readiness check fails, so Pods are silently left out.
  • Wrong namespace: the caller uses a short name that resolves in its own namespace, where no such Service exists.
  • Pending load balancer: no cloud controller, no quota, or a permission problem.
  • Blocked by policy: a network policy or a cloud firewall quietly drops the traffic.
i
Tip

The single most useful habit: look at whether the Service has endpoints. If the list is empty, the problem is between the Service and the Pods. If it is full, the problem lies elsewhere. This one check splits the search in half.

16Design Patterns and Anti-Patterns

Patterns are habits shared by teams that run Services well. Anti-patterns are shortcuts that look harmless until they break.

Patterns that work

Pattern

Private by default

Give every workload a ClusterIP Service, and expose only the few that must be public, through a shared entry point.

Pattern

One Service per role

Give each distinct role its own Service and name, such as storefront, catalog, and payments, so ownership and permissions stay clear.

Pattern

Shared edge

Route many web apps through one Ingress or Gateway to reduce cost and manage certificates in one place.

Pattern

Name the dependency

Wrap outside systems, such as a managed database, in an ExternalName or selector-less Service so applications use a stable in-cluster name.

Pattern

Headless plus StatefulSet

Use this pair for databases and brokers that need stable, individually addressable members.

Pattern

Graceful shutdown

Make apps keep serving briefly after a stop signal, so rolling updates never drop a request.

Anti-patterns to avoid

ANTI-PATTERN 01Avoid
What it looks like

Hard-coding Pod addresses in configuration files, or copying a Service’s cluster IP into a program.

Why it hurts

Pod addresses change constantly, and a cluster IP changes if the Service is deleted and recreated. The program breaks at the next restart, often at night.

Do this instead

Always call the Service by its DNS name and let the cluster do the lookup.

ANTI-PATTERN 02Avoid
What it looks like

Creating a separate public LoadBalancer Service for every web app.

Why it hurts

Costs multiply, addresses sprawl, certificates are scattered, and each exposed load balancer is another door to defend.

Do this instead

Put web apps behind a shared Ingress or Gateway, and keep the Services behind it as ClusterIP.

ANTI-PATTERN 03Avoid
What it looks like

Running Pods without readiness checks and relying on the Service to “just know” when they are ready.

Why it hurts

Traffic is sent to Pods that are still starting or already broken, producing errors on every deployment and after every crash.

Do this instead

Define meaningful readiness checks that test that the app can really serve requests.

ANTI-PATTERN 04Avoid
What it looks like

Depending on plain Service load balancing to spread requests evenly over long-lived connections, such as gRPC or database pools.

Why it hurts

A Service balances when a connection is opened, not for each request. One long connection can send all its traffic to one Pod, leaving others idle.

Do this instead

Use a proxy or service mesh that balances each request, or use client-side balancing with a headless Service.

17Best Practices and Common Mistakes

A short checklist that saves a lot of late-night debugging.

Best practices

  • Use clear, consistent labels. A shared labeling scheme makes selectors simple and reduces accidental matches.
  • Name ports. Named ports let you change a port number in the Pod without editing every Service.
  • Always define readiness checks and, for slow starters, startup checks.
  • Handle shutdown gracefully so old Pods finish current work while the member list updates.
  • Prefer DNS over environment variables for discovery.
  • Run more than one Pod behind every important Service, spread across machines and zones.
  • Restrict traffic with network policies and start from “deny by default.”
  • Limit LoadBalancer Services and review them regularly for forgotten ones.
  • Keep Services in the same namespace as their Pods and use clear namespace boundaries.
  • Test failure. Delete a Pod under load and confirm that customers notice nothing.

Common mistakes

MistakeWhat happensBetter habit
Label typo in the selectorZero endpoints; every request failsCheck that endpoints exist after every change
Confusing port and targetPortConnections refused or timed outWrite both numbers down and match them to the app
Testing a ClusterIP from outside the clusterNothing respondsTest from a Pod inside, or use a temporary port-forward
Expecting ping to workLooks broken when it is fineTest the real port with a proper request
Ignoring the pending load balancerThe address never appearsRead the events on the Service for the cause
Deleting and recreating a ServiceNew cluster IP and a short outageUpdate in place whenever possible
Using the same label on unrelated PodsRequests reach the wrong appGive each app a unique identifying label
Not planning for many ServicesSlow updates in very large clustersConsider IPVS, nftables, or an eBPF network plugin

18Real-World and Industry Examples

These examples come from what projects and companies have said publicly. Details may have changed since.

The cluster’s own front door is a Service

Inside every Kubernetes cluster, a Service named kubernetes in the default namespace points at the API server. Controllers, monitoring agents, and operators running in Pods use it to reach the control plane without knowing which machine is currently active. The project uses its own building block for its most important connection.

Managed clouds and load balancers

On Amazon EKS, Google GKE, and Azure AKS, creating a LoadBalancer Service makes the platform build a real cloud load balancer and fill in its address. Teams commonly use one shared Ingress or Gateway for their many web apps and reserve direct LoadBalancer Services for special protocols. This split saves money and keeps the number of public doors small.

Replacing kube-proxy with eBPF

Cilium, a network plugin used by many organizations, can handle Service routing inside the Linux kernel using eBPF instead of kube-proxy. Google’s GKE Dataplane V2 is built on Cilium, and other managed services offer similar options. Large clusters adopt this to cut the delay and update cost of very long rule lists, while applications keep using ordinary Services.

MetalLB on bare metal

Companies running Kubernetes in their own data centers have no cloud to build load balancers. Projects like MetalLB fill the gap by announcing addresses from a reserved pool on the local network, so LoadBalancer Services get real, reachable addresses just as they would in a cloud.

Service meshes build on Services

Tools such as Istio and Linkerd take the ordinary Service and add smarter, request-level features: retries, timeouts, gradual traffic shifts, and encrypted connections between programs. They still use Services as the map of what exists, which shows how central the Service is to the whole ecosystem.

A typical online store

A store runs a storefront, a catalog, a cart, and a payment program. Each has a ClusterIP Service with a clear name. A shared Gateway with one cloud load balancer receives customer traffic and routes it by website address to the storefront and catalog Services. The cart calls payments by its short name, and the payment Service passes each request to a ready Pod. During a sale, the cart scales from three to thirty Pods, and the Service adds each new Pod as it becomes ready. No settings anywhere are edited by hand.

19Frequently Asked Questions

Q1In one sentence, what is a Kubernetes Service?
A Service gives a changing group of Pods one stable name and address, and shares incoming traffic across the healthy ones.
Q2What is the difference between a Pod and a Service?
A Pod runs your containers and is temporary. A Service is not a running program; it is a stable front, made of rules and a member list, that directs traffic to Pods.
Q3Does a Service create Pods?
No. Something else, usually a Deployment, creates Pods. The Service only finds them through labels.
Q4How does a Service know which Pods to use?
Through its selector, a label rule. Every ready Pod in the same namespace that matches the rule becomes a member, and the list updates automatically.
Q5Which Service type should I choose?
Use ClusterIP for internal traffic, a shared Ingress or Gateway in front of ClusterIP Services for websites, LoadBalancer for non-web protocols that must be public, and NodePort mostly for tests.
Q6Why is my LoadBalancer address stuck on pending?
Usually there is no cloud controller to create it, as on a laptop or a private data center, or the cloud account lacks quota or permission. Read the events on the Service to see the real cause, or install a tool like MetalLB.
Q7Why can I not ping a Service address?
The address is virtual and only exists as forwarding rules for the ports you defined. It does not answer ping. Test the actual port instead.
Q8How do Pods in different namespaces call each other?
Use the Service name with its namespace, such as payments.shop, or the full name ending in svc.cluster.local.
Q9What is a headless Service for?
It skips load balancing and lets DNS return the addresses of individual Pods. It is used for stateful systems such as databases, where members must find each other or clients must choose a specific member.
Q10Does a Service balance load evenly?
Roughly, per connection. It does not look at each request or the current load of each Pod. For long-lived connections or precise balancing, use a smarter proxy or a service mesh.
Q11Do I need an Ingress if I have Services?
Not for internal traffic. For public websites, an Ingress or Gateway adds host and path routing, shared load balancing, and certificate handling that plain Services do not provide.
Q12What happens to a Service if all its Pods are down?
The Service and its address still exist, but the member list is empty, so connections fail until a Pod becomes ready. That is why running several Pods and defining good readiness checks matters.
Q13Is kube-proxy still needed?
In most clusters, yes. Some network plugins, such as Cilium, can replace it by doing the same job in the kernel, but the Service you write looks exactly the same either way.

20Summary and Key Takeaways

Key Takeaways

  • A Service is a stable name and address in front of changing Pods. It solves the problem that Pod addresses die with the Pod, and it shares traffic across all healthy members.
  • Labels and selectors do the matching. The Service owns no Pods. It finds them through a selector, and a controller keeps the member list of ready Pods in EndpointSlices.
  • The virtual address is an illusion built from rules. kube-proxy, or an eBPF network plugin, rewrites traffic from the Service address to a chosen Pod, and CoreDNS provides the name.
  • The type decides who can reach it. ClusterIP is internal, NodePort opens a door on every machine, LoadBalancer adds a cloud entrance, ExternalName is an alias, and a headless Service gives direct access to Pods.
  • Use a shared Ingress or Gateway for websites. Keep most Services private, and expose only what must be public through a small number of well-protected doors.
  • Readiness, graceful shutdown, and policies make it reliable and safe. Define readiness checks, finish work before exit, restrict traffic with network policies, and check for endpoints first whenever something breaks.