Categories
DevOps Orchestration

Kubernetes Services Demo

Kubernetes services expose apps running as a set of Kubernetes pods using a single DNS name. In addition, Kubernetes services provide load balancing between the pods. Of course, I’ll demo how to manage services using kubectl. Keep reading to find out more.

Introduction

In Kubernetes Deployments Demo we used kubectl port-forward to expose app running as the deployment of several pods. Then, we discovered that deployment pods are not load-balanced and only a single pod serves the traffic.

In addition we saw in Kubernetes Pods Demo that pods live only once. Hence, pod ip is ephemeral. Then, of course, we can’t rely on it while connecting to an app running inside a pod. Seems like we need something that will act as a gateway to a set of pods. Pods may come and go, be scaled up or down. Still the app is accessible by its clients. Ideally, app clients don’t need to track app pods and their ips. They want to consume app endpoints using DNS resolvable name. That’s exactly what Kubernetes service provides in addition to load balancing between the pods.

Kubernetes Services Concepts

So we already know that Kubernetes service is a gateway to a set of pods. Of course, it has its own virtual ip address. However, unlike pods, services are not ephemeral. Also, we mentioned that services provide load balancing to their pods. But, how are pods associated with a service? Right. Using a label selector, similarly to Kubernetes deployments.

Kubernetes Service

There are several Kubernetes service types:

Kubernetes Service Types

ClusterIP

The service is reachable only inside Kubernetes cluster.

NodePort

The service is reachable by port on each Kubernetes cluster node via service name and a port.

LoadBalancer

The service is reachable externally. Cloud provider’s load balancer usually proxies to LoadBalancer service.

ExternalName

The service acts as a proxy for some external service.

Kubernetes Services Demo

It’s time for a Kubernetes services short demo. Before that, let’s go over demo prerequisites.

Demo Prerequisites

  • minikube
  • kubectl

Kubernetes Deployments fast rewind

We’ll base the demo on Kubernetes Deployments Demo we saw previously.

First, let’s create minikube multi-node cluster using:

minikube start --nodes 3 -p multinode-demo

Now, let’s create nginx deployment using below command:

$ kubectl create deploy nginx --image=nginx:1.13.2
deployment.apps/nginx created

Make sure nginx app is running in our minikube Kubernetes cluster:

$ kubectl get all -l app=nginx
NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-6d67674bb5-xd52w   1/1     Running   0          61s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           61s

NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-6d67674bb5   1         1         1       61s

Now, we would like to expose the deployment using Kubernetes service. We can of course declare nginx service using yaml. Though, this seems too daunting. So, what can we do? The answer is in the question 🙂 We can create Kubernetes service out of deployment using kubectl expose. Let’s see it in action:

$ kubectl expose deployment/nginx --port 8090 --target-port 80
service/nginx exposed

And of course, now we have Kubernetes service running:

$ kubectl get all -l app=nginx
NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-6d67674bb5-xd52w   1/1     Running   0          8m11s

NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/nginx   ClusterIP   10.110.111.105   <none>        8090/TCP   85s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           8m11s

NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-6d67674bb5   1         1         1       8m11s

Will you see nginx welcome screen if you navigate to http://localhost:8090/? No because, the service is exposed only internally. It’s running on virtual ip 10.111.105. What can we do to expose the services externally? Right, use port-forwarding:

$ kubectl port-forward service/nginx 8090:8090

Now, navigate to http://localhost:8090/ and you’ll see nginx welcome screen. Let’s stop port-forwarding for now (CTRL+C).

Declare Kubernetes services using yaml

Is there a way to see yaml of nginx Kubernetes service we created in the previous section? Of course. We can see yaml of any Kubernetes resource using kubectl get.

$ kubectl --kubeconfig ~/.kube/config get service/nginx -o yaml   
apiVersion: v1
kind: Service
metadata:
 creationTimestamp: "2021-12-11T13:40:38Z"
 labels:
   app: nginx
 name: nginx
 namespace: default
 resourceVersion: "7004"
 uid: 2882c5de-d3c8-402d-823a-104b582d0318
spec:
 clusterIP: 10.110.111.105
 clusterIPs:
 - 10.110.111.105
 ipFamilies:
 - IPv4
 ipFamilyPolicy: SingleStack
 ports:
 - port: 8090
   protocol: TCP
   targetPort: 80
 selector:
   app: nginx
 sessionAffinity: None
 type: ClusterIP
status:
 loadBalancer: {}

There’s a lot of runtime information we’ll not cover here. Above service yaml can be shortened to below one if you intend to store it in git, for instance.

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 8090
      targetPort: 80

I’ll just point out selector which should match the label app: nginx. It’s the same selector we specified in the deployment spec.

Of course, we could declare nginx Kubernetes service using yaml. Yet, I find kubectl expose and kubectl get trick a preferred way for generating service yaml.

Let’s now demo Kubernetes services concepts like pods load balancing and access by DNS name.

Kubernetes Services Concepts in Action

As we mentioned above, Kubernetes services clients can access them by service name. In addition, services provide load balancing for pods. Let’s see both concepts in action.

For this purpose, let’s create serve_hostname deployment. Its pods return pod name when they are accessed at port 80.

$ kubectl create deployment hostnames --image=k8s.gcr.io/serve_hostname --replicas=3
deployment.apps/hostnames created

Next, let’s expose the pods via Kubernetes service.

$ kubectl expose deployment hostnames --port 9090 --target-port 9376
service/hostnames exposed

Now, let’s run busybox pod in the same namepace where we ran hostnames pods.

kubectl run --restart=Never busybox --image=gcr.io/google-containers/busybox -- sleep 7200

As you can see, busybox is going to sleep for 2 hours:

$ kubectl exec pod/busybox -- ps 
PID   USER     COMMAND
    1 root     sleep 7200
   41 root     ps

Now, let’s access hostnames service a few times by service name from busybox pod using wget and print the result to stdout.

# demonstrate DNS resolution using wget in verbose mode
$ kubectl exec pod/busybox -- wget hostnames:8070 -O -
Connecting to hostnames:8070 (10.103.105.38:8070)
-                    100% |*******************************|    26   0:00:00 ETA
hostnames-f86f9ccc9-t4w8h

# demonstrate load balancing using wget in quiet mode
$kubectl exec pod/busybox -- wget hostnames:8070 -qO -
hostnames-f86f9ccc9-t4w8h
$ kubectl exec pod/busybox -- wget hostnames:8070 -qO -
hostnames-f86f9ccc9-nd4tj
$ kubectl exec pod/busybox -- wget hostnames:8070 -qO -
hostnames-f86f9ccc9-876nq

As you can see, DNS resolution works because hostnames service name is resolved to the virtual ip of the service. Next, load balancing works because different pods serve web requests directed at hostnames service. Nice! See more details about debugging Kubernetes services at Debug Services.

Note that, Kubernetes service default type is ClusterIP. That’s why load balancing applies only to internal service requests. In our case internal app wget in busybox pod accesses hostnames service. You may wonder what about external load balancing. For example, in case a user or another app tries to access Kubernetes service from outside the cluster. That’s a good question. We’ll see how to provide external access to services along with load-balancing in future posts. Then, we’ll cover Ingress and see examples in the cloud of LoadBalancer services.

Let’s clean all demo resources using kubectl delete [resource_name]. Note, that while deleting a deployment deletes its pods, the service stays. You have to delete it using kubectl delete svc name.

Finally, let’s stop our minikube cluster.

minikube stop -p multinode-demo

Summary

That’s it about Kubernetes services. Stay tuned for more Kubernetes related posts. And, as always, feel free to share and comment.

Bonus:

Recommended Kubernetes courses on Pluralsight:

Sign up using this link to get exclusive discounts like 50% off your first month or 15% off an annual subscription)

Recommended Kubernetes books on Amazon: