#kubeweek #4

#kubeweek #4

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.

The service discovery concept.

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.

Using LoadBalancer for connecting to Service Instances

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.

Service Discovery using Centralized Registry Service

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