lid's Wiki

Supervision et Kubernetes

Introduction

Les années précédentes, nous avons vu les différents types de supervision des infrastructures.

Pour rappel, on distingue trois grands axes de supervision:

Réseau

Ici, on va principalement surveiller l'état du réseau et de ses différents composants:

Le protocole de choix reste ici SNMP, avec des solutions spécialisées comme Observium ou LibreNMS. Des visualisations de type WeatherMap permettent en un coup d'oeil de vérifier l'état du réseau et d'identifier les comportements anormaux.

Système

La supervision Système se concentre, elle, sur la collecte et l'aggrégation de métriques purement système:

Applicative

La supervision Applicative elle se focalise sur le bon fonctionnement des applicatifs de l'infrastructure. On peut citer pêle-mêle:

Ici, on utilisera généralement conjointement des solutions de supervision classiques ainsi que de l'aggrégation de logs, et potentiellement des outils comme Sentry, New Relic (propriétaire mais puissant), ou statsd qui nous remonteront, notamment, les erreurs applicatives ainsi que leur origine dans le code source de notre applicatif, et les problèmes de performance liés au code même de l'applicatif.

Il existe pléthore de solutions de supervision, de Nagios à Zabbix en passant par Prometheus/Grafana, couplée à des solutions d'aggrégation de logs telles qu'ELK, Graylog ou bien Loki (très prometteur)

On utilise en général conjointement plusieurs solutions de supervision afin d'obtenir la meilleure visibilité possible sur notre infrastructure.

Kubernetes: outils de supervision

Bien évidemment, on va vouloir superviser et monitorer nos clusters Kubernetes de la même manière que nous monitorons le reste de notre infrastucture.

Heureusement, nous disposons de tout un panel de solutions.

Tout d'abord, la majorité des "distributions" Kubernetes intègrent un petit serveur de métriques de base, metrics-server. Son rôle est principalement de remonter l'utilisation RAM et CPU de nos pods afin que Kubernetes puisse déterminer s'il peut provisionner tel ou tel nouveau pod sur un noeud de notre cluster ou pas. Couplé au système de requêtes et de limites, cela nous permet de nous assurer que nos charges de travail disposent toujours de suffisamment de ressources pour s'exécuter correctement.

Cependant, si nous voulons obtenir plus d'informations sur l'état de notre cluster, par exemple le nombre de requêtes par seconde reçues par le serveur API de Kubernetes, ou l'état de la base etcd, par exemple, nous allons devoir utiliser des outils externes dédiés, par exemple:

Dans la suite de ce module, nous utiliserons kube-prometheus-stack du fait de sa maturité.

Installons kube-prometheus-stack sur notre cluster K3S

Là, c'est très simple, il va nous suffire d'utiliser Helm pour ajouter le dépôt de chartes correspondant, et d'installer la charte en question:

helm repo add prometheus https://prometheus-community.github.io/helm-charts
helm repo update
helm fetch prometheus/kube-prometheus-stack
tar xvzf kube-prometheus-stack.tar.gz
cd kube-prometheus-stack
vim kube-prometheus-stack/values.yaml
# on va modifier les paramètres ingress
# pensez à ajouter un enregistrement host sur votre laptop !
helm install -n prom --create-namespace prometheus prometheus/kube-prometheus-stack -f values.yaml

Et on va attendre quelques minutes. Lorsque tout sera terminé, un:

kubectl get ingress,svc,pods -n prom

devrait nous renvoyer:

lidstah@marfak:~$ kubectl get ingress,svc,pods -n prom
NAME                                           CLASS     HOSTS                   ADDRESS                     PORTS     AGE
ingress.networking.k8s.io/prom-stack-grafana   traefik   promtest.lidstah.info   192.168.1.11,192.168.1.49   80, 443   8d

NAME                                              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
service/alertmanager-operated                     ClusterIP   None            <none>        9093/TCP,9094/TCP,9094/UDP   8d
service/prom-stack-grafana                        ClusterIP   10.43.176.117   <none>        80/TCP                       8d
service/prom-stack-kube-prometheus-alertmanager   ClusterIP   10.43.8.159     <none>        9093/TCP,8080/TCP            8d
service/prom-stack-kube-prometheus-operator       ClusterIP   10.43.146.14    <none>        443/TCP                      8d
service/prom-stack-kube-prometheus-prometheus     ClusterIP   10.43.234.76    <none>        9090/TCP,8080/TCP            8d
service/prom-stack-kube-state-metrics             ClusterIP   10.43.181.176   <none>        8080/TCP                     8d
service/prom-stack-prometheus-node-exporter       ClusterIP   10.43.100.13    <none>        9100/TCP                     8d
service/prometheus-operated                       ClusterIP   None            <none>        9090/TCP                     8d

NAME                                                         READY   STATUS    RESTARTS        AGE
pod/alertmanager-prom-stack-kube-prometheus-alertmanager-0   2/2     Running   0               14m
pod/prom-stack-grafana-fbcb88649-6p2sh                       3/3     Running   0               14m
pod/prom-stack-kube-prometheus-operator-59498fb75b-mdwsd     1/1     Running   0               14m
pod/prom-stack-kube-state-metrics-5b44dc4467-x99pz           1/1     Running   0               14m
pod/prom-stack-prometheus-node-exporter-flfql                1/1     Running   0               7d10h
pod/prom-stack-prometheus-node-exporter-pkj4h                1/1     Running   1 (4d20h ago)   7d10h
pod/prometheus-prom-stack-kube-prometheus-prometheus-0       2/2     Running   2 (4d20h ago)   7d10h

Une fois terminé, on va pouvoir récupérer le mot de passe admin généré:

kubectl get secret -n prom prom-stack-grafana -o yaml

Il ne nous reste plus qu'à décoder login et mot de passe obtenus dans le yaml du secret via la commande base64. Normalement, vous savez faire 😃

En se connectant à l'adresse définie lorsque nous avons configuré l'ingress, et en s'identifiant avec les informations obtenues à l'instant, on devrait obtenir ceci:

grafana1.png

La stack a la bonne idée d'intégrer tout un ensemble de dashboards déjà fonctionnels, qui vont nous remonter les informations obtenues des métriques collectées sur le cluster, notamment concernant le serveur API, chaque pod, les stats etcd, etc.

Exemple:

grafana2.png

On va explorer plusieurs de ces dashboards, mais on va ensuite attaquer la partie la plus intéressante: celle qui nous permet de définir de nouvelles sondes qui vont aller interroger nos applicatifs fournissant un endpoint de métriques!

"Monitorons" nos applicatifs!

Alors, ça tombe bien, il existe une petite application de démo toute prête pour que nous puissions tester:

git clone https://github.com/brancz/prometheus-example-app

Elle est très simple: une requête sur / produit une 200 qui incrémente un compteur, une requête sur /err produit une 404, qui implémente un autre compteur, et ces statistiques sont accessibles sur l'endpoint /metrics de l'"applicatif".

On a aussi un déploiement, et un PodMonitor déjà préconfigurés, que nous allons adapter un peu:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: prometheus-example-app
  name: prometheus-example-app
  namespace: apptest
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: prometheus-example-app
  template:
    metadata:
      labels:
        app.kubernetes.io/name: prometheus-example-app
    spec:
      containers:
      - name: prometheus-example-app
        image: quay.io/brancz/prometheus-example-app:v0.3.0
        ports:
        - name: web
          containerPort: 8080

PodMonitor Prometheus

Le PodMonitor va nous servir à indiquer à Prometheus d'aller chercher les informations de monitoring de "l'app" directement sur l'endpoint du pod de notre "applicatif" d'exemple (on préfèrera utiliser un ServiceMonitor, mais on va y revenir par la suite):

apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  labels:
    app.kubernetes.io/name: prometheus-example-app
    release: prom-stack
  name: prometheus-example-app
  namespace: apptest
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: prometheus-example-app
  podMetricsEndpoints:
  - port: web

Alors attention, ici, notez bien le label "release: prom-stack" qui est relatif à mon installation de prometheus dans cet exemple. Pour bien vérifier quel label vous devez ajouter à vos PodMonitors et ServiceMonitors:

lidstah@marfak:~$ kubectl get prometheus -n prom -o yaml | grep -A5 serviceMonitorSelector
    serviceMonitorSelector:
      matchLabels:
        release: prom-stack
    shards: 1
    tsdb:
      outOfOrderTimeWindow: 0s

En effet, par défaut, Prometheus ne "scrapera" (ne récupèrera) les métriques de ses différents moniteurs que s'ils portent bien le bon label release!. Sinon, vous risquez de chercher très, très longtemps (comme votre humble serviteur à l'époque) pourquoi vos métriques ne remontent pas.

On va déployer ces deux manifestes dans notre cluster, et vérifier leur bon fonctionnement.

On crée d'abord notre namespace:

kubectl create ns apptest
kubectl apply -f deployment.yaml -f pod-monitor.yaml
kubectl get podmonitors,deploy,pods -n apptest
# et on vérifie que tout est OK
lidstah@marfak:~$ kubectl get podmonitors,deploy,pods -n apptest
NAME                                                      AGE
podmonitor.monitoring.coreos.com/prometheus-example-app   118s

NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/prometheus-example-app   1/1     1            1           2m3s

NAME                                         READY   STATUS    RESTARTS   AGE
pod/prometheus-example-app-76c48dff8-l944k   1/1     Running   0          2m3s

On va peut être lui ajouter un petit service pour exposer ça à l'extérieur, non?

Je vous laisse faire? Normalement, ça ne devrait pas poser trop de problème 😃

Bien, maintenant, on va interroger les URLs /, /err et /metrics de notre applicatif d'exemple, afin de vérifier son bon fonctionnement (et de "préchauffer" quelques stats).

Il ne nous reste plus qu'à créer un petit dashboard Grafana pour tester tout ça:

grafana3.png

ServiceMonitor Prometheus

Alors, un PodMonitor, c'est sympa, mais il est plus intéressant de créer un ServiceMonitor, qui, comme son nom l'indique, ira interroger nos endpoints non pas directement en "tapant" sur le(s) Pod(s) de notre applicatif, mais sur un port exposé par un Service, qui nous permettra de bénéficier en rime de la répartition de charge offerte par les Services.

NOTE: Ici, notre applicatif d'exemple expose ses métriques sur le même port que l'"application". En production, on voudra séparer trafic applicatif et trafic métriques en les séparant sur des ports différents. En effet, on expose nos métriques en même temps que notre applicatif dans notre exemple, ce qui veut dire que n'importe qui sur "Internet" (ici: le réseau du labo) peut avoir accès à nos métriques. Et on a pas envie du tout de ça 😃

On va se créer un service "prometheus-example-app-metrics-svc" de type ClusterIP cette fois ci. Normalement, ça, vous savez faire 😃. Le port exposé par ce service devra être nommé "metrics" - vous pouvez le nommer différemment mais il faudra en tenir compte dans la création de notre ServiceMonitor. C'est ce service que nous utiliserons pour aller "scrapper" nos métriques.

Notre ServiceMonitor devrait ressembler à ça:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: prometheus-example-app-servicemonitor
  namespace: apptest
  labels:
    release: prom-stack
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: prometheus-example-app
  endpoints:
    - port: metrics
      interval: 15s
      path: /metrics

Comme précédemment: faites très attention au label release!

Avant de le déployer, nous allons supprimer notre podmonitor:

kubectl delete podmonitors -n apptest prometheus-example-app

De même, il faudra un peu de temps à Grafana et Prometheus pour se rendre compte de la modification PodMonitor vers ServiceMonitor, ce qui au bout de quelques minutes devrait donner ceci:

grafana4.png

Notez le "saut" entre le PodMonitor et le ServiceMonitor.

TP: Ajoutez un endpoint de métriques à votre applicatif

But

Ajoutez un endpoint /metrics à votre applicatif développé/déployé dans kube pendant le module de Benjamin.

Le but est d'exposer plusieurs métriques de votre applicatif (nombre de requêtes par seconde, temps d'exécution d'une fonction de votre code, nombre d'utilisateurs, taux de création d'utilisateurs par unité de temps, etc) pour pouvoir les "donner à manger" à Prometheus et obtenir de la visibilité sur ces métriques via un dashboard grafana.

Contrairement à l'exemple précédent, utilisez un port différent pour exposer les métriques de votre applicatif. N'oubliez pas qu'un Service peut exposer plusieurs ports. Idéalement, utilisez un Ingress pour exposer votre applicatif (donc, en renvoyant vers le port "web" de votre Service, le port "metrics" lui n'étant exposé qu'à l'intérieur du cluster).

Rendu

Oral lors du dernier cours du module, où vous devrez: