TP - PromQL - Détecter des anomalies sur un Cluster Kubernetes
Dans ce TP nous allons creuser plus loin les requêtes PromQL avec des aggregations, fonctions, calculs dans le contexte de l’observation d’un cluster Kubernetes.
Kubernetes est un peu le Linux du cloud : c’est la solution (ou plutôt le “noyau” de solution) open source pour créer des clouds applicatifs (conteneurs applicatifs). Prometheus est la solution de référence pour monitorer les clouds de conteneurs car il est très adapté aux environnements dynamiques ou les “cibles” de la surveillance vont et viennent.
Nous allons d’abord installer un cluster Kubernetes et l’opérateur kube-prometheus qui permet de déployer et d’opérer dans le temps un système Prometheus haute disponibilité.
Nous utiliserons ensuite cette configuration pour essayer des requêtes PromQL plus avancées dans un contexte dynamique.
Installation de Kubernetes
Section titled “Installation de Kubernetes”- Installons les dépendances de Kubernetes telles d’indiquées dans le premier TP kubernetes avec un script:
bash /opt/kubernetes.sh - Vérifions l’installation avec
kubectl get nodes - Lancez
minikube stop - Ouvrez OpenLens dans le menu internet pour vérifier son installation
Pour installer k3s (notre kubernetes pour ce TP) lancez dans un terminal la commande suivante: curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik" sh -
- Pour récupérer la configuration lancez
mkdir -p ~/.kubesudo chmod 744 /etc/rancher/k3s/k3s.yaml cp /etc/rancher/k3s/k3s.yaml ~/.kube/config- vérifier la config avec
kubectl get nodes
Testons notre installation dans OpenLens en visitant le cluster nommé default
Installation de Kube-Prometheus
Section titled “Installation de Kube-Prometheus”Lancez la commande suivante pour récupérer kube-prometheus dans votre dossier personnel: cd ~ && git clone https://github.com/prometheus-operator/kube-prometheus.git
-
Assurez vous d’être dans le dossier cloné :
cd ~/kube-prometheus -
Lancez l’installation de l’opérateur de Prometheus avec le bloc de commande suivant:
# Create the namespace and CRDs, and then wait for them to be availble before creating the remaining resourceskubectl create -f manifests/setup
# Wait until the "servicemonitors" CRD is created. The message "No resources found" means success in this context.until kubectl get servicemonitors --all-namespaces ; do date; sleep 1; echo ""; done
kubectl create -f manifests/-
Observons un peu dans Lens (commentaire formateur) et plus d’information dans les supports Kubernetes sur le même site
-
Accédons à l’interface de Prometheus avec la commande
kubectl --namespace monitoring port-forward svc/prometheus-k8s 9999:9090(laissez la tourner dans le terminal) puis en visitantlocalhost:9090dans le navigateur.
Des requêtes PromQL avancées : identifier les problèmes dans notre Cluster
Section titled “Des requêtes PromQL avancées : identifier les problèmes dans notre Cluster”Pour chacune des requêtes suivantes:
- Comprendre de quoi elle parle (avec l’aide du formateur si Kubernetes ne vous est pas familier)
- créer les resources Kubernetes requises en faisant
+ > create resourcedans OpenLens puis coller le code et create. - Décomposer la requête et la jouer partie par partie dans PromLens idéalement ou dans Prometheus pour comprendre le sens des différentes sous parties et leur retours
Trouver le nombre de Pods par namespace
Section titled “Trouver le nombre de Pods par namespace”sum by (namespace) (kube_pod_info)Trouver les PersistentVolumeClaims dans l’état “Pending”
Section titled “Trouver les PersistentVolumeClaims dans l’état “Pending””Avant d’exécuter la requête, créez un PersistentVolumeClaim avec la spécification suivante :
apiVersion: v1kind: PersistentVolumeClaimmetadata: name: pvc-claim-2spec: storageClassName: manual accessModes: - ReadWriteOnce resources: requests: storage: 3GiCela restera dans l’état “Pending” car nous n’avons pas de storageClass appelé “manual” dans notre cluster.
Maintenant, exécutez la requête suivante :
kube_persistentvolumeclaim_status_phase{phase="Pending"}Trouver les Pods Kubernetes dans un état CrashLoop
Section titled “Trouver les Pods Kubernetes dans un état CrashLoop”Avant d’exécuter la requête, créez un Pod avec la spécification suivante :
apiVersion: v1kind: Podmetadata: name: crashing-podspec: containers: - name: crashing-container image: ubuntu restartPolicy: AlwaysCe pod n’a pas de commande qui dure dans le
Maintenant, exécutez la requête suivante :
increase(kube_pod_container_status_restarts_total[15m]) > 3Trouver l’état des différents nœuds du cluster
Section titled “Trouver l’état des différents nœuds du cluster”-
sum(kube_node_status_condition{condition="Ready",status="true"}) -
sum(kube_node_status_condition{condition="NotReady",status="true"}) -
sum(kube_node_spec_unschedulable) by (node)
Localiser les surallocations CPU (CPU overcommit)
Section titled “Localiser les surallocations CPU (CPU overcommit)”- Avant d’exécuter la requête, créez un Pod avec la spécification suivante :
apiVersion: v1kind: Podmetadata: name: gros-podspec: containers: - name: gros-pod image: alpine resources: limits: # le pod exige au moins 4 coeurs de CPU et 8Go de ram pour fonctionner cpu: "4000m" memory: "8000M" requests: cpu: "4000m" memory: "8000M" # => il ne sera jamais lancé dans notre cluster trop limité # dans prometheus on peut détecter que le cluster est trop petit pour les application demandées (resource overcommitment)Maintenant, exécutez la requête suivante :
sum(kube_pod_container_resource_limits{resource="cpu"}) - sum(kube_node_status_capacity{resource="cpu"})Si cette requête renvoie une valeur positive, le cluster a surallocé le CPU.
Surallocation de mémoire (Memory Overcommit)
Section titled “Surallocation de mémoire (Memory Overcommit)”sum(kube_pod_container_resource_limits{resource="memory"}) - sum(kube_node_status_capacity{resource="memory"})Trouver les Pods Kubernetes “Unhealthy”
Section titled “Trouver les Pods Kubernetes “Unhealthy””Avant d’exécuter cette requête, créez un Pod avec la spécification suivante :
apiVersion: v1kind: Podmetadata: name: ssd-podspec: containers: - name: ssd-pod image: alpine nodeSelector: disktype: ssdCe Pod ne pourra pas s’exécuter car nous n’avons pas de nœud avec l’étiquette disktype: ssd.
Maintenant, exécutez la requête suivante :
min_over_time(sum by (namespace, pod) (kube_pod_status_phase{phase=~"Pending|Unknown|Failed"})[15m:1m]) > 0Trouver le nombre de conteneurs sans limites CPU dans chaque espace de noms
Section titled “Trouver le nombre de conteneurs sans limites CPU dans chaque espace de noms”count by (namespace)(sum by (namespace, pod, container)(kube_pod_container_info{container!=""}) unless sum by (namespace, pod, container)(kube_pod_container_resource_limits{resource="cpu"}))Trouver les nœuds instables
Section titled “Trouver les nœuds instables”Dans cette requête, vous trouverez des nœuds qui passent continuellement de l’état “Ready” à l’état “NotReady” de manière intermittente.
sum(changes(kube_node_status_condition{status="true",condition="Ready"}[15m])) by (node) > 2Si les deux nœuds fonctionnent correctement, vous ne devriez pas obtenir de résultat pour cette requête.
Trouver les cœurs CPU inactifs
Section titled “Trouver les cœurs CPU inactifs”sum((rate(container_cpu_usage_seconds_total{container!="POD",container!=""}[30m]) - on (namespace,pod,container) group_left avg by (namespace,pod,container)(kube_pod_container_resource_requests{resource="cpu"})) * -1 >0)Trouver la mémoire inutilisée
Section titled “Trouver la mémoire inutilisée”sum((container_memory_usage_bytes{container!="POD",container!=""} - on (namespace,pod,container) avg by (namespace,pod,container)(kube_pod_container_resource_requests{resource="memory"})) * -1 >0 ) / (1024*1024*1024)