Using a Service to Expose App When a worker node dies, the Pods running on the Node are also lost. A ReplicaSet might then dynamically drive the cluster back to the desired state via the creation of new Pods to keep your application running. A Service in Kubernetes is an abstraction which defines a logical set of Pods and a policy by which to access them. Services enable a loose coupling between dependent Pods. A Service is defined using YAML or JSON, like all Kubernetes object manifests. The set of Pods targeted by a Service is usually determined by a label selector.
Create a new Service
kubectl get pods
List the current Services from our cluster:
kubectl get services
To create a new service and expose it to external traffic we'll use the expose command with NodePort as parameter.
kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080
kubectl get services
To find out what port was opened externally:
kubectl describe services/kubernetes-bootcamp' export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')" echo "NODE_PORT=$NODE_PORT"
we can test that the app is exposed outside of the cluster using curl
curl http://"$(minikube ip):$NODE_PORT"
Using labels
The Deployment created automatically a label for our Pod. With the describe deployment subcommand we can see the name (the key) of that label: kubectl describe deployment
Let’s use this label to query our list of Pods. kubectl get pods -l app=kubernetes-bootcamp
kubectl get services -l app=kubernetes-bootcamp
Get the name of the Pod and store it in the POD_NAME environment variable:
export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')" echo "Name of the Pod: $POD_NAME"
To apply a new label we use the label subcommand followed by the object type, object name and the new label:
kubectl label pods "$POD_NAME" version=v1
we can check it with the describe pod command:
kubectl describe pods "$POD_NAME"
List of pods using the new label:
kubectl get pods -l version=v1
Deleting a service
To delete Services :
kubectl delete service -l app=kubernetes-bootcamp
Confirm that the Service is gone:
kubectl get services
To confirm that route is not exposed anymore you can curl the previously exposed IP and port:
curl http://"$(minikube ip):$NODE_PORT"
This proves that the application is not reachable anymore from outside of the cluster. We can confirm that the app is still running with a curl from inside the pod:
kubectl exec -ti $POD_NAME -- curl localhost:8080
Service Discovery
In modern cloud-native infrastructure such as Kubernetes, applications are designed using microservices. The different components need to communicate within a microservices architecture for applications to function, but individual IP addresses and endpoints change dynamically.
Types of service discovery
There are multiple different types of service discovery. Let’s take a look at some of the most popular approaches.
Server-side service discovery
Server-side service discovery involves putting a load balancer (LB) in front of the service and letting the load balancer connect to service instances. This process eliminates client-side complexity. The client simply points to the IP or DNS name of the load balance.
Service registry
Another approach to service discovery is to remove the LB component and implement service discovery on the client-side using a centralized service registry.
To get started, create a test namespace for this demo:
$ kubectl create ns demo
namespace/demo created
Next, create an nginx app deployment:
$ kubectl -n demo apply -f
https://k8s.io/examples/application/deployment-update.yaml
deployment.apps/nginx-deployment created
pods are up and running and confirm if the endpoints are available.
$ kubectl -n demo get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-559d658b74-k79zt 1/1 Running 0 45s
nginx-deployment-559d658b74-xjpvb 1/1 Running 0 45s
## check if the pods endpoints are available in Kubernetes ( not yet )
$ kubectl -n demo get ep
No resources found in demo namespace.
Create a service object for the deployment using the kubectl expose command.
$ kubectl -n demo expose deployment/nginx-deployment
service/nginx-deployment exposed
$ kubectl -n demo get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-deployment ClusterIP 10.245.202.247 ‹none› 80/TCP 13s
$ kubectl -n demo get endpoints
NAME ENDPOINTS AGE
nginx-deployment 10.244.2.152:80,10.244.2.203:80 24s
$ kubectl -n demo get svc nginx-deployment -o yaml
- apiVersion: v1
kind: Service
metadata:
name: nginx-deployment
namespace: demo
resourceVersion: "31628410"
uid: 45a58559-d9e3-43a6-bfbc-e3ab6bb4aff0
spec:
clusterIP: 10.245.202.247
clusterIPs:
- 10.245.202.247
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
$ kubectl -n demo get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-deployment ClusterIP 10.245.202.247 ‹none› 80/TCP 82s
$ kubectl -n demo run tmp-shell --rm -i --tty --image nicolaka/netshoot --
/bin/bash
bash-5.1# nslookup nginx-deployment
Server:10.245.0.10
Address:10.245.0.10#53
Name:nginx-deployment.demo.svc.cluster.local ( auto mapped to FQDN )
Address: 10.245.202.247 ( IP of the service )
Access the app/service by Service name:
bash-5.1# curl nginx-deployment
‹!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›
bash-5.1#
Check the pod environment variables related to service discovery
bash-5.1# env
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
NGINX_DEPLOYMENT_PORT_80_TCP_PROTO=tcp
HOSTNAME=netshoot
NGINX_DEPLOYMENT_PORT_80_TCP=tcp://10.245.202.247:80
PWD=/root
HOME=/root
KUBERNETES_PORT_443_TCP=tcp://10.245.0.1:443
NGINX_DEPLOYMENT_PORT_80_TCP_ADDR=10.245.202.247
NGINX_DEPLOYMENT_SERVICE_PORT=80
NGINX_DEPLOYMENT_PORT_80_TCP_PORT=80
NGINX_DEPLOYMENT_SERVICE_HOST=10.245.202.247
TERM=xterm
SHLVL=1
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.245.0.1
NGINX_DEPLOYMENT_PORT=tcp://10.245.202.247:80
KUBERNETES_SERVICE_HOST=10.245.0.1
KUBERNETES_PORT=tcp://10.245.0.1:443
KUBERNETES_PORT_443_TCP_PORT=443
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
_=/usr/bin/env