Service Discovery

K8s is a dynamic system. It has to manage placing pods on nodes, make sure they are running and more stuff. Due to this nature k8s makes it easy to run a lot of things, but it can be a bit hard to find these things.

What is Service Discovery?

A service is a method for exposing a network application that is running in one or more Pods in your cluster

Actually you use one type of service discover everyday, DNS, the thing that helps you resolve hostnames to IPs. It works great for the internet, but falls short in the k8s world.

Why? DNS caches a bunch of stuff, and in a k8s cluster pods are ephemeral, they can be killed and come back up in seconds, so due to this cache we could be pointing to something that is already dead.

While these pods that compose the backend may change, the frontend clients should not need to be aware of that, nor should they need to keep track of the of the backend themselves.

K8s has an object/resource specific to this issue.

The Service Object

A Service is an object, it has a manifest and all that. Say you have a set of pods that each listen on port 5000 and are labeled as name=flask-app. The manifest would look something like this:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: flask-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 5000

K8s will assign the service a Cluster IP , and will be continuously scanning for Pods that match the selector (the flask-app part). Then it will make the updates to the set of EndpointSlices for the Service.

Using the type NodePorts

By using this type, in addition of a Cluster IP, the system picks a port on every node in the cluster to forward traffic to the service.

Meaning you can connect to any node in the cluster, and reach an specific service. You can use NodePort without knowing where any of the pods for that service are running.

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort <--- here
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - port: 80
      # By default and for convenience, the `targetPort` is set to
      # the same value as the `port` field.
      targetPort: 80
      # Optional field
      # By default and for convenience, the Kubernetes control plane
      # will allocate a port from a range (default: 30000-32767)
      nodePort: 30007

Now each request that is send to the service will be randomly directed to one of the pods that implements the service.