top of page
Writer's pictureRafael Natali

Kubernetes Network In Action - 2/3

Updated: Feb 20

This is the second of three articles explaining and detailing the Kubernetes Network model with a hands-on approach. In the first article, I spoke about Pod-to-Pod communication. This article will focus on Pod-to-Service communication, and the next one will discuss Ingress / Ingress Controllers. These articles are based on a repository I created which contains more examples and content. I invite you to review the repo at https://github.com/rafaelmnatali/kubernetes.



Pod to Service communication

A Service serves as a central entry point that allows Pods to communicate with one another. For instance, when a group of Pods (referred to as "backends") offers functionality to other Pods (known as "frontends") within your cluster, the backend Service will furnish the frontend with a list of backend Pods that the frontend can establish connections with.

There are four Kubernetes Service types:


ClusterIP

ClusterIP is is the default type of Service. Kubernetes will assign an IP address from a pool of IP addresses that your cluster has reserved for that purpose.

Deploy a NGINX web server, and let's see how the ClusterIP works:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      initContainers:
      - name: init
        image: busybox
        command: ['sh', '-c', 'echo "Welcome to the home page of host $(hostname)!" > /usr/share/nginx/html/index.html']
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      containers:
      - name: nginx
        image: nginx
        ports:
        - name: http-web-svc
          containerPort: 80
          protocol: TCP
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: default
spec:
  selector:
    app: nginx
  ports:
  - name: http-web-svc
    protocol: TCP
    port: 80
    targetPort: http-web-svc

List of Services:

NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes      ClusterIP   10.96.0.1        <none>        443/TCP   197d
nginx-service   ClusterIP   10.110.110.219   <none>        80/TCP    6s

Use the nicolaka/netshoot image to execute network validations.

kubectl run tmp-shell --rm -i --tty --image nicolaka/netshoot -- /bin/bash

First, use nslookup to query the DNS for the Service name:

tmp-shell:~# nslookup nginx-service
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   nginx-service.default.svc.cluster.local
Address: 10.110.110.219

The DNS returns the IP address as we saw in the previous command.

We can use the curl command to send an HTTP request to the Service name.

tmp-shell:~# curl nginx-service
Welcome to the home page of host nginx-5c7575f557-j2pzq!
tmp-shell:~# curl nginx-service
Welcome to the home page of host nginx-5c7575f557-vbglc!
tmp-shell:~# curl nginx-service
Welcome to the home page of host nginx-5c7575f557-82mx4!

The NGINX Service is associated with three Pods (as shown in the ENDPOINTS column). In this particular example, the Service directed the request to a different Pod each time:

$ kubectl get endpointslices.discovery.k8s.io                               
NAME                  ADDRESSTYPE   PORTS   ENDPOINTS                             
kubernetes            IPv4          8443    192.168.49.2                          
nginx-service-5pf9n   IPv4          80      10.244.3.46,10.244.3.47,10.244.3.48   17m

Using Kubeshark, it's possible to have a visual representation of the network traffic.

The tmp-shell Pod does DNS requests to resolve the A/AAAA records for nginx-service.default.svc.cluster.local. After that it sends a GET to the Service in port 80 and then it receives the answer from 10.244.3.48.


Headless Service

Headless Service is created by explicitly setting ClusterIP to None when creating the Service. That does not allocate an IP address or forward traffic. In my opinion, the main use case is for Stateful applications, where the headless is responsible for the network identity of the Pods.

How is the IP discovery different from ClusterIP to Headless?

Deploy a Headless Service for our NGINX:

apiVersion: v1
kind: Service
metadata:
  name: nginx-headless-service
  namespace: default
spec:
  clusterIP: None 
  selector:
    app: nginx
  ports:
  - name: http-web-svc
    protocol: TCP
    port: 80
    targetPort: http-web-svc

List of Services:

NAME                     TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)  
kubernetes               ClusterIP   10.96.0.1        <none>        443/TCP   
nginx-headless-service   ClusterIP   None             <none>        80/TCP    
nginx-service            ClusterIP   10.110.110.219   <none>        80/TCP    

Use the nicolaka/netshoot image to execute network validations.

kubectl run tmp-shell --rm -i --tty --image nicolaka/netshoot -- /bin/bash

Run nslookup to query both services:

tmp-shell:~# nslookup nginx-service
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   nginx-service.default.svc.cluster.local
Address: 10.110.110.219
tmp-shell:~# nslookup nginx-headless-service
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   nginx-headless-service.default.svc.cluster.local
Address: 10.244.3.46
Name:   nginx-headless-service.default.svc.cluster.local
Address: 10.244.3.47
Name:   nginx-headless-service.default.svc.cluster.local
Address: 10.244.3.48

In the first case, the ClusterIP returns its own IP address. The Headless Service returns the IP address of each Pod.


Summary

In this article, I experimented with two types of Kubernetes Services — ClusterIP, which provides an IP address and load-balancing, and headless Service, which don’t offer load-balancing and returns a list of all Pods associated. The article explores how you can connect to your applications using these two Services.

A Service is the preferred method of exposing a network application running as one or more Pods in your cluster. One of the key advantages of Kubernetes Services is that you don’t need to modify your existing application to use a different service discovery mechanism.

In the third and final part of this series, I will discuss Ingress and Ingress Controllers.


References

60 views0 comments

Comments


bottom of page