Kubernetes Services Evolution
Tags: kubernetes, helm, devops
Published: 2023-05-08 23:46:43

Kubernetes is a complex piece of software. Over the years of learning about it, it seems to have become more complex - the more I learn, the more I realize I don't know. One thing that has become more clear, however, is networking. I was once confused as to how to allow pods to talk to each other, but no more. Here are the things that helped me understand Kubernetes Services.

# Services - NodePort, Load Balancers, and ExternalName

Kubernetes allows communication in a number of different ways, and they are normally through a service, where we change the type in the yaml:

```
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 8080
  type: NodePort
```


I like to think of Services as being like Pokemon that evolve. NodePort is like the first baby pokemon before it has evolved. It is the simplest way to expose a Service. It forwards the traffic to a set of pods from a port. Then the poke-service evolves into a LoadBalancer, which provides an external IP address, load balancing, and other features. Normally LoadBalancers are used in a cloud environment, which leads to the Ingress, which isn't a service at all. The Ingress provides a way to provide access to multiple services on different paths.

Here is an example LoadBalancer:



```
apiVersion: v1
kind: Service
metadata:
  name: service1
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "tcp"
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
  type: LoadBalancer
  selector:
    app: service1
  ports:
    - name: http
      port: 80
      targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: service2
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "tcp"
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
  type: LoadBalancer
  selector:
    app: service2
  ports:
    - name: http
      port: 80
      targetPort: 80
```

and Ingress:

```
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - host: service1.example.com
    http:
      paths:
      - path: /service1
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              name: http
  - host: service2.example.com
    http:
      paths:
      - path: /service2
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              name: http
```

## Load Balancer vs Ingress

The difference between LoadBalancer and Ingress is a bit nuanced, but both LoadBalancer and Ingress require external implementation, such as ElasticLoadBalancer or Istio's Ingress Controller. Ingress controller's provide more advanced routing, such as based on URL Path, while the LoadBalancer implements a load balancing algorithm. Additionally, the Ingress can be the plugin point for much other features of Service Mesh, such as mTLS. LoadBalancer can provide access to multiple services, but it doesn't use the path rerouting.

# Communication

"But how do you make the service call?" - In order to make the service call, just use the name of the service!

In this case:

```
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 8080
```

I could make the REST call like so, from the metadata.name:

`http://**my-service**/v1/make/some-call`.