When we create a Pod in Kubernetes, it has assigned a cluster-wide private IP address, which will be accessible by any other pod in the cluster. No matter in which node or host it is deployed while is within the same cluster. But when the pod dies, it will get a new IP assigned which may drive to problems in the network when other resources are connecting to that pod. That’s why Kubernetes introduced how to expose a pod internally in Kubernetes regardless its private IP.
What’s a Service
A Kubernetes Service is an abstraction which defines a logical set of Pods running somewhere in your cluster, that all provide the same functionality. When created, each Service is assigned a unique IP address (also called clusterIP). This address is tied to the lifespan of the Service, and will not change while the Service is alive. Pods can be configured to talk to the Service, and know that communication to the Service will be automatically load-balanced out to some pod that is a member of the Service.
How a Pod is added to a Service
Pods are exposed through EndpointSlices. The Service’s selector will be evaluated continuously and the results will be POSTed to an EndpointSlice that is connected to the Service using a labels. When a Pod dies, it is automatically removed from the EndpointSlices that contain it as an endpoint. New Pods that match the Service’s selector will automatically get added to an EndpointSlice for that Service.
How to create a Service to expose a Pod.
We can use the expose
option within kubectl
command to create it. My personal favourite option is to export that yaml as a file, modify it to satisfy my needs and then apply
that file.
In this example we already have a pod called nginx-pod
which is running a Nginx service on port 80. We are gonna create a new service called nginx-service
which will expose that pod on port 80.
controlplane $ k get po
NAME READY STATUS RESTARTS AGE
nginx-pod 1/1 Running 0 3m52s
controlplane $ k expose pod nginx-pod --port=80 --target-port=80 --dry-run=client -oyaml > service.yaml
controlplane $ cat service.yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx-pod
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
status:
loadBalancer: {}
controlplane
As we can see, we created the service giving the pod name; however it’s not using it. The Service just take the pod to retrieve its selector app: nginx
to use it in the service. Thanks to this, every pod that is created with that label, will be added as an endpoint to the Service taking its private IP.
As we want to give it another name. We are gonna edit the file and change the name to nginx-service
in the metadata.name
section. Then we will apply that file.
controlplane $ vim service.yaml
controlplane $ k apply -f service.yaml
service/nginx-service created
controlplane $ k get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 26d
nginx-service ClusterIP 10.99.122.67 <none> 80/TCP 6s
controlplane $ k describe service nginx-service
Name: nginx-service
Namespace: default
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.99.122.67
IPs: 10.99.122.67
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 192.168.1.4:80
Session Affinity: None
Events: <none>
controlplane $
As we can see, we already have the service created and the endpoint has been automatically added. Now if our pod dies and a new one comes to life, it will be automatically added to the service and we won’t need to change the endpoint in the applications that are using it. If we look at the Pod description we will see how the IPs are the same
controlplane $ k describe po nginx-pod
Name: nginx-pod
Namespace: default
Priority: 0
Service Account: default
Node: node01/172.30.2.2
Start Time: Wed, 08 May 2024 10:08:43 +0000
Labels: app=nginx
Annotations: cni.projectcalico.org/containerID: 15c844a02dfd1a5b293f640bfa552fe0c4b30a0bc677d780847b7d75d4b658af
cni.projectcalico.org/podIP: 192.168.1.4/32
cni.projectcalico.org/podIPs: 192.168.1.4/32
Status: Running
IP: 192.168.1.4
IPs:
IP: 192.168.1.4
Also if we get more pods with that label, they will be automatically load-balanced by the service.
We can check if the service is working by using a curl command to the Service IP and the assigned port.
controlplane $ curl http://10.99.122.67:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
Note that if we change the label in the pod, it will be removed from the service and won’t be available anymore.
If you want to know more about Kubernetes, read our articles and visit the official documentation.