Dans la deuxième partie de cet article, nous avons vu comment Kube Proxy pilotait la répartition de charge et la persistance d'IP pour les Pods qui assurent réellement le service grâce à l'objet "Service" de Kubernetes et les "Endpoints".
Dans cette troisième partie, nous allons détailler les types de services fournis par K8s.

Les Services K8s

Un service représente une abstraction de répartition de charge au sein d'un cluster.
Il possède un type qui définit son rôle et son fonctionnement. Ces types sont essentiellement:

  • Cluster IP
  • Node Port
  • Load Balancer

Cluster IP

C'est le type de service par défaut de Kubernetes. Il assigne une adresse IP à partir d'un pool d'adresse réservé par le cluster.
Il représente la base de la plupart des autres types de services. Le type Cluster IP permet de faire communiquer des Pods entre eux. Son usage est seulement interne au cluster.

Créons deux pods dans un cluster:

kubectl run nginx --image nginx
kubectl run nginx2 --image nginx

Les pods sont créés sans services, nous allons créer un service pour chaque pod:

kubectl expose pods nginx --port 80
kubectl expose pods nginx2 --port 80

Lorsque l'on exécute la commande kubectl get svc, on peut voir que chacun des pods est relié à un service de type cluster IP possédant une IP du pool prévu à cet usage dans le cluster.

kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
nginx        ClusterIP   10.43.193.150   <none>        80/TCP    13m
nginx2       ClusterIP   10.43.45.159    <none>        80/TCP    13m

On peut constater la communication entre les pods en se connectant sur l'un deux et en exécutant un Curl vers le second.

kubectl exec -it ngninx -- bash
root@nginx:/# curl nginx2
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>

Voici l'implémentation d'un service de type Cluster IP via un manifest YAML :

apiVersion: v1
kind: Service

metadata:
  name: nginx

spec:
  type: ClusterIP
  ports:
    - targetPort: 80
      port: 80
      
  selector:
    app: nginx

Dans la partie 'spec', il est possible de configurer un attribut .spec.clusterIP avec une addresse IP spécifique afin de réutiliser une entrée DNS d'un système plus ancien (l'IP choisie doit être comprise dans le range CIDR service-cluster-ip-range). S'il n'est pas configuré, une adresse sera attribuée automatiquement. Il est possible, enfin, de le configurer avec la valeur "None", dans ce cas le service ne se verra assigner aucune adresse IP et deviendra un type Headless.
Il est possible d'utiliser un service headless pour s'interfacer avec d'autres mécanismes de découverte de service, sans être lié à l'implémentation de Kubernetes.

NodePort

Ce type de service crée un port externe au cluster dans un range spécifique, réservé par le cluster (30000-32767 par défaut) qui est proxifié vers un port interne coté service. En gros c'est du NAT/PAT destination qui permet de rentrer dans le cluster à destination d'un port cible sur une application. Le port est configuré sur tous les Nodes d'un cluster avec le même numéro.
Avec ce type de service, il est possible de configurer son propre service de Load Balancing externe ou même d'exposer directement un port sur un ou plusieurs Nodes.

Reprenons notre exemple précédent avec nos deux pods nginx, avec les services de type Cluster IP, il est possible de faire communiquer les deux pods entre eux à l'intérieur du cluster Kubernetes. Comment faire pour accéder à l'un des serveurs nginx depuis l'extérieur du cluster ?

Créons un service de type Node Port avec le manifest suivant :

apiVersion: v1
kind: Service

metadata:
  name: np-nginx

spec:
  type: NodePort
  ports:
    - targetPort: 80
      port: 80
      nodePort: 30080
      
  selector:
    run: nginx

il est alors possible d'accéder au pods nginx depuis l'extérieur du cluster via l'adresse IP d'un Node du cluster associé au port affecté : 30080. Tous les Nodes du cluster possèdent le même port pour accéder au Pod. L'usage d'un Node Port impose un Load Balancer externe pour distribuer la charge de travail vers les nœuds du cluster.

Load Balancer

Lorsqu'un Cloud Service Provider est utilisé pour faire tourner des clusters Kubernetes, il est possible de s'appuyer sur les load balancers externes intégrés, proposés par la plateforme Cloud.
Dans ce cas il possible d'utiliser le type Load Balancer dans un service Kubernetes.

apiVersion: v1
kind: Service
metadata:
  name: lb-nginx
spec:
  selector:
    run: nginx
  ports:
    - port: 80
      targetPort: 80
  type: LoadBalancer

Lorsque que l'on utilise un service de type Load Balancer sur une infrastructure On Premise, la sortie de la commande kubectl get svc donne:

NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
lb-nginx     LoadBalancer   10.43.8.237    <pending>     80:31509/TCP   12s

On peut voir l'adresse du Cluster IP qui permet d'accéder au service au sein du Cluster, mais l'External-IP, qui permet d'accéder au service depuis l'extérieur du Cluster reste sur pending.
On voit ici que sans un Load Balancer externe configuré, ce type de service est inutilisable.

Dans les prochains articles nous nous intéresserons aux différentes solutions qui permettent d'utiliser des services de type Load Balancing dans un environnement On Premise.