How to expose a Pod internally in Kubernetes

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.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top