Service
Learn how to create a Kubernetes service and how service discovery works.
This section continues from the previous section - make sure you do the tutorial in sequence.
DeploymentService
Each Pod has a unique IP address - but the address is ephemeral. The Pod IP addresses are not stable and it can change when Pods start and/or restart. Moreover, if you have a Deployment that starts multiple Pods, and you need to consume an API from the Pods, you do not want to connect using an ephemeral IP address. Usually, you'll need to add a load balancer to distribute traffic to each individual instance.
In Kubernetes, a Service is a Network (L4) Load Balancer that'll provide you a single stable Service IP (and hostname) to load balance the traffic to a set of pods selected by using labels.
Service YAML
You can create a Service and deploy into Kubernetes using the kubectl
CLI like in the Hello World tutorial. That's great to get a feel of Kubernetes. However, it's best that you create a YAML file first, and then deploy the YAML file.
# Under the helloworld-springboot-tomcat directory , create a k8s directory
mkdir k8s/
kubectl create service clusterip helloworld \
--tcp=8080:8080 \
--dry-run \
-o yaml > k8s/service.yaml
You can open the k8s/service.yaml
file to see the content. Below is a version of the YAML file that's slimmed down to the bare minimum.
# API Version and Kind are important to indicate the type of resource
apiVersion: v1
kind: Service
metadata:
# Every Kubernetes resource has a name that's unique within a namespace
name: helloworld
# Every Kubernetes can have labels, label key/value pairs can be queried later.
labels:
app: helloworld
spec:
# The type of the service - this one is an internal only service
type: ClusterIP
# Any Pods that matches these labels will be load balanced through
# this Service (L4 load balancer)
selector:
app: helloworld
ports:
# A port can have a name, it can be renamed to be more descriptive
# such as "http", "jmx", "metrics", etc.
- name: 8080-8080
# The port to listen on by the Service (L4 Load Balancer)
port: 8080
# The port to forward traffic to on the destination Pod
targetPort: 8080
# TCP or UDP protocol
protocol: TCP
Deploy
Use kubectl
command line to deploy the YAML file:
kubectl apply -f k8s/service.yaml
Verify that the service is configured:
kubectl get svc helloworld
You should see that the Service has a Cluster IP address:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
helloworld ClusterIP ... <none> 8080/TCP 7s
Service Discovery
In a traditional Spring Cloud application, service discovery is done using an external service registry like Eureka, and client-side load balancing with Ribbon.
In Kubernetes, the Kubernetes Service itself can act as the service registry:
You can discover all the endpoints associated with a service
Kubernetes Service's Cluster IP is a built-in L4 load balancer, and it's automatically associated with a DNS name
Endpoints
Each Service has a selector
block that is used to find Pods with matching labels and enlisting them as an Endpoint of the Service (or, you can think of it as a backend instance of a load balancer).
In the example above, the selector is app: helloworld
, you can also find the matching Pods using kubectl
:
# Scale out the # of instances so we can see more than one pod
kubectl scale deployment helloworld --replicas=2
# Find Pods using a selector
kubectl get pods -lapp=helloworld
Describe the Service to see the Endpoint IP addresses that it's currently enlisted,, and look for the Endpoints
output:
kubectl describe svc helloworld
It is possible to continue to use Ribbon for client-side load balancing by retrieving these endpoints using the Kubernetes API. This is an advanced usage and not covered in this documentation. However, you can achieve a similar result if you use Spring Cloud Kubernetes to replace Spring Cloud Eureka.
DNS Name
The newly created Kubernetes Service is also a L4 Load Balancer, and it can be accessed using the Cluster IP, or the hostname helloworld
, or a Fully Qualified Name (FQN) of helloworld.default.svc.cluster.local
.
This service is currently only accessible from within the Kubernetes cluster. I.e., there is no public IP address. You can start a new Pod within the cluster that has a shell, and execute commands within the cluster. This accurately simulates a client application sending request to another backend service.
nginx
container image has a shell that we can use, so deploy one instance of nginx
.
kubectl create deployment nginx --image=nginx
Attach to the nginx
Pod:
POD_NAME=$(kubectl get pods -lapp=nginx -o jsonpath='{.items[0].metadata.name}')
kubectl exec -ti ${POD_NAME} /bin/bash
From within the Pod, curl
the service:
# From within the nginx Pod
curl http://helloworld:8080
exit
Last updated
Was this helpful?