Author : MD TAREQ HASSAN | Updated : 2021/04/30
What is a Service in Kubernetes
- A Service in Kubernetes is an abstraction which defines a logical set of Pods and a policy by which to access them
- An abstract way to expose an application running on a set of Pods as a network service
- Services enable decoupling of Pods
- A Service is defined using YAML (preferred) or JSON, like all Kubernetes objects
- Service Acts as a load balancer for Pods (distributing load to pod ReplicaSet)
- Service abstracts communication between Pods with IP address and DNS names
- Pods only need to know Service IP address and DNS names instead of communicating directly with each other
- If a Pod dies, service will still serve using new Pod (and the other Pod would not know that a pod just died). This this way, communication is not disrupted
A service would get a static IP and a persistent DNS name and would manage a set of pods. Applications (pods) would communicates with each other and with outside clients via their associated services.
Why Service is Needed
Pods are ephemeral
- Ephemeral means “lasting for a very short time”
- Pods are nonpermanent resources, they may die frequently and then new pod (instance) will be created
- Pods are fungible, they can be replaced easily
Lets say a set of 3 pods (pod0, pod1, pod2) representing a backend app where all 3 pods will have IP address and combindly they would constitute a ReplicaSet. Fontend apps uses that backend app (dependency). Frontend was communicating with pod0, but after some time pod0 dies and replaced by pod3. Pod3 would have a new (different) IP address that means frontend would not be able to funstion because pod0 is no longer available.
Enter K8s Service - a logical grouping of pods (i.e. 3 pods that constitute a backend app in our example) in way that dependent entities (i.e. a frontend app in our example) do not need to know about specific pod. Rather the pods will sit behind the service and the service will act as a load balancer and handle incoming requests.
- Service would maintain an entry called “endpoint” for each pod
- An endpoint is combination of pod IP and port
- pod0 -> 10.8.0.4:80
- pod1 -> 10.8.0.5:80
- pod2 -> 10.8.0.6:80
- Service would have a collection of “3 endpoints” for 3 pods
- An endpoint is combination of pod IP and port
- If a pod dies or replaced by a new pod, service would update it’s endpoints (collection)
- Service communicates will pods using endpoint
- Incoming requests will be distributed to all pods accordingly using endpoint
- Any request to application pod will go through a service
So a service acts as:
- API gateway for pods: pods are created or moved around, the service is always reachable at (internal static) IP address
- Load balancer for pods: traffic sent to the service’s IP address is load balanced to the pods
- Service discovery: services are assigned internal DNS entries by the Kubernetes DNS service (service DNS name that does not change)
IP Address and DNS Name
- A service gets a single DNS name that does not change
- Services get static virtual IP addresses
- Virtual in a sense that those IP addresses are only visible inside K8s cluster (not routable from outside of cluster, routable within the cluster network)
- It’s called Service CIDR
- Service CIDR should be planned before creating cluster. See: Design IP Address Spaces
- Kubernetes assigns service a virtual IP address, that IP address is called “ClusterIP”
- DNS names will resolve to the ClusterIP assigned for the Service
Services Types
Kubernetes ServiceTypes allow you to specify what kind of Service you want (default is ClusterIP). Type values and their behaviors are:
- ClusterIP:
- Exposes the Service on a cluster-internal IP (a virtual IP is assigned from service CIRD and gets DNS name)
- Choosing this value makes the Service only reachable from within the cluster
- This is the default ServiceType (when type is not mentioned in manifest or resource creation yaml/json file)
- NodePort:
- Exposes the Service on each Node’s IP at a static port (the NodePort)
- A ClusterIP Service, to which the NodePort Service routes, is automatically created
- You’ll be able to contact the NodePort Service, from outside the cluster, by requesting
<NodeIP>:<NodePort>
- LoadBalancer:
- Exposes the Service externally using a cloud provider’s load balancer (in case of Azure -> Azure Load Balancer)
- NodePort and ClusterIP Services, to which the external load balancer routes, are automatically created
- ExternalName:
- An ExternalName Service is a special case of Service that does not have selectors and uses DNS names instead
- Maps the Service to the contents of the externalName field (e.g.
foo.bar.example.com
) by returning a CNAME record with its value - No proxying of any kind is set up
Defining a Service
- A Service in Kubernetes is a REST object, similar to a Pod
- Like all of the REST objects, a Service definition is POSTed to the API server to create a new instance
- The name of a Service object must be a valid DNS label name.
Example: suppose you have a set of Pods where each listens on TCP port 9376 and contains a label app=MyApp:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
This specification creates a new Service object named “my-service” (defaults to type: ClusterIP
), which targets TCP port 9376
on any Pod with the app=MyApp
label.
Another example
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app: MyApp
ports:
# By default and for convenience, the `targetPort` is set to the same value as the `port` field.
- port: 80
targetPort: 80
# Optional field
# By default and for convenience, the Kubernetes control plane will allocate a port from a range (default: 30000-32767)
nodePort: 30007
How Does a Service Select Pods?
- Manifest file (or resource definition file) of a pod has “selector” label in “spec” section
- The “spec” section of a service specification (or service manifest file) also has
- Selector label: similar to pod’s selector label
- Target ports: used to create enpoint mappings
- The controller for the Service selector continuously scans for Pods that match its selector and puts (or wraps) those pods behind that service
- Suppose we have a set of Pods where each listens on TCP port
9376
and contains a label app=MyApp - Now we created a new Service object named “my-service”, which targets TCP port
9376
on any Pod with theapp=MyApp
label - The controller for the Service selector scans for Pods that match
app=MyApp
label, and then POSTs any updates to an Endpoint object also named “my-service” which puts all pods withapp=MyApp
label in a group and from now that pod group (pod ReplicaSet) will managed by “my-service” Service
Points To Be Noted
- Pods are always stay behind (or wrapped by) a service
- Client of an application (as set of pods) does not need to know about the pods, because it communicates with service and service forwards request to application pods accordingly
- Services without selectors:
- Services most commonly abstract access to Kubernetes Pods, but they can also abstract other kinds of backends
- you can define a Service without a Pod selector
- When service has no selector, the corresponding Endpoints object is not created automatically. You can then manually map the Service to the network address and port where it’s running, by adding an Endpoints object manually
- See: K8s Services without selectors