Dans kubernetes on va avoir différentes facon d’exposer un service:
- ClusterIP
- NodePort
- LoadBalancer
- Ingress Controler
On va laisser le dernier de côté et s’interesser au 3 premiers puis mettre en place un LoadBalancer qui est un service natif dans kubernetes mais on va devoir utiliser un service externe pour assigner des adresses IPs à ce dernier → MetalLB
Imaginons ce déploiement:
# web-app.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: lst
labels:
name: service-demo
spec:
replicas: 1
selector:
matchLabels:
name: service-demo
template:
metadata:
labels:
name: service-demo
spec:
containers:
- image: nginx
name: web-app
command:
- /bin/sh
- -c
- "echo 'Bienvenu dans la salle du temps !!' > /usr/share/nginx/html/index.html && nginx -g 'daemon off;'"
$ kubectl apply -f web-app.yml
01. ClusterIP
Ce service permet d’acceder à notre service au sein du cluster, à partir de n’importe quel noeud ou control-plane. Ce qui permet de toujours avoir accès au service même si ce dernier est relancé sur un autre noeud.
$ kubectl expose deployments web-app --namespace lst --name web-app-svc --port 80
On accède bien à notre service à travers un autre pod dans le cluster.
C’est bien tout ca, mais si je souhaite y accèder à partir de ma machine ?
Ouvrons un port sur les noeuds qui nous permettra cela.
02. NodePort
Ce service permet d’ouvrir un port sur chacun des noeuds compris entre 30000 et 32767 par défaut.
Il est déconseillé d’utiliser directement ce service en production car sa gestion peut vite devenir complex d’un point de vu sécurité et disponibilité.
Indirectement lorsqu’on crée un NodePort, kubernetes va également créer un ClusterIP et faire la connection entre les deux pour nous.
Cette fois je vais simplement le déclarer à la suite de notre déploiement.
On supprime rapidement le ClusterIP précédemment créé et on enchaine.
$ kubectl delete service --namespace lst web-app-svc
# web-app.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: lst
labels:
name: service-demo
spec:
replicas: 1
selector:
matchLabels:
name: service-demo
template:
metadata:
labels:
name: service-demo
spec:
containers:
- image: nginx
name: web-app
command:
- /bin/sh
- -c
- "echo 'Bienvenu dans la salle du temps !!' > /usr/share/nginx/html/index.html && nginx -g 'daemon off;'"
---
apiVersion: v1
kind: Service
metadata:
name: web-app-svc
namespace: lst
labels:
name: service-demo
spec:
type: NodePort
selector:
name: service-demo
ports:
- port: 80 # Port exposé par le Pod nginx
targetPort: 80 # Port exposé par le ClusterIP
nodePort: 30007 # Port exposé par le NodePort
$ kubectl apply -f web-app.yml
On voit bien que nous avons accès depuis une machine exterieur au cluster à notre service via chacun des noeuds worker seulement.
Maintenant si je souhaite éviter la gestion des ports, on peut passer au LoadBalancer.
On supprime et on repart.
$ kubectl delete -f web-app.yml
03. LoadBalancer
Ce service est encore un niveau au dessus de ClusterIP et NodePort. D’ailleurs il utilise également ces services pour son fonctionnement.
# web-app.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: lst
labels:
name: service-demo
spec:
replicas: 1
selector:
matchLabels:
name: service-demo
template:
metadata:
labels:
name: service-demo
spec:
containers:
- image: nginx
name: web-app
command:
- /bin/sh
- -c
- "echo 'Bienvenu dans la salle du temps !!' > /usr/share/nginx/html/index.html && nginx -g 'daemon off;'"
---
apiVersion: v1
kind: Service
metadata:
name: web-app
namespace: lst
labels:
name: service-demo
spec:
type: LoadBalancer
selector:
name: service-demo
ports:
- name: http
port: 80 # Port de notre service Nginx
protocol: TCP
targetPort: 80 # Port que l'on souhaite utiliser
$ kubectl apply -f web-app.yml
$ kubectl get service -n lst
Sur ma machine MetalLB est installé donc je ne peux pas vous mettre de capture, cependant vous verez qu’aucune adresse IP externe ne sera assigné à votre service LoadBalancer.
Pour cela, on va utiliser MetalLB pour créer une pool d’IP que notre LB pourra utiliser.
On supprime notre déploiement juste avant.
$ kubectl delete -f web-app.yml
- Installer MetalLB via Helm
helm repo add metallb https://metallb.github.io/metallb
helm install metallb metallb/metallb
Pour choisir les ip à assigner, si vous utilisez kind par exemple, il faudra voir le CIDR associé à votre réseau docker kind. Si vous êtes sur votre réseau local, vérifier l’adresse de votre réseau ainsi que la range de votre DHCP.
Par exemple, comme vous voyez sur les captures chez moi c’est 192.168.1.0/24 et j’ai une range de 192.168.1.2-192.168.1.200
En conséquence pour l’exemple, je vais créer la pool sur 192.168.1.195-192.168.1.199 car je sais qu’aucune de mes machines sur mon réseau n’est sur ces IPs.
# first-pool.yml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.1.195-192.168.1.199 # Définissez votre pool en fonction de votre ŕéseau et disponibilité
Avec cette jolie piscine d’IP disponible pour nos futures LoadBalancer, il faut également déployer un service qui va se charger de les annoncer.
# l2-advertisement.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: advertisement-demo
namespace: metallb-system
spec:
ipAddressPools:
- first-pool # S'assurer que c'est bien le nom de notre IPAddressPool
On applique tout ca.
$ kubectl apply -f first-pool.yml
$ kubectl apply -f l2-advertisement.yaml
$ kubectl apply -f web-app.yml
Félicitation, vous avez votre service accessible depuis l’exterieur de votre cluster proprement !
Maintenant, si on souhaite utiliser qu’une seule IP est bien rediriger le traffic au sein de nos noeuds, utiliser un ingress controler est pour moi la prochaine étape.
Enjoy o/