Service Discovery¶
- In this lab we will learn what is a
Serviceand go over the differentServicetypes.
What will we learn?¶
- What a Kubernetes
Serviceis and why you need one - How to create and test
ClusterIP,NodePort, andLoadBalancerservices - How to use Kubernetes internal DNS (
FQDN) to access services - The differences between the service types
Prerequisites¶
- A running Kubernetes cluster (
kubectl cluster-infoshould work) kubectlconfigured against the cluster
01. Some General Notes on What is a Service¶
Serviceis a unit of application behavior bound to a unique name in aservice registry.Serviceconsist of multiplenetwork endpointsimplemented by workload instances running on pods, containers, VMs etc.Serviceallow us to gain access to any given pod or container (e.g., a web service).- A
serviceis (normally) created on top of an existing deployment and exposing it to the “world”, using IP(s) & port(s). K8Sdefine 3 main ways (+FQDN internally) to define a service, which means that we have 4 different ways to access Pods.- There are several proxy mode which inplements diffrent behaviour, for example in
user proxy modefor eachServicekube-proxyopens a port (randomly chosen) on the local node. Any connections to this “proxy port” are proxied to one of the Service’s backend Pods (as reported via Endpoints). - All the service types are assigned with a
Cluster-IP. - Every service also creates
Endoint(s), which point to the actual pods.Endpointsare usually referred to asback-endsof a particular service.
01. Create namespace and clear previous data if there is any¶
# If the namespace already exists and contains data form previous steps, let's clean it
kubectl delete namespace codewizard
# Create the desired namespace [codewizard]
kubectl create namespace codewizard
namespace/codewizard created
02. Create the required resources for this hand-on¶
# Network tools pod
kubectl create deployment -n codewizard multitool --image=praqma/network-multitool
deployment.apps/multitool created
# nginx pod
kubectl create deployment -n codewizard nginx --image=nginx
deployment.apps/nginx created
# Verify that the pods running
kubectl get all -n codewizard
NAME READY STATUS RESTARTS AGE
pod/multitool-74477484b8-bdrwr 1/1 Running 0 29s
pod/nginx-6799fc88d8-p2fjn 1/1 Running 0 7s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/multitool 1/1 1 1 30s
deployment.apps/nginx 1/1 1 1 8s
NAME DESIRED CURRENT READY AGE
replicaset.apps/multitool-74477484b8 1 1 1 30s
replicaset.apps/nginx-6799fc88d8 1 1 1 8s
Service Type: ClusterIP¶
- If not specified, the default service type is
ClusterIP. - In order to expose the deployment as a service, use:
--type=ClusterIP ClusterIPwill expose the pods within the cluster. Since we don’t have anexternal IP, it will not be reachable from outside the cluster.- When the service is created
K8Sattaches a DNS record to the service in the following format:<service name>.<namespace>.svc.cluster.local
03. Expose the nginx with ClusterIP¶
# Expose the service on port 80
kubectl expose deployment nginx -n codewizard --port 80 --type ClusterIP
service/nginx exposed
# Check the services and see it's type
# Grab the ClusterIP - we will use it in the next steps
kubectl get services -n codewizard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
nginx ClusterIP 10.109.78.182 <none> 80/TCP
04. Test the nginx with ClusterIP¶
- Since the service is a
ClusterIP, we will test if we can access the service using the multitool pod.
# Get the name of the multitool pod to be used
kubectl get pods -n codewizard
NAME
multitool-XXXXXX-XXXXX
# Run an interactive shell inside the network-multitool-container (same concept as with Docker)
kubectl exec -it <pod name> -n codewizard -- sh
- Connect to the service in any of the following ways:
Test the nginx with ClusterIP¶
1. using the IP from the services output. grab the server response:¶
# Expected output:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
2. Test the nginx using the deployment name - using the service name since its the DNS name behind the scenes¶
# Expected output:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>
If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.
</p>
<p>
For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br />
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.
</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
3. using the full DNS name - for every service we have a full FQDN (Fully qualified domain name) so we can use it as well¶
# bash-5.0# curl -s <service name>.<namespace>.svc.cluster.local
bash-5.0# curl -s nginx.codewizard.svc.cluster.local
Service Type: NodePort¶
NodePort: Exposes the Service on each Node’s IP at a static port (theNodePort).- A
ClusterIPService, to which theNodePortService routes, is automatically created. NodePortservice is reachable from outside the cluster, by requesting<Node IP>:<Node Port>.- The NodePort is allocated from a flag-configured range (default: 30000-32767).
05. Create NodePort¶
1. Delete previous service¶
# Delete the existing service from previous steps
kubectl delete svc nginx -n codewizard
service "nginx" deleted
2. Create NodePort service¶
# As before but this time the type is a NodePort
kubectl expose deployment -n codewizard nginx --port 80 --type NodePort
service/nginx exposed
# Verify that the type is set to NodePort.
# This time you should see ClusterIP and port as well
kubectl get svc -n codewizard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
nginx NodePort 100.65.29.172 <none> 80:32593/TCP
Note the PORT(S) column: 80:32593/TCP. - 80 is the port the service exposes internally (ClusterIP). - 32593 is the NodePort (the port exposed on every node).
3. Test the NodePort service¶
To test the service from outside the cluster (e.g., from your local machine), we need two pieces of information: 1. The Node IP: The IP address of one of the cluster nodes. 2. The NodePort: The port allocated to the service (which we saw above).
Step 3.1: Get the Node Port
We can retrieve the allocated NodePort manually from the kubectl get svc output, or programmatically:
# Get the NodePort allocated to the 'nginx' service
kubectl get svc nginx -n codewizard -o jsonpath='{.spec.ports[0].nodePort}{"\n"}'
32593
Step 3.2: Get the Node IP
We need the IP address of a node. In a multi-node cluster, any node’s IP will work.
# List nodes and their IP addresses
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE
minikube Ready control-plane 1d v1.26.1 192.168.49.2 <none> Buildroot 2021.02.4
minikube ip to get this IP directly. Step 3.3: Access the Service
Now construct the URL using the format http://<NODE_IP>:<NODE_PORT>.
# Example: curl http://192.168.49.2:32593
# Replace with YOUR actual Node IP and Node Port
curl -s http://<NODE_IP>:<NODE_PORT>
# Expected output:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
<h1>Welcome to nginx!</h1>
...
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Service Type: LoadBalancer¶
Note
We cannot test a LoadBalancer service locally on a localhost, but only on a cluster which can provide an external-IP
06. Create LoadBalancer (only if you are on real cloud)¶
1. Delete previous service¶
# Delete the existing service from previous steps
kubectl delete svc nginx -n codewizard
service "nginx" deleted
2. Create LoadBalancer Service¶
# As before this time the type is a LoadBalancer
kubectl expose deployment nginx -n codewizard --port 80 --type LoadBalancer
service/nginx exposed
# In real cloud we should se an EXTERNAL-IP and we can access the service
# via the internet
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
nginx LoadBalancer 100.69.15.89 35.205.60.29 80:31354/TCP