K8S #01 : Flannel, MetalLB, Nginx
A voir si j’en fais une série… 🤔
Chose promise, chose due ! Mon cluster Kubernetes installé via Kubeadm commence lentement mais sûrement à prendre forme ! 😁
I) Découverte de K8S, et de la partie Networking
Alors pour un peu de contexte, je ne suis clairement pas un expert en K8S… je suis familier avec les notions de base (pods, nodes, namespaces, services, deployment…) et la CLI, mais j’ai encore clairement énormément de choses à apprendre.
En général, quand je veux me former à une techno j’aime bien avoir un objectif, un projet. Bref, avoir un lab. C’est donc comme ça que je me suis mis à installer un p’tit cluster via Kubeadm composé de 3 nœuds sous UbuntuServer. J’avais fait deux précédents articles où via Packer/Terraform je créais le template, puis je le clonais et préparer les hôtes.
Une fois le tout setupé, mon premier réflexe a été de mettre en place le réseau. Et déjà là faut apprendre deux trois bricoles d’entrée de jeu !
J’utilise kubeadm pour setuper mon cluster, et j’ai choisi Flannel comme CNI par défaut. La commande utilisée pour créer le tout a donc ressemblé à ceci :
# On initialise notre cluster, en renseignant le subnet utilisé par les pods. Par défaut, Flannel utilise 10.244.0.0/16
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
Mais ensuite il faut l’installer, ce fameux CNI qu’est donc Flannel ! Et là, avant d’aller plus loin, expliquons ce que c’est et à quoi ça sert…
II) Les CNIs, Container Network Interface
Un CNI est donc un plugin pour K8S responsable de la gestion du réseau pour les pods dans un cluster. Il va permettre de gérer la connexion entre les pods grosso modo.
Il existe forcément une looooongue liste de CNIs… parmi lesquels :
- Flannel, très simple et très léger à utiliser. En général c’est celui que beaucoup de personnes choisissent ;
- Calico, un chouilla plus complexe et plus avancé. Comme dit plus haut, je ne suis pas expert donc je ne saurai vous dire les vraies options supplémentaires comparé à Flannel ;
- WeaveNet, … ;
- Cilium, … ;
- … ;
Bref, vous l’aurez compris, ici je vais me concentrer sur mon premier choix. Voyons maintenant comment installer tout ça !
III) Installation de Flannel
Pour ce faire rien de plus simple, il suffit de télécharger et appliquer le manifeste. Un manifeste n’est ni plus ni moins qu’un fichier permettant de décrire l’état d’une ressource, comme un Deployment, un Service, un ConfigMap… avec ses caractéristiques, comme le nombre de réplicas, le nom de l’image, ses labels… :
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
Et c’est bon ! On peut vérifier que nos pods sont bien en running, en vérifiant ceux tournant dans le namespace kube-flannel :
kubectl get pods -n kube-flannel
Comme quoi, pas si compliqué que ça… maintenant passons à l’installation de MetalLB, et voyons en même temps pourquoi nous en avons besoin.
IV) MetalLB, le « DHCP » pour LoadBalancers bare-metal
Comme dit en début d’article, mon cluster est donc On-Premise, comprenez par là qu’il n’est pas installé sur un Cloud.
J’utilise aussi kubeadm pour setuper le tout, mais sachez qu’il existe pléthore d’autres outils… alors ce n’est pas le sujet ici, mais par exemple il existe minikube, j’avais justement fait un article dessus il y a un sacré bout de temps. Bref, je digresse.
Tout ça pour dire qu’en général, dans 90% du temps, on a son petit cluster K8S sur Azure/AWS/GCP, et nos services LoadBalancer récupèrent une IP publique automatiquement. On a rien à configurer en CLI ou autre. Le bémol, c’est qu’ici, et beh c’est pas le cas.
Arrive alors MetalLB. Dans le titre je parle de « DHCP » mais c’est plus pour l’image ; en réalité c’est un contrôleur de LoadBalancers pour Kubernetes, en tout cas c’est une des définitions les plus probantes que j’ai pu trouvée.
En gros, on va l’installer sur notre cluster, lui renseigner une (ou plusieurs) plages d’adresses IPv4 (ou v6 !), et il va se charger de distribuer ces adresses à nos services LoadBalancer sur notre instance dès que ceux-ci en auront besoin.
Bien, assez de blabla ! Pour l’installer, on a plusieurs choix (comme souvent avec K8S…) :
# Via un fichier manifeste, comme pour Flannel
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml
Soit via Helm, le « package manager » made in K8S :
helm repo add metallb https://metallb.github.io/metallb
helm install metallb metallb/metallb
Alors cet article commence déjà à devenir un peu long pour juste expliquer l’install’ de Flannel/MetalLB/Nginx Ingress Controller, donc je ne vais pas décrire précisément ce qu’est Helm, j’en ferai peut être un article dédié. Sachez simplement qu’il permet d’installer/gérer des charts, des sortes d’applications K8S « pré-packagés » dirons-nous.
Bref, qu’importe la façon que vous allez choisir, l’important est que ça tourne !
Une fois fait, il ne nous reste plus qu’à créer un petit fichier manifeste en Yaml qui va nous permettre de définir notre fameuse plage d’IPs pour MetalLB :
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: example
namespace: metallb-system
spec:
addresses:
- 192.168.0.70-192.168.0.75
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: empty
namespace: metallb-system
Alors ici j’ai volontairement mis une petite plage, mais libre à vous d’adapter, en mettant par exemple :
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: example
namespace: metallb-system
spec:
addresses:
- 192.168.0.70-192.168.0.75 # Plage IPv4
- 2001:db8::10-2001:db8::15 # Plage IPv6
- 10.0.0.0/24 # Subnet IPv4 en notation CIDR
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: empty
namespace: metallb-system
Et il n’y a plus qu’à appliquer le tout !
# Ici mon fichier de config s'appelle donc metallb-config.yaml, et je l'ai créé dans un folder nommé metallb, histoire d'avoir un peu de clarté
kubectl apply -f metallb/metallb-config.yaml
Et pour tester la chose… si l’on appliquer ce fichier manifeste via un classique kubectl apply -f , et qui est un simple service web Apache avec un service de type LoadBalancer :
# Création du Namespace 'web'
apiVersion: v1
kind: Namespace
metadata:
name: web
---
# Déploiement d'un serveur web HTTP (Apache) dans le namespace 'web'
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
namespace: web
spec:
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: httpd
image: httpd:2.4.48-alpine3.14 # Image du serveur web Apache
ports:
- containerPort: 80 # Le serveur web écoute sur le port 80
---
# Création d'un Service LoadBalancer pour exposer le serveur web à l'extérieur du cluster, et obtenir une IP de MetalLB justement
apiVersion: v1
kind: Service
metadata:
name: web-server-service
namespace: web
spec:
selector:
app: web # Sélectionne le Deployment avec l'étiquette 'app: web'
ports:
- protocol: TCP
port: 80 # Port du service exposé
targetPort: 80 # Port dans le conteneur
type: LoadBalancer # Type de service pour exposer à l'extérieur du cluster
Tadaaaaaa~ !
On voit bien ici que notre service dans le namespace web a bien reçu une external-ip ! Si c’est pas beau ça… 🥹
Maintenant qu’on a donc notre cluster avec Flannel d’installé, MetalLB prêt à distribuer des IPs pour nos services LoadBalancer… il ne reste qu’à installer notre cher Nginx Ingress Controller et on aura déjà une solide base pour faire mumuse !
*Nous n’aurons plus besoin de ce serveur web de test, donc autant supprimer le namespace entier. Comme ça, pas besoin de supprimer le Deployment et le Service manuellement.
kubectl delete namespace web
V) Nginx Ingress Controller
Alors initialement je comptais partir sur Traefik… j’avais fait quelques tests, et j’avais réussi à setup l’accès à l’interface web etc, mais pour une raison que j’ignore, impossible de faire du simple routage basé sur un nom d’hôte… ‘marche juste pô. J’ai cherché un peu mais plutôt que de laisser le temps filer, je me suis dit qu’on pourrait très bien partir sur Nginx, qui est l’Ingress Controller de référence sur K8S 💁🏻♂️
Bref ! On va donc utiliser Helm pour l’installer, en rajoutant en premier lieu le dépôt :
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
Avant de procéder à l’installation dans son namespace correspondant, on va rapidement récupérer un fichier values.yaml et l’éditer :
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/refs/heads/main/charts/ingress-nginx/values.yaml
Et on s’assure que le paramètre hostNetwork soit bien à true :
Et enfin on peut créer notre namespace puis l’installer dans ce dernier !
kubectl create namespace nginx-controller
helm install ingress-nginx ingress-nginx/ingress-nginx -f values.yaml -n nginx-controller
Il récupère bien son IP ! Maintenant créons rapidement un fichier manifeste pour un serveur web Apache, avec une IngressRoute nous permettant d’y accéder via son FQDN, à savoir apache.tips4tech.local.
Bien-entendu, il vous faudra créer une entrée dans votre DNS. Ici, je fais donc pointer mon FQDN vers l’IP récupérée par mon contrôleur Nginx :
apache.tips4tech.local => 192.168.0.70
Voilà le manifeste pour Apache :
apiVersion: apps/v1
kind: Deployment
metadata:
name: apache-deployment
spec:
replicas: 3
selector:
matchLabels:
app: apache
template:
metadata:
labels:
app: apache
spec:
containers:
- name: apache
image: apache:latest
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: apache-service
spec:
selector:
app: apache
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: apache
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: apache.tips4tech.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: apache-service
port:
number: 80
On le démarre via un simple kubectl apply -f deploy-apache.yaml et on vérifie ça !
Parfait ! 😎
On a désormais réussi à mettre en place Flannel, MetalLB, et notre Ingress Controller Nginx avec en prime le test d’un p’tit serveur web ! Pas mal comme début !
VI) Conclusion
Comme dit en début d’article, je ne suis (pas encore ?) un expert en K8S ! C’est pourquoi si certains abus de langage/petites coquilles se sont glissés dans cet article, n’hésitez clairement pas en commentaires 🫡.
J’ai décidé de partir pour le moment sur Nginx comme déjà dit aussi, car visiblement j’ai quelques p’tits soucis avec Traefik… rien d’insurmontable, un truc qui m’échappe et ça viendra vite. Mais voilà, je préférai tout de même avancer et ne pas rester bloqué trop longtemps dessus.
Je ne sais pas non plus si je ferai une « Série Kubernetes« , on verra. Là l’objectif, après avoir setupé toute la partie Network, ce serait de :
- Checker pour la partie Storage avec un grand S, c’est-à-dire montages NFS, voir du GlusterFS si j’me sens motivé… j’ai justement retrouvé dans mes brouillons un article traitant de cette techno… ‘article datant d’il y a 4 ans 😅
- Checker pour installer Harbor, histoire d’avoir mon propre petit registre d’images Docker ;
- Revenir sur la partie Networking pour setup du HTTPs… en général on peut utiliser Let’s Encrypt qui est super simple à setuper sur Traefik/Nginx, mais ici j’aimerai pousser le vice et utiliser ma propre PKI interne… et puis vu que c’est du On-Prem isolé, pas possible d’utiliser Let’s Encrypt ici ;
- … ;
Bref, ce n’est que le début, mais ça peut s’annoncer bien sympatoche ! Je vous tiens au courant de tout ça.
Sur ce, j’espère encore et toujours vous avoir appris quelques bricoles, et vous souhaite une bonne journée/soirée ! Ciao !
Laisser un commentaire