Récupérez le projet de base : git clone -b exercice https://github.com/Uptime-Formation/tp3-k8s.git tp3. On peut ouvrir une fenêtre VSCode directement dans le dossier qui nous intéresse avec : code tp3.
Ce TP va consister à créer des objets Kubernetes pour déployer une application microservices (plutôt simple) : monsterstack.
Elle est composée :
monstericon,dnmonsterredis servant de cache pour les images de monstericonNous allons également utiliser le builder kubernetes skaffold pour déployer l’application en mode développement : l’image du frontend monstericon sera construite à partir du code source présent dans le dossier app et automatiquement déployée dans minikube.
docker composeDockerfile présent dans le dossier TP3.docker-compose.yml est utile pour faire tourner les trois services de l’application dans docker rapidement (plus simple que kubernetes)Pour lancer l’application il suffit :
curl https://get.docker.com | sudo sh -sudo docker compose up -dsudo docker compose ps et les logs avec sudo docker compose logs -fPassons maintenant à Kubernetes.
Explorer avec Kompose comment on peut traduire un fichier docker-compose.yml en ressources Kubernetes (ce sont les instructions à la page suivante : https://kubernetes.io/fr/docs/tasks/configure-pod-container/translate-compose-kubernetes/).
D’abord, installons Kompose :
# Linux
curl -L https://github.com/kubernetes/kompose/releases/download/v1.26.1/kompose-linux-amd64 -o kompose
chmod +x kompose
sudo mv ./kompose /usr/local/bin/kompose
Puis, utilisons la commande kompose convert et observons les fichiers générés.
Ces fichiers ne sont pas très complets, supprimons-les.
dnmonster et le datastore redis Maintenant nous allons également créer un déploiement pour dnmonster:
dnmonster.yaml dans le dossier k8s-deploy-dev et collez-y le code suivant :dnmonster.yaml :
apiVersion: apps/v1
kind: Deployment
metadata:
name: dnmonster
labels:
app: monsterstack
spec:
selector:
matchLabels:
app: monsterstack
partie: dnmonster
strategy:
type: Recreate
replicas: 5
template:
metadata:
labels:
app: monsterstack
partie: dnmonster
spec:
containers:
- image: amouat/dnmonster:1.0
name: dnmonster
ports:
- containerPort: 8080
name: dnmonster
redis.yaml:apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
labels:
app: monsterstack
spec:
selector:
matchLabels:
app: monsterstack
partie: redis
strategy:
type: Recreate
replicas: 1
template:
metadata:
labels:
app: monsterstack
partie: redis
spec:
containers:
- image: redis:latest
name: redis
ports:
- containerPort: 6379
name: redis
kubectl apply -f k8s-deploy-dev/ et vérifiez dans Lens que les 5 + 1 réplicats sont bien lancés.monstericon Ajoutez au fichier monstericon.yml du dossier k8s-deploy-dev le code suivant:
apiVersion: apps/v1
kind: Deployment
metadata:
name: monstericon
labels:
app: monsterstack
spec:
selector:
matchLabels:
app: monsterstack
partie: monstericon
strategy:
type: Recreate
replicas: 3
template:
metadata:
labels:
app: monsterstack
partie: monstericon
spec:
containers:
- name: monstericon
image: monstericon
ports:
- containerPort: 5000
skaffold en suivant les indications ici: https://skaffold.dev/docs/install/L’image monstericon de ce déploiement n’existe pas sur le Docker Hub, et notre Kubernetes doit pouvoir accéder à la nouvelle version de l’image construite à partir du Dockerfile. Nous allons utiliser skaffold pour cela.
Il y a plusieurs possibilités :
skaffold.yaml et le fichier de Deployment correspondant pour remplacer le nom de l’image monstericon pour faire référence à l’adresse à laquelle on souhaite pousser l’image sur le registry distant (ex: docker.io/MON_COMPTE_DOCKER_HUB/monstericon)artifacts: dans le fichier skaffold.yaml ceci : local:
push: true
heureusement le mécanisme de layers des images Docker ne nous oblige à uploader que les layers modifiés de notre image à chaque build
(plus long) configurer un registry local (en Docker ou en Kubernetes) auquel Skaffold et Kubernetes peuvent accéder
registry:2) ou plus avancé (Harbour par exemple)(plus avancé) utiliser Kaniko, un programme de Google qui permet de builder directement dans le cluster Kubernetes : https://skaffold.dev/docs/pipeline-stages/builders/docker/#dockerfile-in-cluster-with-kaniko
Observons le fichier skaffold.yaml
Lancez skaffold run pour construire et déployer l’application automatiquement (skaffold utilise ici le registry docker local et kubectl)
monstericon L’image monstericon de ce déploiement n’existe pas sur le Docker Hub, et notre Kubernetes doit pouvoir accéder à la nouvelle version de l’image construite à partir du Dockerfile.
Sans un outil comme Skaffold, nous sommes bloqué·es : il faut construire l’image à la main et la pousser dans un registry joignable par notre install.
Voici l’image déjà poussée par le formateur :
docker.io/uptimeformation/monstericon
Probes livenessProbe doit être à la hauteur du i de image:) :livenessProbe:
tcpSocket: # si le socket est ouvert c'est que l'application est démarrée
port: 5000
initialDelaySeconds: 5 # wait before firt probe
timeoutSeconds: 1 # timeout for the request
periodSeconds: 10 # probe every 10 sec
failureThreshold: 3 # fail maximum 3 times
readinessProbe:
httpGet:
path: /healthz # si l'application répond positivement sur sa route /healthz c'est qu'elle est prête pour le traffic
port: 5000
httpHeaders:
- name: Accept
value: application/json
initialDelaySeconds: 5
timeoutSeconds: 1
periodSeconds: 10
failureThreshold: 3
La livenessProbe est un test qui s’assure que l’application est bien en train de tourner. S’il n’est pas rempli le pod est automatiquement supprimé et recréé en attendant que le test fonctionne.
Ainsi, k8s sera capable de savoir si notre conteneur applicatif fonctionne bien, quand le redémarrer. C’est une bonne pratique pour que le replicaset Kubernetes sache quand redémarrer un pod et garantir que notre application se répare elle même (self-healing).
Cependant une application peut être en train de tourner mais indisponible pour cause de surcharge ou de mise à jour par exemple. Dans ce cas on voudrait que le pod ne soit pas détruit mais que le traffic évite l’instance indisponible pour être renvoyé vers un autre backend ready.
La readinessProbe est un test qui s’assure que l’application est prête à répondre aux requêtes en train de tourner. S’il n’est pas rempli le pod est marqué comme non prêt à recevoir des requêtes et le service évitera de lui en envoyer.
CONTEXT pour lui indiquer si elle doit se lancer en mode PROD ou en mode DEV. Ici nous mettons l’environnement DEV en ajoutant (aligné avec la livenessProbe):env:
- name: CONTEXT
value: DEV
env: :resources:
requests:
cpu: "100m" # 10% de proc
memory: "50Mi"
limits:
cpu: "300m" # 30% de proc
memory: "200Mi"
Nos pods auront alors la garantie de disposer d’un dixième de CPU (100/1000) et de 50 mégaoctets de RAM. Ce type d’indications permet de remplir au maximum les ressources de notre cluster tout en garantissant qu’aucune application ne prend toute les ressources à cause d’un fuite mémoire etc.
skaffold run pour appliquer les modifications.kubectl describe deployment monstericon, lisons les résultats de notre readinessProbe, ainsi que comment s’est passée la stratégie de déploiement type: Recreate.Les services K8s sont des endpoints réseaux qui balancent le trafic automatiquement vers un ensemble de pods désignés par certains labels. Ils sont un peu la pierre angulaire des applications microservices qui sont composées de plusieurs sous parties elles même répliquées.
Pour créer un objet Service, utilisons le code suivant, à compléter :
apiVersion: v1
kind: Service
metadata:
name: <nom_service>
labels:
app: monsterstack
spec:
ports:
- port: <port>
selector:
app: <app_selector>
partie: <tier_selector>
type: <type>
---
Ajoutez le code précédent au début de chaque fichier déploiement. Complétez pour chaque partie de notre application :
name: dans metadata:) par le nom de notre programme. En particulier, il faudra forcément appeler les services redis et dnmonster comme ça car cela permet à Kubernetes de créer les entrées DNS correspondantes. Le pod monstericon pourra ainsi les joindre en demandant à Kubernetes l’IP derrière dnmonster et redis.partie par le nom de notre programme (monstericon, dnmonster et redis)app et partie par ceux du pod correspondant.Le type sera : ClusterIP pour dnmonster et redis, car ce sont des services qui n’ont à être accédés qu’en interne, et LoadBalancer pour monstericon.
skaffold run.kubectl get services.minikube service monstericon.skaffold delete.Pour Minikube : Installons le contrôleur Ingress Nginx avec minikube addons enable ingress.
Pour les autres types de cluster (cloud ou k3s), lire la documentation sur les prérequis pour les objets Ingress et installez l’ingress controller appelé ingress-nginx : https://kubernetes.io/docs/concepts/services-networking/ingress/#prerequisites. Si besoin, aidez-vous du TP suivant sur l’utilisation de Helm.
Avant de continuer, vérifiez l’installation du contrôleur Ingress Nginx avec kubectl get svc -n ingress-nginx ingress-nginx-controller : le service ingress-nginx-controller devrait avoir une IP externe.
Il s’agit d’une implémentation de reverse proxy dynamique (car ciblant et s’adaptant directement aux objets services k8s) basée sur nginx configurée pour s’interfacer avec un cluster k8s.
Repassez le service monstericon en mode ClusterIP. Le service n’est plus accessible sur un port. Nous allons utiliser l’ingress à la place pour afficher la page.
Ajoutez également l’objet Ingress suivant dans le fichier monster-ingress.yaml :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: monster-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: monsterstack.local # à changer si envie/besoin
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: monstericon
port:
number: 5000
Ajoutez ce fichier avec skaffold run.
Récupérez l’ip de minikube avec minikube ip, (ou alors allez observer l’objet Ingress dans Lens dans la section Networking. Sur cette ligne, récupérez l’ip de minikube en 192.x.x.x.).
Ajoutez la ligne <ip-minikube> monsterstack.local au fichier /etc/hosts avec sudo nano /etc/hosts puis CRTL+S et CTRL+X pour sauver et quitter.
Visitez la page http://monsterstack.local pour constater que notre Ingress (reverse proxy) est bien fonctionnel.
Le dépôt Git de la correction de ce TP est accessible ici : git clone -b tp3 https://github.com/Uptime-Formation/corrections_tp.git