#KubeWeek Challenge Day-4 Kubernetes Services and Service Discovery
# how to expose Kubernetes workloads to the outside world using Services. # how to discover Services and Pods within a Kubernetes cluster using DNS.
Table of contents
Expose Kubernetes workloads to the outside world using Service:
Services in Kubernetes:
A Kubernetes Service is a Kubernetes object which enables cross-communication between different components within and outside a Kubernetes cluster. It exposes Kubernetes applications to the outside world while simultaneously allowing network access to a set of Pods within and outside of a Kubernetes cluster.
Why Services and Not Pod IP?
The Pod IP address is dynamic, which means it could change any moment. For example, when a Pod crashes or is deleted and another one comes up with the help of a ReplicaSet, the new Pod has a different IP address from the terminated one. This makes the Pod IP address unstable which can result in application errors. However, managing a connection to a Pod with a Service creates a stable IP address to reach the Pod.
Service Types:
There are five different types of Service:
ClusterIP (default)
Node Port
ExternalName
Headless
Load balancer
Creating a Service with ClusterIP:
Step 1: First, create a Deployment and make sure that the spec.selector.matchLabels.app
value in the Deployment manifest file matches the spec.template.metadata.labels.app
value in the same Deployment manifest as well as the spec.selector.app
value in the Service manifest file. The manifest file will look like this:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
replicas: 2
strategy:
type: Recreate
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
env: prod
spec:
containers:
- name: my-deployment-container
image: nginx
Use kubectl create
command to create the Deployment. This configuration will create a Deployment with two Pods that we will expose with a ClusterIP service. Once the Pods are running by checking it using kubectl get pods
command, create a Service with the below configuration:
Step 2: Create the Service
Create a YAML file:
vim clp_service.yaml
apiVersion: v1
kind: Service
metadata:
name: example-prod
spec:
selector:
app: my-app
env: prod
type: ClusterIP
ports:
- protocol: TCP
port: 80
targetPort: 8080
Step 3: Deploy your Service to the cluster.
kubectl create -f clp_service.yaml
Step 4: Make sure both your Pods and the Service are running by checking their statuses.
Check the status of the service:
kubectl get service example-prod
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example-prod ClusterIP 10.107.61.93 <none> 80/TCP 13s
Check the status of the Pods to get their names:
kubectl get pods
NAME READY STATUS RESTARTS AGE
my-deployment-6b9b97d749-g5d2w 1/1 Running 0 10m
my-deployment-6b9b97d749-w9tq5 1/1 Running 0 10m
Step 5: Determine the Service IP and Port.
Exec into one of the containers:
kubectl exec -it my-deployment-6b9b97d749-g5d2w -- bin/bash
root@my-deployment-6b9b97d749-g5d2w:
Check the Service info in the Container:
root@my-deployment-97cfc859f-q9dqh:/# printenv | grep SERVICE
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=44
KUBERNETES_SERVICE_PORT_HTTPS=443
As can be seen above, the created Service was not part of the output. Why? This will be the case if you create the Deployment before the Service. You can simply correct it by deleting all the instances of the Pod so that they can be re-created when the Service is already running.
$ kubectl delete pod my-deployment-6b9b97d749-g5d2w my-deployment-6b9b97d749-w9tq5
pod "my-deployment-6b9b97d749-g5d2w" deleted
pod "my-deployment-6b9b97d749-w9tq5" deleted
Check the status of the Pods:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
my-deployment-6b9b97d749-48d27 1/1 Running 0 21s
my-deployment-6b9b97d749-gsrwp 1/1 Running 0 21s
Exec into one of the Containers again:
$ kubectl exec -it my-deployment-6b9b97d749-48d27 -- bin/bash
root@my-deployment-6b9b97d749-48d27:/#
Check the Service info in the Container:
root@my-deployment-6b9b97d749-48d27:/# printenv | grep SERVICE
KUBERNETES_SERVICE_PORT_HTTPS=443 ## Default Service name and Port on the Cluster
KUBERNETES_SERVICE_PORT=443
EXAMPLE_PROD_SERVICE_HOST=10.107.61.93 ##Service IP as shown in the Service status
KUBERNETES_SERVICE_HOST=10.96.0.1 ## Kubernetes IP already on the cluster
EXAMPLE_PROD_SERVICE_PORT=80 ##Service name and Port specified in the Service YAML file.
As can be seen here, the Service name, Port, and host values are output in the container. This is possible because both the Service and the Pod are running on the same Cluster and the Service was created before the Pod/Deployment.
Discover Services and Pods within a Kubernetes cluster using DNS:
Kubernetes provides built-in DNS-based service discovery, allowing services and pods to communicate with each other using DNS names.
By default, each Service in a Kubernetes cluster is assigned a DNS name based on its name and namespace.
Similarly, pods are assigned a DNS name based on their name and namespace.
Discovering a Service using DNS:
Let's say we have a Service named "my-service" deployed in the "default" namespace. We can discover this Service using DNS. Here's an example Python code snippet to resolve the DNS and retrieve the IP address of the Service:
import socket
service_host = "my-service.default.svc.cluster.local"
service_port = 80
service_address = socket.gethostbyname(service_host)
print(f"Service IP: {service_address}")
In the above code snippet, replace my-service
with the actual name of your Service, and modify the namespace and port accordingly. Running this code will resolve the DNS name my-service.default.svc.cluster.local
and print the corresponding IP address of the Service.
Discovering a Pod using DNS:
Similarly, let's assume we have a Pod named "my-pod" running in the "default" namespace. We can discover this Pod using DNS. Here's an example Python code snippet to resolve the DNS and retrieve the IP address of the Pod:
import socket
pod_host = "my-pod.default.pod.cluster.local"
pod_port = 8080
pod_address = socket.gethostbyname(pod_host)
print(f"Pod IP: {pod_address}")
Replace my-pod
with the actual name of your Pod, and adjust the namespace and port as necessary. Executing this code will resolve the DNS name my-pod.default.pod.cluster.local
and display the IP address of the Pod.
To test the above code snippets, ensure that you have the necessary Python environment set up with the socket
module available. Execute the code and observe the output, which will provide the IP addresses of the discovered Service and Pod.
Note: Remember to replace the placeholder values (my-service
, my-pod
, default
, etc.) in the code snippets with the actual names and namespaces of your Services and Pods within the Kubernetes cluster.
Thank you for reading!Happy Learning!!
Santosh Chauhan