Kubernetes Course Labs

Networking Pods with Services

Every Pod has an IP address which other Pods in the cluster can reach, but that IP address only applies for the life of the Pod - replace the Pod and the new one will have a different IP address.

Services provide a consistent IP address linked to a DNS name, so you can send traffic to a name rather than an IP address. You'll always use Services for routing internal and external traffic into Pods.

Services and Pods are loosely-coupled: traffic comes into the Service, and the Service finds a Pod to send it onto using a label selector.

API specs

Service definitions have the usual metadata. The spec needs to include the network ports and the label selector:

apiVersion: v1
kind: Service
metadata:
  name: whoami
spec:
  selector:
    app: whoami
  ports:
    - name: http
      port: 80
      targetPort: 80

The ports are where the Service listens, and the label selector can match zero to many Pods.

Pod YAML

Pods need to include matching labels to receive traffic from the Service.

Labels are specified in the object metadata:

apiVersion: v1
kind: Pod
metadata:
  name: whoami
  labels:
    app: whoami
spec:
  # ...

Labels are abitrary key-value pairs used for storing small pieces of useful data. You can use any keys you like - app, component and version are typically used for application Pods.

Run sample Pods

Start by creating some simple Pods from definitions which contain labels:

kubectl apply -f labs/services/specs/pods

You can work with multiple objects and deploy multiple YAML manifests with Kubectl

📋 Check the status for all Pods, printing all the IP addresses and labels.

kubectl get pods -o wide --show-labels

The Pod name has no affect on networking, Pods can't find each other by name. Try running a DNS lookup inside the sleep Pod to find the whoami Pod:

kubectl exec sleep -- nslookup whoami

Deploy an internal Service

Kubernetes provides different types of Service for internal and external access to Pods.

ClusterIP is the default and it means the Service gets an IP address which is only accessible within the cluster - it's for components to communicate internally.

📋 Deploy the Service from labs/services/specs/services/whoami-clusterip.yaml and print its details.

kubectl apply -f labs/services/specs/services/whoami-clusterip.yaml

Print the details:

kubectl get service whoami

kubectl describe svc whoami

The get and describe commands are the same for all objects; Services have the alias svc

The Service has its own IP address, and that is static for the life of the Service.

Use DNS to find the Service

Kubernetes runs a DNS server inside the cluster and every Service gets an entry, linking the IP address to the Service name. Now you will get a response if you do the same DNS lookup:

kubectl exec sleep -- nslookup whoami

This gets the IP address of the Service from its DNS name. The first line is the IP address of the Kuberentes DNS server itself.

Now the Pods can communicate using DNS names:

kubectl exec sleep -- curl -s http://whoami

📋 Recreate the whoami Pod and the replacement will have a new IP address - but try the cURL command and you'll see the service resolution with DNS still works.

Check the current IP address then delete the Pod:

kubectl get pods -o wide -l app=whoami

kubectl delete pods -l app=whoami

You can use label selectors in Kubectl too - labels are a powerful management tool

Create a replacement Pod and check its IP address:

kubectl apply -f labs/services/specs/pods

kubectl get pods -o wide -l app=whoami

The Service IP address doesn't change, so if clients cache that IP they'll still work. Now the Service routes traffic to the new Pod:

kubectl exec sleep -- nslookup whoami

kubectl exec sleep -- curl -s http://whoami

Understanding external Services

There are two types of Service which can be accessed outside of the cluster: LoadBalancer and NodePort.

They both listen for traffic coming into the cluster and route it to Pods, but they work in different ways. LoadBalancers are easier to work with, but not every Kubernetes cluster supports them.

In this course we'll deploy both LoadBalancers and NodePorts for all our sample apps so you can follow along whichever Kubernetes distribution you're using.

Platform | LoadBalancer | NodePort --- | --- | --- | Docker Desktop | ✔ | ✔ K3s | ✔ | ✔ K3d | 🌓 | ✔ AKS, EKS, GKE etc. | ✔ | ✔ Kind | ❌ | ✔ Minikube | ❌ | ✔ Microk8s | ❌ | ✔ Bare-metal | ❌ | ✔

If you're running your own cluster and don't have LoadBalancer support you can add it with MetalLB, but that's not in scope for this course :)

Deploy an external Service

Here are two Service definitions to make the whoami app available outside the cluster:

You can deploy both:

kubectl apply -f labs/services/specs/services/whoami-nodeport.yaml -f labs/services/specs/services/whoami-loadbalancer.yaml

📋 Print the details for the services - both have the label app=whoami.

kubectl get svc -l app=whoami

If your cluster doesn't have LoadBalancer support, the EXTERNAL-IP field will stay at <pending> forever

External Services also create a ClusterIP, so you can access them internally from Pods.

You always need to use the Service port for communication:

kubectl exec sleep -- curl -s http://whoami-lb:8080

kubectl exec sleep -- curl -s http://whoami-np:8010

The Services all have the same label selector, so they all direct traffic to the same Pod

Now you can call the whoami app from your local machine:

# either
curl http://localhost:8080

# or
curl http://localhost:30010

If you're not running Kubernetes on your local machine then you'll need to use a different address - use the node's IP address for NodePort access or the EXTERNAL-IP address field for the LoadBalancer

Lab

Services are a networking abstraction - they're like routers which listen for incoming traffic and direct it to Pods.

Target Pods are identified with a label selector, and there could be zero or more matches.

Create new Services and whoami Pods to test these scenarios:

What happens? How can you check if a Service has found any matching Pods to use as targets?

Stuck? Try hints or check the solution.


Cleanup

Every YAML spec for this lab adds a label kubernetes.courselabs.co=services .

That makes it super easy to clean up, by deleting all those resources:

kubectl delete pod,svc -l kubernetes.courselabs.co=services