Kubernetes Services

Services provide networking between pods.
We create services using config files just as we do with pods and deployments.
We are going to make use of services to setup some communication between all of our different pods or to get access to a pod from outside of our cluster.

Anytime we need communication or networking between our pods or anytime we try to access a pod from outside of the cluster we are allways going to make use of a service

Types of services:

  • Cluster IP: Sets up an easy-to-remember URL to access a pod. Only exposes pods in the cluster.
  • Node Port: Makes a pod accessible outside of a cluster. Usually only used for dev purposes.
  • Load Balancer: Makes a pod accessible from outside of a cluster. This is the right way to expose a pod to the outside world.
  • External Name: Redirects an in-cluster request to a CNAME url. This is and advanced corner-case.

NOTE: Only ‘Cluster IP’ and ‘Load Balancer’ will be used on daily basis.

For the following steps you can use https://github.com/luckpp/microservices-demo/tree/master/infra/k8s as reference.


Creating a NodePort Service

  • Create the posts-nodeport-srv.yaml:
apiVersion: v1
kind: Service
metadata:
  name: posts-nodeport-srv
spec: # will customize how this service behaves
  type: NodePort
  selector:
    app: posts
  ports:
    - name: posts # this is only for logging purposes
      protocol: TCP
      port: 4000 # this is the port of the NodeService
      targetPort: 4000 # this is the port inside the docker container
  • apply the config file to the cluster: $ kubectl apply -f posts-nodeport-srv.yaml
  • list all services running inside the cluster: $ kubectl get services
    • on the PORT(S) column the 4000:3xxxx is listed
    • the 3xxxx is the port randomly assigned that we will use to get access to that service from outside of the cluster
  • alternative to the previous command is: $ kubectl describe service posts-nodeport-srv
    • and for access from outside of the cluster use the NodePort

Access the service with this address: minikube_ip:service_port

  • get the minikue IP address by running: $ minikube ip
  • get the service port obtained with:
    • $ kubectl get services
    • $ kubectl describe service posts-nodeport-srv
  • NOTE: on Mac/Windows the address is: localhost:service_port

Creating a ClusterIP Service

Creating a ClusterIP Service

NOTE:

  • the deployment and service configuration can be co-located in the same yaml file
  • in order to create multiple objects inside an yaml file we separate them with —

apiVersion: v1
kind: Service
metadata:
  name: event-bus-srv
spec:
  selector:
    app: event-bus
  # type: ClusterIP # this is optional
  ports:
    - name: event-bus
      protocol: TCP
      port: 4005
      targetPort: 4005

Making pods communicate

  • identify the service that you want to communicate to
    $ kubectl get services
    # for example we have identified the service ID ‘event-bus-srv’
  • in JS code make calls using that service ID
    await axios.post('http://event-bus-srv:4005/events', {…});
  • get the minikube ip
    $ minikube ip
  • get the ‘posts-srv’ service randomly assigned ip (starting with 3xxxx)
    $ k get services
  • compose the POST request using Postman

Applyng multiple config file: $ kubectl apply -f .


Create a LoadBalancer Service

Create a LoadBalancer Service.

The goal of the LoadBalancer Service is to make sure that we have a single point of entry in our entire cluster.

Terminology arround LoadBalancer:

  • LoadBalancer Service: Tells Kubernetes to reach out to its provider and provision a load balancer. Gets traffic into a single pod.
  • Ingress or Ingress Controller: A pod with a set of routing rules to distribute traffic to other services.

NOTE:

  • the project ingress-nginx will create a Load Balancer Service and an Ingress Controller for us (https://github.com/kubernetes/ingress-nginx)
  • there is another project that does the same thing and has the name kubernetes-ingress

Steps:

The configuration file for the Ingress Controller ingress-srv.yaml:

apiVersion: networking.k8s.io/v1beta1 # extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-srv
spec:
  rules:
    - host: posts.com
      http:
        paths:
          - path: /posts
            backend:
              serviceName: posts-srv
              servicePort: 4000

In order to apply the file:
$ kubectl apply -f ingress-srv.yaml

Check that the Ingress has been created:
$ kubectl get ingress

In order to access the posts service:

  • tweak the /etc/hosts file in order to map the minikube IP to the posts.com domain if you are testing locally
    • $ minikube ip # copy this IP
    • $ sudo nano /etc/hosts
      • add the following line at the end of the file: 192.168.99.102 posts.com
      • CTRL+o CTRL+x
  • do a HTTP GET request to the posts API
    • $ curl http://posts.com/posts

Kubernetes Deployments

In Kubernetes we work with Pods that run one or multiple Containers.
Rather than creating a Pod directly we create a Deployment.

Deployment:

  • is a Kubernetes object that is intended to manage a set of Pods
  • each of those Pods are going to be identical in nature
    • they will run the same configuration, same container inside them

The deployment has 2 big jobs assigned to it:

  • is going to make sure that if any pod is going to disappear (has crashed) it will automatically create that pod again
  • will help with updating the code inside the containers

Conclusion: A deployment is just a manager that manages a set of pods.

apiVersion: apps/v1   # the object bucket to be used
kind: Deployment
metadata:
  name: posts-depl
spec:                 # specifies how the deployment should behave
  replicas: 1         # the number of pods we want to create to run an image
  selector:           # selects the pods with label posts
    matchLabels:
      app: posts
  template:           # Here we specify the exact configuration of the pod we want a deployment to create
    metadata:         # Works together with the selector section
      labels:         # so we want the pod to have a label of app: posts
        app: posts
    spec:             # similar to pod creation
      containers:
        - name: posts
          image: luckpp/posts:0.0.1

NOTE: A deployment might have a hard time figuring out which pods it should manage inside our cluster. In other word if some pods are created we want to give the deployment some information to select the pod(s) to manage. This can be achieved with the ‘selector’ and ‘metadata’ sections from ‘spec’ inside the yaml.

In order to apply the config file defined above
$ kubectl apply -f posts-depl.yaml

Deployment commands:

  • $ kubectl get deployments
  • $ kubectl describe deployment [depl_name]
  • $ kubectl apply -f [config_file_name]
  • $ kubectl delete deployment [depl_name]

Updating Deployments

  1. Update the image used by a deployment:
  • make a change to your project
  • rebuild the image, specifying a new image version
  • in the deployment config file, update the version of the image
  • run the command: $ kubectl apply -f [depl_file_name]

-> to get the logs: $ kubectl logs [pod_name]

This type of update is not used very often in professional development since it requires to modify the image version inside the deployment yaml.

  1. Update the image used by a deployment:
  • the deployment must be using the ‘latest’ tag in the pod spec section (or leave the ‘latest’ out since is implicit)
  • make an update to your code
  • build the image
  • push the image to docker hub (or use ‘imagePullPolicy: Never’ for the container inside de depl.yaml)
  • In order to apply the change: $ kubectl rollout restart deployment [depl_name]