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.
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.
selector
- list of labels to find target Podsports
- list of ports to listen onname
- port name within Kubernetesport
- port the Service listens ontargetPort
- port on the Pod where traffic gets sentPods 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
andversion
are typically used for application 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
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
anddescribe
commands are the same for all objects; Services have the aliassvc
The Service has its own IP address, and that is static for the life of 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
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.
LoadBalancer Services integrate with the platform they're running on to get a real IP address. In a managed Kubernetes service in the cloud you'll get a unique public IP address for every Service, integrated with a cloud load balancer to direct traffic to your nodes. In Docker Desktop the IP address will be localhost
; in k3d it will be a local network address.
NodePorts don't need any external setup so they work in the same way on all Kubernetes clusters. Every node in the cluster listens on the specified port and forwards traffic to Pods. The external port number must be >= 30000 - a security feature so Kubernetes components don't need to run with elevated privileges on the node.
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 :)
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
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?
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