Service
Service is a core concept in Kubernetes. By creating a Service, you can provide a unified entry point for a group of container applications that share the same function, and distribute incoming requests to the individual container applications on the backend.
A Simple Example
This example maps port 80 of a Service to Pods that carry the app: nginx label.
1 | apiVersion: v1 |
spec.selector: Selects which Pods traffic should be forwarded to, based on labels.
spec.ports[].port: The port that this Service will expose. The value must be an integer.
spec.ports[].targetPort: The port number or port name of the target Pod. If a name is used, it must conform to IANA_SVC_NAME. If not specified, targetPort defaults to the same value as port.
For more Service Spec configuration options, refer to the official API Reference.
Run the following command to create a Service:
1 | kubectl apply -f https://raw.githubusercontent.com/chengqing-su/kubernetes-learning/master/service/nginx-service.yaml |
The result looks like this:

Service Types (How Services Are Accessed)
In the screenshot above, you can see that Services have a type. The type can be specified via spec.type, and there are four options: ClusterIP, NodePort, LoadBalancer, and ExternalName.
| Type | Description |
|---|---|
| ClusterIP | The default Service type. Exposes the Service on a cluster-internal IP. With this type, the Service is only accessible from within the cluster. |
| NodePort | Exposes the Service on each Node’s IP at a static port (NodePort). |
| LoadBalancer | Exposes the Service externally using a cloud provider’s load balancer. |
| ExternalName | Maps the Service to the contents of the externalName field (e.g. foo.bar.example.com) by returning a CNAME record. |
Why Do We Need Services?
To better understand Services, let’s create a Deployment with the following manifest:
1 | apiVersion: apps/v1 |
Create the Deployment with the following command:
1 | kubectl apply -f https://raw.githubusercontent.com/chengqing-su/kubernetes-learning/master/service/nginx-deployment.yaml |
The result is as follows:

At this point we can see that Endpoints now has values — these IP addresses belong to the Pods created by the Deployment.
Suppose we want to expose the application managed by this Deployment to another application A inside the cluster. Application A could access it using the Pod IPs directly, or it could go through the Service.
However, applications are constantly being upgraded and iterated, and Pods were never designed to be permanent objects. Pods will eventually die, and once they do, they are not brought back to life.
Let’s try updating the Nginx application above. Run the following command to upgrade nginx to 1.17. Note: it is not recommended to use this approach to upgrade any application in a production environment.
1 | kubectl set image deployment nginx-deployment nginx=nginx:1.17 |
The result is as follows:

The Endpoints have changed — the Pods previously created by the Deployment have been deleted, and Endpoints now points to the new Pods. If Application A was accessing the application using the old Pod IPs, it would now need to update its target IP addresses.
A Service is an abstraction that defines a logical set of Pods and a policy for accessing them (this pattern is sometimes referred to as a microservice). Our actual applications run inside Pods, and Pods are inherently unstable. Relying on direct Pod-to-Pod communication carries a significant maintenance burden. A Service, by contrast, is relatively stable and provides a consistent interface for other applications to rely on. This also helps decouple consumers from individual Pods.
Headless Service
Sometimes we do not need the default load-balancing behavior and a Service IP that a Service provides, or another application needs to discover the individual instances behind a Service. You can set spec.clusterIP to None to create a Headless Service.