Kubernetes - Healthchecks - Cron Job Monitoring (arm64)

Lorsque tous les résultats des traitements de nuit, des tâche automatiques, sont envoyés vers votre adresse email
çà devient vite le bord… Contrôle de ceci, contrôle de cela, La lecture des emails devient très complexe et fatiguante.

Healtchecks, c’est un tableau de bord qui indique ce qui s’est bien passé et ce qui est en défaut.

Comment ca marche ? Vous exécuter la tâche, après son exécutionn vous ajouter simplement une ligne de code (curl par exemple) qui appelle l’application “healthchecks”, avec un identifiant unique et l’état du traitement (code retour de la commande par exemple 0 est OK en shell).
Cette identifiant est attribué à la tâche déclarée sur l’application “healthchecks”. Une fois la tâche créée sur l’application, celle-ci vous donne l’url unique à coller dans vos scripts (plusieurs langages supportés).

Donc le matin si tous s’est bien passé tout est vert, ou bien c’est la guirlande multicolore :)

Une tâche enregistrée sur “healthchecks” doit avoir été appellée dans le temps imparti, si ce n’est pas le cas, le tableau de bord devient rouge et il est possible d’envoyer des alertes vers plusieurs types de supports : mail, matrix,…

Installer “healthchecks” dans le cluster Kubernetes

En suivant les recommandations de “Pēteris Caune - Healthchecks Team”

Pré-requis

  • Cluster kubernetes opérationnel
  • Service Postgresql (persistence des données)
  • Vous savez exposer un service réseau kubernetes (haproxy, traefic,…)

Base de données postgresql

Créer une base de données pour l’applicatif “healthchecks”. Cette base de donnée devra être accessible de tous les “Workers” du cluster kubernetes (paramétrage pg_hba.conf nécessaire).

Exemple :

  • Nom de la base de données : hc
  • Utilisateur postgresql : hc
  • Mot de passe de l’utilisateur postgresql : mypassword

Connecté au serveur postgresql :

su - postgres
psql
CREATE USER hc with password 'mypassword';
CREATE DATABASE hc WITH TEMPLATE = template0 ENCODING = 'UTF8' LC_COLLATE = 'en_US.UTF-8' LC_CTYPE = 'en_US.UTF-8';
GRANT ALL PRIVILEGES ON DATABASE hc to hc;
\q
exit

Modifiez le fichier pg_hba.conf pour que la nouvelle base de données “healthchecks” soit accessible de tous les workers du cluster Kubernetes.

Exemple, mon cluster kubernetes comporte deux “Workers”, dont les adresses IP respectives sont :

  • 192.168.1.20
  • 192.168.1.21

Ajoutez au fichier pg_hba.conf :

host hc    hc   192.168.1.20/32  md5
host hc    hc   192.168.1.21/32  md5

puis exécuter : systemctl reload postgresql

Les informations de comptes (utilisateur/mot de passe, addresseIP/port du serveur postgresql) seront nécessaires pour effectuer le paramétrage de “healthchecks”.

Installation de “healthchecks”

Vous êtes maintenant habitués à utiliser les “manifests” Kubernetes, qui décrivent les opérations à réaliser dans le cluster. Nous allons créer le descriptif de déploiement de l’application “healthchecks”.

Manifest de déploiement

Dans cet ordre :

  • Création du “namespace”
  • Création du “Secret” pour les variables d’environnement
  • Création d’une “ConfigMap” fichier de configurationt “uwsgi.ini”
  • Création d’une “ConfigMap” optionel, seulement si vous ne pouvez pas agir sur la configuration des loadbalancers, Permet de résoudre le problème csrf django rencontré lors de la connexion à l’application, voir: chapitre TLS Termination
  • Création de “LimitRange” à adapter selon votre architecture
  • Création du “Deployment”, container readonly et user/group 999 (id user du container)
  • Création du “Service”

Contenu du fichier “manifest.yml” :

apiVersion: "v1"
kind: "Namespace"
metadata:
  name: "healthchecks"
  labels:
    name: "healthchecks"
---
apiVersion: v1
kind: "Secret"
metadata:
  name: "healthchecks-secret-envvars"
  namespace: "healthchecks"
type: "Opaque"
stringData:
  # Needed if impossible to set loadbalancer : https://healthchecks.io/docs/self_hosted_docker/  - see TLS Termination
  CSRF_TRUSTED_ORIGINS: "https://yourdomain"
  SECRET_KEY: "xxxxxxxxxxxxxxxxxxxxx"
  DEBUG: "False"
  SITE_ROOT: "https://yourdomain"
  SITE_NAME: "whatyouwant"
  ALLOWED_HOSTS: "yourdomain"
  DB: "postgres"
  DB_TARGET_SESSION_ATTRS: "read-write"
  DB_USER: "hc"
  DB_HOST: "yourpostgresqlserver hostname or ip address"
  DB_NAME: "hc"
  DB_PASSWORD: "postgres hc user password"
  # Ne pas autoriser les "auto inscriptions", vous pourriez avoir des surprises
  # un healthcheck en libre service ??
  REGISTRATION_OPEN: "False"
  DEFAULT_FROM_EMAIL: "healthchecks@yourdomain"
  EMAIL_HOST: "STMP host"
  EMAIL_HOST_USER: "credential login smtp"
  EMAIL_HOST_PASSWORD: "credential password smtp"
  EMAIL_PORT: "Smtp port 465|587"
  EMAIL_USE_TLS: "True"
---
apiVersion: "v1"
kind: "ConfigMap"
metadata:
  name: "uwsgi-ini-configmap-healthchecks"
  namespace: "healthchecks"
data:
  uwsgi.ini: |+
    [uwsgi]
    master
    die-on-term
    http-socket = :8000
    harakiri = 10
    post-buffering = 4096
    # la version originale indique processes = 4
    # Performances ok sur raspberry PI4 avec 1 et limitrange max cpu 1000m
    processes = 1
    enable-threads
    threads = 1
    chdir = /opt/healthchecks
    module = hc.wsgi:application
    thunder-lock
    disable-write-exception

    hook-pre-app = exec:./manage.py migrate
    attach-daemon = ./manage.py sendalerts
    attach-daemon = ./manage.py sendreports --loop    

---
# Needed if impossible to set loadbalancer : https://healthchecks.io/docs/self_hosted_docker/  - see TLS Termination
apiVersion: "v1"
kind: "ConfigMap"
metadata:
  name: "local-settings-py-configmap-healthchecks"
  namespace: "healthchecks"
data:
  local_settings.py: |+
    import os

    CSRF_TRUSTED_ORIGINS = os.getenv("CSRF_TRUSTED_ORIGINS", "").split(",")    


---
apiVersion: "v1"
kind: "LimitRange"
metadata:
  name: "limitrange-healthchecks"
  namespace: "healthchecks"
spec:
  limits:
    - default:
        cpu: "1000m"
        memory: "300Mi"
      defaultRequest:
        cpu: "150m"
        memory: "200Mi"
      max:
        cpu: "1000m"
        memory: "300Mi"
      min:
        cpu: "150m"
        memory: "200Mi"
      type: Container
---
apiVersion: "apps/v1"
kind: "Deployment"
metadata:
  name: "healthchecks"
  namespace: "healthchecks"
spec:
  revisionHistoryLimit: 1
  strategy:
    type: "Recreate"
  selector:
    matchLabels:
      app: "healthchecks"
  replicas: 1
  template:
    metadata:
      labels:
        app: "healthchecks"
    spec:
      securityContext:
        runAsUser: 999
        runAsGroup: 999
      containers:
        - name: "healthchecks"
          env:
            - name: "CSRF_TRUSTED_ORIGINS"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "CSRF_TRUSTED_ORIGINS"
                  optional: false
            - name: "SECRET_KEY"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "SECRET_KEY"
                  optional: false
            - name: "DEBUG"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "DEBUG"
                  optional: false
            - name: "SITE_ROOT"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "SITE_ROOT"
                  optional: false
            - name: "SITE_NAME"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "SITE_NAME"
                  optional: false
            - name: "ALLOWED_HOSTS"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "ALLOWED_HOSTS"
                  optional: false
            - name: "DB"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "DB"
                  optional: false
            - name: "DB_TARGET_SESSION_ATTRS"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "DB_TARGET_SESSION_ATTRS"
                  optional: false
            - name: "DB_USER"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "DB_USER"
                  optional: false
            - name: "DB_HOST"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "DB_HOST"
                  optional: false
            - name: "DB_NAME"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "DB_NAME"
                  optional: false
            - name: "DB_PASSWORD"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "DB_PASSWORD"
                  optional: false
            - name: "REGISTRATION_OPEN"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "REGISTRATION_OPEN"
                  optional: false
            - name: "DEFAULT_FROM_EMAIL"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "DEFAULT_FROM_EMAIL"
                  optional: false
            - name: "EMAIL_HOST"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "EMAIL_HOST"
                  optional: false
            - name: "EMAIL_HOST_PASSWORD"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "EMAIL_HOST_PASSWORD"
                  optional: false
            - name: "EMAIL_HOST_USER"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "EMAIL_HOST_USER"
                  optional: false
            - name: "EMAIL_PORT"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "EMAIL_PORT"
                  optional: false
            - name: "EMAIL_USE_TLS"
              valueFrom:
                secretKeyRef:
                  name: "healthchecks-secret-envvars"
                  key: "EMAIL_USE_TLS"
                  optional: false
          image: "healthchecks/healthchecks:v2.1"
          # imagePullPolicy : Always IfNotPresent None
          imagePullPolicy: "Always"
          securityContext:
            readOnlyRootFilesystem: true
          ports:
            - containerPort: 8000
              protocol: "TCP"
              name: "port-8000"
          volumeMounts:
            - mountPath: "/opt/healthchecks/docker/uwsgi.ini"
              name: "configmapvol-uwsgi-ini"
              subPath: "uwsgi.ini"
            # Needed if impossible to set loadbalancer : https://healthchecks.io/docs/self_hosted_docker/  - see TLS Termination
            - mountPath: "/opt/healthchecks/hc/local_settings.py"
              name: "configmapvol-local-settings-py"
              subPath: "local_settings.py"
      volumes:
        - name: "configmapvol-uwsgi-ini"
          configMap:
            name: "uwsgi-ini-configmap-healthchecks"
        # Needed if impossible to set loadbalancer : https://healthchecks.io/docs/self_hosted_docker/  - see TLS Termination
        - name: "configmapvol-local-settings-py"
          configMap:
            name: "local-settings-py-configmap-healthchecks"
---
apiVersion: "v1"
kind: "Service"
metadata:
  name: "healthchecks-app-port-0-8000"
  namespace: "healthchecks"
spec:
  type: "NodePort"
  ports:
    - port: 8000
      protocol: "TCP"
      targetPort: 8000
      name: "port-healthchecks-8000"
  selector:
    app: "healthchecks"
---

Pour installer, exécuter, à partir du master kubernetes : kubectl apply -f manifest.yml

Connexion à l’ihm “healthchecks”

L’applicatif est démarrée, le service reseau est effectif, ouvrir votre navigateur, puis indiquer l’url d’accès au service ex : https://monurlhealthchecks. Il s’agit de la première connexion, vous ne pourrez pas vous y connecter.
Il faut d’abord créer un “superuser”.

Pour exécuter cette opération, démarrer un shell dans le container “healthcheck” sur votre cluster kubernetes, puis exécuter la commande :

./manage.py createsuperuser
# Vous devrez entrer votre adresse email, un mot de passe et sa confirmation
# Pour abandonner CTRL+C

Retourner sur votre navigateur web et connectez-vous à l’application avec ce compte et son mot de passe.

Alertes

Si n’avez encore visité le site , je vous invite a regarder la partie Notifications, pour chaque cas désiré, vous devrez agir sur la configuration du container (non abordé ici).

Conclusion

Cet outil est génial et facilite grandement la vie de l’administrateur système…

+++