ClusterIP Service
Creating a ClusterIP Service
We'll use the deployment created in the previous section to create applications. Then, we'll use a Service to route traffic to the Pods created by the Deployment.
Navigate to the simple-service
directory:
cd bootstrapping-with-kubernetes-examples/deploy/simple-service
The service.yaml
file in this directory contains the following configuration:
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
type: ClusterIP
selector:
app: simple-deployment
ports:
- protocol: TCP
port: 8000
targetPort: 8000
Start the deployment and service with the following commands:
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
Here's a sample output:
$ kubectl apply -f deployment.yaml
deployment.apps/simple-deployment created
$ kubectl apply -f service.yaml
service/backend-service created
Verify if the service and deployment are created:
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
simple-deployment 3/3 3 3 10m
$ kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
simple-deployment-794f78c89-9h7jh 1/1 Running 0 10m app=simple-deployment,pod-template-hash=794f78c89
simple-deployment-794f78c89-hs2s9 1/1 Running 0 10m app=simple-deployment,pod-template-hash=794f78c89
simple-deployment-794f78c89-tgnhl 1/1 Running 0 10m app=simple-deployment,pod-template-hash=794f78c89
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
backend-service ClusterIP 10.98.60.140 <none> 8000/TCP 11m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 20m
Let's send a request to the Service.
To send request to a ClusterIP Service, we need to be inside the Kubernetes cluster. So we'll use the kubectl
command to run a Pod with interactive shell:
kubectl run -i --tty --rm debug --image=alpine -- sh
Install curl
apk add curl
Send a request to the Service:
curl -i http://backend-service:8000/rest/v1/health/
Here's the output:
$ kubectl run -i --tty --rm debug --image=alpine -- sh
If you don't see a command prompt, try pressing enter.
/ #
/ # apk add curl
fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/community/x86_64/APKINDEX.tar.gz
(1/10) Installing ca-certificates (20240226-r0)
(2/10) Installing brotli-libs (1.1.0-r2)
(3/10) Installing c-ares (1.28.1-r0)
(4/10) Installing libunistring (1.2-r0)
(5/10) Installing libidn2 (2.3.7-r0)
(6/10) Installing nghttp2-libs (1.62.1-r0)
(7/10) Installing libpsl (0.21.5-r1)
(8/10) Installing zstd-libs (1.5.6-r0)
(9/10) Installing libcurl (8.8.0-r0)
(10/10) Installing curl (8.8.0-r0)
Executing busybox-1.36.1-r29.trigger
Executing ca-certificates-20240226-r0.trigger
OK: 13 MiB in 24 packages
/ #
/ #
/ # curl -i http://backend-service:8000/rest/v1/health/
HTTP/1.1 200 OK
date: Thu, 04 Jul 2024 04:48:21 GMT
server: uvicorn
content-length: 15
content-type: application/json
{"status":"ok"}/ #
/ #
Here's a breakdown of what happened here:
- Kubernetes has a built-in DNS Server that creates DNS records for the Services. The resolution happens by the Service name. In this case, the Service name is
backend-service
. - When you create a Service, you spcify a
selector
field. Based on this, the endpoint slice controller creates Endpoint objects. The Endpoint object contains the IP addresses of the Pods that match the selector. You can see the Endpoint object created for the Service using the following command:
$ kubectl get endpoints backend-service
NAME ENDPOINTS AGE
backend-service 192.168.189.66:8000,192.168.189.67:8000,192.168.235.130:8000 38m
- You can see to which Pods the Service is routing the traffic. Run the following command to see the IP addresses of the Pods:
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
simple-deployment-794f78c89-9h7jh 1/1 Running 0 39m 192.168.189.66 worker2 <none> <none>
simple-deployment-794f78c89-hs2s9 1/1 Running 0 39m 192.168.189.67 worker2 <none> <none>
simple-deployment-794f78c89-tgnhl 1/1 Running 0 39m 192.168.235.130 worker1 <none> <none>
- Along with this a DNS record for the Service is created by the DNS server.
- When you send a curl http://backend-service:8000/rest/v1/health/ request, the DNS server resolves the Service name to the IP addresses of the Pods. The request is then routed to one of the Pods.
Understanding the Service manifest
Let's break down the service.yaml
file:
apiVersion: v1
: This tells Kubernetes to use thev1
API version.kind: Service
: This specifies the type of object we're creating, which is a Service.metadata
: This field specifies the additional metadata that should be associated with the Service.name
: This field specifies the name of the Service. In this case, it'sbackend-service
.
spec
: This field specifies the specification of the Service.type
: This field specifies the type of the Service. In this case, it'sClusterIP
.selector
: This field specifies the selector that the Service uses to route the traffic to the Pods. In this case, the selector isapp: simple-deployment
.ports
: This field specifies the ports that the Service listens on.protocol
: This field specifies the protocol that the Service listens on. In this case, it'sTCP
.port
: This field specifies the port on which the Service listens. In this case, it's8000
.targetPort
: This field specifies the port on the Pods to which the traffic is routed. In this case, it's8000
.name
: [Optional] This field specifies the name of the port. In this case, it's not specified.
Cleaning up
To clean up the resources created in this section, run the following commands:
kubectl delete -f deployment.yaml
kubectl delete -f service.yaml
Summary
In this section, we created a ClusterIP Service to route traffic to the Pods created by the Deployment. We then sent a request to the Service from inside the cluster to see how the traffic is routed to the Pods.