Catégories
Application Paramétrage Uncategorized

Migration reverse proxy apache vers HAProxy et Traefik

Afin de simplifier la configuration et permettre l’ajout de serveurs j’ai décidé de remplacer mon reverse proxy apache par le triptyque:

  1. apache pour le TLS
  2. HAProxy pour la répartition inter VM
  3. Traefik pour le routage intra VM vers les conteneurs
Architecture cible

Installation de Traefik

L’utilisation de la version docker de Traefik parait évidente puisque d’une part l’utilisation des versions dockerisées m’a montré que cela fonctionne mieux et souvent du premier coup car toute la configuration d’intégration est faite (mise en conteneur = paquet prêt à l’emploi) et d’autre part Traefix sera utilisé pour faire du routage vers des conteneurs docker !

Dans mon infra, l’installation de Traefik est très simple. Il me suffit de déclarer un nouveau projet dans mon Gitlab en suivant l’exemple dans la documentation de Traefik pour docker. Ce qui donne:

https://gitlab.bressure.net/docker/applications/traefik

Le déploiement des instantes Traefik se fait très simplement en reprenant l’exemple du .gitlab-cy.yml de mes instances prom-node puisque Traefik doit également s’installer sur toutes mes machines où docker se trouve.

Triptyque Apache / Haproxy / Traefik

Sur le schéma on voit que le port d’exposition d’un service n’a pas besoin d’être connu car Traefik va écouter les évènements du démon docker pour associer à un nom d »hôte (nom de service comme blog.bressure.net) à un port exposé où rediriger le flux. Ainsi le haproxy en amont n’a pas besoin de connaître le port d’exposition mais seulement vers quel serveur backend envoyer les flux.

Installation du HAProxy

Le haproxy fera l’objet d’une petit travail de configuration et comme l’image haproxy sur docker hub est vierge de toute configuration initiale, je vais me coller à cette tâche. Pour cela il ne suffit pas créer un projet de type applications (docker-compose) mais je vais avoir également besoin de mettre sous IC la construction d’une image personnalisée avec ma configuration. Donc je crée 2 nouveaux projets dans mon Gitlab:

  1. https://gitlab.bressure.net/docker/applications/haproxy
  2. https://gitlab.bressure.net/docker/services/haproxy

Migration progressive

La configuration de mon reverse proxy apache est sensible car c’est la pierre angulaire de mon infra en traitant le TLS et les redirections vers tous les services (dockerisés ou pas). La migration sera donc également sensible et je souhaite la faire sans interruption ce qui implique qu’elle soit progressive le temps que j’itère pour arriver à un résultat qui me satisfait.

L’objectif final sera également de

  • passer à des certificats wildcard afin de simplifier l’ajout de nouveaux services sans devoir passer par la case création d’un certificat à chaque fois
  • pour avoir accès la préprod (ie staging) sans passer par l’accès directe à la VM de préprod
  • pouvoir migrer les services docker d’un hôte à un autre sans revoir toute la configuration du haproxy.

La suite au prochain billet.

Catégories
Paramétrage

Limites de Apache en guise de reverse proxy

Depuis presque un an, mon finfra personnelle est passée à la conteneurisation avec Docker. Elle garde néanmoins un apache en guise de reverse proxy et terminaison TLS.

Apache en reverse proxy et terminaison TLS

L’utilisation de apache seul permet de facilement discriminer sur nom de domaine pour rediriger le flux vers l’ip de la VM de production et le port exposé par le serveur qui est sous forme de conteneur docker. Exemple de configuration:

<VirtualHost *:443>
        ServerName  matomo.bressure.net
   

        SSLProxyEngine On

          ProxyPass "/" "http://192.168.122.30:8085/"
        ProxyPassReverse "/" "http://192.168.122.30:8085/"

        SSLCertificateFile    /etc/letsencrypt/live/matomo.bressure.net/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/matomo.bressure.net/privkey.pem

</VirtualHost>

Or un des objectifs de départ de la mise sous forme de conteneur était de permettre la scalabilité.

Scalablité horizontale par extension de l’enveloppe de la VM

On voir sur le schéma précédent un exemple de scalabilité horizontale ou on ajoute des conteneurs au sein de la même VM pour répartir la charge sur plusieurs instances de l’application. On voit que un apache seul avec la configuration en exemple ne permettra pas d’adresser les multiples conteneurs qui exposent chacun un port différent sur la VM hôte.

Scalabilité horizontale en multipliant les VM

L’extension de l’enveloppe d’une VM a des limites liées à l’OS comme par exemple le nombre de processus gérés. Il faudra pour aller plus loin déployer les conteneurs sur d’autres VM. On va donc avoir plusieurs IP. Encore une fois une l’apache seule avec la configuration en exemple n’est pas adapté pour gérer cette répartition.

Certes il existe des configurations de type ferme de serveur qui permettent d’utiliser apache comme répartiteur de charge mais cela complexifie la configuration qui traite déjà 2 aspects: TLS et reverse proxy.

Répartiteur et routage intra VM par Traefik

Le premier type de scalabilité par extension de l’enveloppe de la VM peut être pris en charge par Traefik. Ce dernier pourrait être installé sous forme de conteneur qui s’exécute sur la VM en question. Le principe est que Traefik sera le seul à recevoir les requêtes et les routera vers les autres conteneurs en fonction du nom de domaine demandé ou de l’url. La plus value de Traefik est de gérer lui même la liaison avec les port exposées des conteneurs ce qui simplifie l’ajout de services. Un autre avantage est que Traefik sait faire de la répartition de charge. Ainsi si plusieurs conteneurs prétendent fournir le même service (via nom de domaine ou url), Traefik sera en mesure de répartir la charge entre ces conteneurs.

Traefik pour automatiser le routage intra VM

Répartiteur de charge inter VM par HAproxy

Cette fonction pourrait être occupé par Traefik par fichier de configuration mais je trouve que Traefik prend tout son sens par son mécanisme de découverte des services par écoute du démon docker. D’ailleurs il a été initialement fait pour ça, c’est-à-dire permettre d’accéder facilement sans configuration externe (comme avec mon reverse proxy apache) aux services exposés par des conteneurs.

HAproxy de sont côté offre des fonctionnalités poussées en terme de répartitions de charge au niveau TCP/HTTP. Ce qui ouvre plus de possibilités en terme de « proxification »

L’idée est d’utiliser un HAProxy pour faire la répartition entre plusieurs VM. L’ajout de VM étant une opération moins courante que l’ajout de services, la définition des fermes de serveurs pourra continuer à être manuelle dans mon infra.

HAProxy pour la répartition inter VM

Durant ces longues semaines de confinements, une migration de mon reverse proxy apache vers HAProxy/Traefik parait être une saine occupation à mes heures perdues.

Catégories
Application Paramétrage

Jitsi la vidéoconférence pour tous

Dans cette période de confinement due à l’épidémie de covid-19, la question de la communication sécurisée interpersonnelle ou de groupe pour maintenir les échanges professionnels se pose. Les fournisseurs grand public sont évidements hors jeux en terme de confidentialité d’une part à cause de la centralisation sur un serveur privé et d’autre part à cause de l’utilisation de protocoles propriétaires et de code source non libre. Sont donc exclus les solutions comme Skype ou Face Time. Le monde du libre offre des solutions bien plus intéressantes en terme de…. confidentialité et dont le maître mot est décentralisation !

Confidentialité

La question de la confidentialité est résolue par le chiffrement de bout en bout au-dessus de la couche applicative. Cela n’est évidement pas toujours possible pour des raison de performance (vidéo temps réelle) ou de commodité pour l’utilisateur. Ainsi je peux crypter mes mails avant de les envoyer, charge à mon destinataire de les déchiffrer. L’application peut fournir des facultés pour accomplir cette tâche supplémentaire avec un chiffrement intégré via OpenPGP ou encore plus simplement avec OMEMO qui ne requiert aucune compétence de la part de l’utilisateur pour s’assurer d’un chiffrement de bout en bout pour le protocole XMPP.

Décentralisation

Certaines solutions grand public propose un chiffrement entre le client et le serveur central mais rien ne garantie que le serveur central ne déchiffre pas le message avant de le transmettre au destinataire. C »est comme l’ouverture des colis par la Poste ! Le seul moyen de ce prémunir est le chiffrement de bout en bout pour garantir confidentialité et authenticité du message. Du moins momentanément.

En effet en passant par un serveur central que l’on ne maîtrise pas, les données chiffrées peuvent être stockées pour une analyse ultérieure. A moins que l’observateur ne scrute tout le réseau, on peut se prémunir simplement en utilisant un système de messagerie décentralisé dont chaque nœud est interopérable avec les autres. En allant au bout de l’idée héberger son propre nœud

Jitsi vidéo, audio et messagerie instannée

J’avais mis en place sur mon serveur personnel une instance de ejabberd qui me permet d’avoir mon propre système de messagerie instantanée sécurisé et interopérable. J’ai buté alors sur la mise en œuvre des fonctions audio et vidéo qui demandait trop d’effort d’intégration.

Jitsi est un logiciel open-source sous licence apache v2. Si originellement il était prévu pour la VoIP (audio) il est maintenant une solution de Visioconférence.

La version native s’installe comme un charme sur ma débian mais n’a pas fonctionné out of the box. Contrairement à la version dockerisée qui renforce ma conviction sur la conteneurisation: ça marche du premier coup ! En effet la partie configuration est déjà faite. Peut-être que mon problème avec la version native venait de mon infrastructure en NAT alors que avec docker l’application est forcément prévue dans une telle configuration. Dans le cas de Jitsi c’est en plus une agrégation de composants.

architecture – source : https://github.com/jitsi/docker-jitsi-meet#architecture

Out of the box

Pour rendre mon instance de Jitsi accessible depuis internet il ne m’a fallut que:

  • créer un domaine pour ce service
  • ajouter une redirection dans mon frontal apache pour ce domaine
  • ouvrir les ports TCP et UDP pour RTP de ma box pour les envoyer vers mon serveur
  • Restreindre les droits d’ouverture de conférence aux authentifiés en suivant la documentation

JItsi est orienté conférence et la messagerie instantanée est une fonction de groupe au sein d’une conférence. La solution ejabberd remplit bien son rôle mais dans le mouvement de changement et le confinement je testerai peut-être une solution plus moderne: Matrix !

Catégories
Actualité Paramétrage

Surveillance des log avec Grafana

Dans mes expériences avec Grafana et Prometheus je me contentais jusque là de reproduire avec des outils plus dans l’air du temps des fonctions remplies par Munin. Cela revient à mettre sous forme graphique des métriques numériques en montrant leurs évolutions au cours du temps. Le billet précédent clôt ce chapitre avec la mise en place d’une surveillance de l’état de mes services HTTP.

Loki un concentrateur de log

Grafana Labs la compagnie dernière Grafana (et Prometheus en employant les mainteneurs du projet) a developpé en 2018 un équivalent de Prometheus pour les journnaux ie les logs: Loki. Il s’agit de concentrer les logs en provenances de divers composants d’une application afin de pouvoir les corréler entre elles et avec les métriques d’autres sources comme Prometheus au sein de Grafana.

Promtail pour exposer les log …

Pour alimenter Prometheus il faut des métriques qui sont fournies par les applications elles-même ou part des outils intermédiaires qui exposent les valeurs pour Prometheus. Comme par exemple blackbox vu dans un billet précédent. De même pour les log, il y a l’outil intermédiaire Promtail qui va lire les logs dont la spécification est bien-sûr paramétrable pour ensuite les rendre disponibles dans Loki.

… en mode push

La différence avec Prometheus est que l’alimentation des log se fait en mode push. En effet contrairement aux métriques qui sont en générale intégrées dans Prométheus sur l’initiative de Prometheus (mode pull), l’alimentation de Loki par Promtail se fait sur initiative de Promtail (mode push).

Le schéma suivant montre en vert les composants que je mets en œuvre pour la concentration des logs de mon infra. Au conteneur Loki, j’ajoute un conteneur Promtail sur chacun des noeud pour avoir les log du système hôte via un montage du répertoire /var/log.

Loki et Promtail pour surveiller les logs dans Grafana

Cette architecture est valable dans le cadre de mon infra composée d’une seule machine physique. On voit bien que les logs sont envoyées à Loki sans confidentialité (sans passer par une brique HTTPS) ni authentification de celui qui pousse (sans un BASIC AUTH au moins). Voilà une exercice pour le prochain billet !

POC validé

Mais avant de mettre en place des mécanismes de sécurités je vais tâcher d’extraire des logs plus pertinentes au regard de mes besoins de supervision: comme la log du frontal apache ou celles des services même.


Source de mes fichiers relatifs à docker:

Catégories
Application Paramétrage Uncategorized

Tableau de bord Grafana pour surveiller la disponibilité

Dans l’article précédent je mettais en place les sondes blackbox pour Prometheus afin de tester la disponibilité de mes applications. Ces sondes placées à des endroits stratégiques doivent permettent également de diagnostiquer l’emplacement du problème eventuel dans l’architecture.

Définition de la disponibilité

J’utilisais jusque-là d’une part sur mon smartphone l’application Nock Nock qui verifie que les services web repondent bien par un code HTTP 200. D’autre part le plugin Jetpack pour wordpress surveille également mes sites, peut-être en allant plus loin que de vérifier le code de retour HTTP. Pour le moment le moment je vais mettre un place un tableau de bord sur code 200.

capture d’écran de l’appli Nock Nock

La mise en œuvre du tableau de bord de disponibilité est directe. Il suffit de prendre la métrique issue du prober http placé dans le blackbox simulant un accès par internet.

probe_success{source="internet"} 

Pour le rendu, je prends la visualisation stat avec comme calcul la dernière valeur. En effet je veux l’information instantanée de disponibilité !

Taux de disponibilité

La valeur instantanée de la disponibilité ne permet pas de dire si en général l’application est disponible sur une certaine durée.

Je définis le taux de disponibilité comme le ratio entre les success de test d’accessibilité et le nombre de tests sur une période donnée. Autrement dit c’est le pourcentage de code HTTP 200. Ainsi pour avoir le taux de disponibilité sur la fenêtre courante de Grafana, il suffit d’utiliser le calcul moyenne (mean).

Le taux de disponibilité horaire se définit par le ratio de requête en code 200 sur la période remontant à 1h jusqu’à maintenant. En faisant ce calcul sur la plage de la fenêtre courante, on a alors l’évolution de la disponibilité horaire. Le calcul de la disponibilité horaire se fait par la formule:

avg_over_time(probe_success{source="internet"}[1h])

Tendance du taux de disponibilité

Le taux de disponibilité ne permet pas de dire si le service est en évolution favorable ou en dégradation ou encore en disponibilité constante. Pour cela il faut avoir la dérivé du taux de disponibilité. On doit utiliser la fonction dériv mais on ne peut pas faire de sous -requêtes c’est-à-dire englober l’expression vue plus haut dans la fonction de dérivée.

Heureusement qu’il y a un moyen de contourner cette limitation en créant une règle d’expression dans prometheus afin de définit ce qu’est un taux de disponibilité horaire.

record: serviceDispoHoraire expr: avg_over_time(probe_success{source="internet"}[1h])

Cette expression sera évaluée et enregistrée dans la base de données temporelles de prométheus comme les autres métriques. Elle sera utilisée telle quelle pour les graphiques de taux de disponibilité horaire et avec la fonction de deriv pour avoir la tendance d’évolution du taux.

Ainsi pour avoir la tendance instantanée, il suffit de prendre la dérivée sur les 5 dernière minutes afin d’avoir un estimation de l’évolution à court terme.

deriv(serviceDispoHoraire{source="internet"}[5m])

La visualisation sera de type calcul avec comme valeur la dernière valeur. Par ailleurs si on veut une tendance sur la période de la fenêtre de grafana, il faudra prendre le type de calcul moyenne.

Tableau de bord Grafana de surveillance des services HTTP
Catégories
Application Paramétrage Uncategorized

Surveillance des services avec prometheus et blackbox

La mise en place du node exporter pour apache me permet de surveiller mon reverse proxy. Je peux ainsi m’assurer que mon infra est bien accesssible.

Cela ne m’assure pas que les services qui sont derrière le reverse proxy sont bien accessibles.

Définition de l’accessibilité

Que le reverse proxy fonctionne est une condition nécessaire, que le processus du service backend fonctionne est une nécessité également mais si par exemple le DNS ne fonctionne pas, le service n’est plus accessible. Plus généralement un service est accessible si il l’est pour son utilisateur. La métriques doit donc utiliser une sonde qui se place comme un utilisateur.

Diagnostique de non accessibilité

Cela consistera pour moi à vérifier que les url des services sont bien accessibles au travers la brique la plus externe de mon architecture. Cela revient à passer par l’IP publique de ma box soit l’url publique de mes services. Pour cela un blackbox sur l’hôte permettra de verifier les url publiques des services. De manière générale, un blackbox sera installé sur chaque neoud de l’infrastructure: l’hôte principal et les 2 VM à conteneurs.

En cas d’échec la cause du problème restera encore à chercher. Elle peut provenir de n’importe quelle brique des couches sous-jacentes: box, reverse proxy, VM, service, base de données ?

Un blackbox par hôte

Le rapidite du diagnostique de la non accessibilité demande des métriques sur les briques profondes. La box ne peut pas vraiment être testée car toute l’architecture est derrière celle-ci. Le reverse proxy est déjà testé par l’exporter apache. Pour les VM on pourra utiliser le ping de blackbox depuis la machine hôte. Un test via la blackbox de l’hôte vers l’url local des services (comme utilisé dans le reverse proxy) pourra vérifier la liaison entre le reverse proxy et les services. Enfin les blackbox sur les VM pourra vérifier l’ accessibilité des services en local. Pour ce qui est du diagnostique des bases de données, comme celles-ci ne sont pas exposées vers l’exterieur, je ne peux pas les tester depuis les blackbox de l’hôte.

Un blackbox par nœud

Mise en place des blackbox

L’opération est des plus simples. Il suffit d’ajouter le service prom/blackbox-exporter dans mon application prom-node qui regroupe tous les services distanciés sur chacun de mes noeuds.

version: "3.7"
services:
  blackbox_exporter:
    image: 'prom/blackbox-exporter'
    restart: always
    ports:
      - '9115:9115'
    volumes:
      - blackbox_conf:/etc/blackbox_exporter
....
volumes:
  blackbox_conf: {}

Je mets en volume le repertoire de configuration du conteneur blackbox-exporter car cdans mon cas j’ai dû forcer l’ipv4. Oui v4 !

Forcage IPv4

En faisant un test depuis l’hôte et en passant l’argument debug=true je voyais une erreur remontée par un composant Go qui n’arrivait pas à acceder aux urls de mes services car il prenait systématiquement l’IPv6 associé. Malheureusement cela ne marche pas même après avoir activé l’IPv6 dans le démon docker. Pour faire simple j’ai choisi de forcer l’IPv4. Comme j’ai monté la configuration en volume il suffit d’aller modifier sur l’hôte le fichier /var/lib/docker/volumes/prom-node_blackbox_conf/_data/config.yml

modules:
  http_2xx:
    prober: http
    http:
       preferred_ip_protocol: ip4

Configuration de prometheus

Pour configurer prometheus il suffit de suivre à lettre la documentation de blackbox. Remarquons la subtilité qui consiste à changer le point d’appel par l’adresse du blackbox et passer le point d’appel en paramètre car au final c’est le blackbox qui interroge le point d’appel.

- job_name: 'services depuis internet'
  metrics_path: /probe
  params:
     module: [http_2xx] # Look for a HTTP 200 response.
  static_configs:
  - targets:
    # - http://prometheus.io # Target to probe with http.
    # - https://prometheus.io # Target to probe with https.
    # - http://example.com:8080 # Target to probe with http on port 8080.
     - https://blog.bressure.net
     - https://kitejust4fun.bressure.net
     - https://mattermost.bressure.net
     - https://www.kitejust4fun.fr
     - https://owncloud.bressure.net
     - https://bikejust4fun.bressure.net
     - https://www.cramayailes.fr
     - https://matomo.bressure.net
     - https://gitlab.bressure.net
     - https://registry.bressure.net
     - https://prometheus.bressure.net
     - https://grafana.bressure.net
  relabel_configs:
     - source_labels: [__address__]
       target_label: __param_target
     - source_labels: [__param_target]
       target_label: instance
     - target_label: __address__
       replacement: 192.168.0.12:9115

Lorsque je veux vérifier que la liaison avec les backend est fonctionnelle, j’utilise directement les adresses IP dans un autre job et cela donne:

- job_name: 'services depuis infra'
  metrics_path: /probe
  params:
     module: [http_2xx] # Look for a HTTP 200 response.
  static_configs:
  - targets:
    # - http://prometheus.io # Target to probe with http.
    # - https://prometheus.io # Target to probe with https.
    # - http://example.com:8080 # Target to probe with http on port 8080.
    # blackbox infra
     - http://192.168.0.12:9115
    # blackbox production
     - http://192.168.122.30:9115
    # blog pro
     - http://192.168.122.30:8081
    # bikejust4fun
     - http://192.168.122.30:8082
    # kitejust4fun blog
     - http://192.168.122.30:8083
    # kitejust4fun asso
     - http://192.168.122.30:8084
    # matomo
     - http://192.168.122.30:8085
    # cramayailes
     - http://192.168.122.30:8086
    # owncloud
     - http://192.168.122.30:8087
    # mattermost
     - http://192.168.122.30:8088
    # gitlab, registry
     - http://192.168.0.12:8080
    # prometheus
     - http://192.168.0.12:9090
    # grafana
     - http://192.168.0.12:3000


  relabel_configs:
     - source_labels: [__address__]
       target_label: __param_target
     - source_labels: [__param_target]
       target_label: instance
     - target_label: __address__
       replacement: 192.168.0.12:9115

Comme les instances qui sont relatives au même service, par exemple ce blo sont référencées par des url différentes https://blog.bressure.net ou http://192.168.122.30:8081, il faudra faire une gymnastique dans la tableau de bord. Pour simplifier l’utilisation des métriques, je préfère ajouter un label spéciale que j’appelle service et qui me permettra de regrouper les métriques d’un même service. Pour cela j’utilise la fonction de modification des label déjà vu pour l’astuce du blackbox. Ainsi pour que mon blog j’ajoute le label service=blog par la configuration:

relabel_configs:
     - source_labels: [__address__]
       target_label: __param_target
     - source_labels: [__param_target]
       target_label: instance
     - target_label: __address__
       replacement: 192.168.0.12:9115 # The blackbox ex
     - source_labels: [instance]
       regex: 'http\:\/\/192\.168\.122\.30\:8081'
       replacement: 'blog'
       target_label: service

Test de connectivité

Le test HTTP est parfois non pertinent quand on veux juste vérifier que quelques chose répond. Il est alors suffisant de tester qu’une connexion TCP est possible. Je fais alors un job dans Prométheus:

 job_name: 'connection depuis infra'
  metrics_path: /probe
  params:
     module: [tcp_connect]
  static_configs:
  - targets:
    # - http://prometheus.io # Target to probe with http.
    # - https://prometheus.io # Target to probe with https.
    # - http://example.com:8080 # Target to probe with http on port 8080.
    # blackbox infra
     - 192.168.0.12:9115
    # blackbox production
     - 192.168.122.30:9115
    # blog pro
     - 192.168.122.30:8081
    # bikejust4fun
     - 192.168.122.30:8082
    # kitejust4fun blog
     - 192.168.122.30:8083

La prochaine étape sera de mettre en place des alertes quand les services ne sont plus disponibles.

Catégories
Application Paramétrage

Surveillance apache avec Prometheus

Dans le remplacement de Munin par Prometheus, les indicateurs systèmes (OS et docker) sont en place. Avant de supprimer munin de mes machines, il reste encore quelques éléments à reprendre commme les métriques de:

  • Apache (frontal et reverse proxy)
  • KVM
  • Mail
  • Fail2ban
  • Queue d’impression (utile ?)

Commençons par la surveillance de apache

Apache exporter

Sur le site de Prometheus on trouve une liste de logiciels complementaires poir exporter des métriques des composants connus tels que apache. De nombreuses version de cet exporter pour apache sont disponibles, sur github notament, mais je retiendrais les 3 versions suivantes:

  • httpd_exporter de https://github.com/kelein/httpd_exporter
  • apache_exporter de https://github.com/Lusitaniae/apache_exporter
  • prometheus-apache-exporter en paquet debian

Compiler avant d’utiliser…. pas user-friendly

En tant qu’informaticien et développeur à la base la compilation est une étape qui ne devrait pas effrayer. Cela tombe bien car la version de kelein est un exporter dockerisé et demande à faire une compilation avant se pouvoir etre utilisée.

Compiler en docker c’est quoi ?

Dans les projet docker, la phase build consiste à fabriquer l’image avant de pouvoir l’exécuter. Cette phase est normale lors du développement du logiciel mais ne devrait pas être imposée à l’utilisateur du logiciel.

Quand je vais acheter une voiture, elle n’est pas fournie en kit que je dois monter

Differentes stratégies de constructions

Comme l’informaticien est un utilisateur que la compilation n’effrait pas, un petit docker build . ne va pas nous gêner. Si le httpd_exporter de kelein se construit parfaitement du premier coût c’est parce qu’il embarque dans son Dockerfile tout ce qu’il faut: compilation du source en langage Go dans une image intermediaire et création de l’image finale.

httpd_exporter pas compatible avec les tableaux de bord Grafana

Le test de l’image obtenue est concluant pour peu que l’indique bien l’url cible du serveur apache accessible depuis le conteneur via l’argument

--scrape_uri="https://perso.bressure.net/server-status"

Malheureusement les métriques sont exportées sous des noms qui ne ne sont pas ceux attendus par les tableaux de bord Grafana disponibles en libre service. Ces derniers se basent sur l’exportation faite par apache_exporter de Lusitaniae.

Lusitaniae

Cette autre version semble être la plus ancienne dans la sphère Docker. De plus elle est reprise dans le paquet prometheus-apache-exporter de Debian. C’est un signe de qualité et utiliser un exporteur à la fois disponible en version conteneurisés et native permettrait de passer de l’un à l’autre plus simplement.

Autre stratégie de construction

Comme pour httpd_exporter il faut faire un buils avant d’utiliser. Je me sens comme revenu dans en 1998 où pour utiliser le mode graphique sous Linux il fallait parfois encore compiler et jouer du makefile… Cette fois-ci je déchante car le Dockefile attend un binaire dont on a bien le source Go mais pas les instructions de build…. sauf dans la documentation. Il eu été préférable de les avoir dans le source du projet même et idéalement dans un Dockerfile.

On est informaticien ? Alors on compile via les instructions données dans la documentation. Je choisi donc une version de Go un peu récente et lance la compilation via une image docker de Go. La déception ne tarda pas à venir. La construction échoue sur un problème de dépendance dans la définition du projet.

Docker c’est un peu la création de paquet

Cette mésaventure soulève un aspect non négligeable de docker. Contrairement à l’écosystème Java où un seule langage et une seule méthode (si on se réfère au temps glorieux de J2EE) permettent de construire, d’empaqueter et déployer une application, docker offre certe de repondre au problème des dépendances et d’intégration mais il ressemble sur bien des aspects à un mécanisme de paquet des distribution Linux.

Compétences multi-langage requise

En effet le mainteneur d’un paquet doit savoir compiler le logiciel à partir de son source. Cela necessite donc de connaître les mecanismes de constructions propres au langage dans lequel est écrit l’application. Dans le cas des exporter pour appache c’est le langage Go. Pour pouvoir construire l’image il ne suffit pas juste connaitre Docker mais il faut également connaitre Go. J’ai egalement expérimenté le même soucis avec un projet Rails dont l’écosystème avec les Gemfiles m’est totalement étranger.

Fournir des images au lieu des sources

Comme je vois Docker comme une couche au dessus de l’application permettant à celle-ci de s’exécuter sans que l’utilisateur ait à se soucier des dependances où autres plomberie d’intègration, cela me conforte dans l’idée de la nécessité de fournir des images à l’utilisateur et non des souces pour la commande docker build.

Paquet debian prometheus-apache-exporter

Heureusement que d’autres savent mieux que moi comment compiler des sources Go. Debian fournit d’ailleurs un paquet binaire de l’exporter apache basé sur Lusitaniae.

Cherchant la simplicité et puisque mon apache n’est de toute façon pas encore dockerisé, je me suis rabattu sur cette version native de l’exporter. Cela n’est pas sans conséquence car étant installé en service systemd le paramètrage de l’url nécessite de s’accomoder d’un paramétrage propre à l’OS. On fait du système.

Paramètrage de l’exporter apache en service

En allant consulter la documentation Debian, j’apprends que le fichier définition du service installé par le paquet est dans /lib/systemd/system/prometheus-apache-exporter.service et non pas dans /etc/systemd/system/

En allant voir ce fichier on découvre qu’un fichier de variable est utilisé et que la variable ARGS permettra de paramétrer notre exporter.

EnvironmentFile=/etc/default/prometheus-apache-exporter ExecStart=/usr/bin/prometheus-apache-exporter $ARGS

Il ne reste plus qu’à aller ajouter dans /etc/default/prometheus-apache-exporter le paramètre

ARGS='-scrape_uri https://perso.bressure.net/server-status/?auto'

Notez que l’argument ne contient qu’un seul tiret dans le service et deux en ligne de commande docker. Je passe sous silence la sécurisation qui rend l’url du status de apache accessible seulement en local.

Tableau de bord grafana

A ce stade les métriques suivantes sur apache peuvent être disponibles dans Prometheus. Il suffit de déclarer un nouveau job pointant sur le endpoint offert par l’exporter. Par exemple dans le fichier prometheus.yml:

- job_name: apache
honor_timestamps: true
scrape_interval: 15s
scrape_timeout: 10s
metrics_path: /metrics
scheme: http
static_configs:
- targets:
- 192.168.0.12:9117

On peut alors avoir ce genre de graphique:

Graphique prometheus d’une métrique apache

En utilisant un tableau de bord en libre service sur le site de grafana, on peut avoir ce genre de graphiques sans aucune configuration supplémentaire:

Tableau de bord Grafana pour apache

On a réussi facilement à remplacer Munin par Prometheus pour surveiller apache. La prochaine étape sera de passer sous Prometheus la surveillance des VM. La suite au prochain billet.

Catégories
Application Paramétrage

Les alertes avec Prometheus

Remplacer munin par Prometheus se serait complet sans la partie envoi des alertes. Dans mon cas un simple mail suffira.

Alertmanager

Comme tout est dockerisé chez moi, je vais donc ajouter dans mon application de monitoring le service alertmanager. Le rôle de l’alertmanager est de recevoir les demandes de notification quand une métrique a une valeur donnée. Les fonctions de l’alertmanager sont entre autres de temporiser, relayer ou inhiber les notifications.

Grafana peut également envoyer des notifications mais comme je l’ai déjà mentionné, je ne vais l’utiliser que pour sa fonction de tableau de bord. Par ailleurs Grafana peut envoyer des alertes vers l’alertmanager donc ce dernier jouera parfaitement son rôle en recevant les demandes de notification de la part de Promethéus ou Grafana.

Alertes

Créer des alerte est relativement simple. Si munin est fournit avec beaucoup de plugin déjà éprouvés, il va falloir ajouter les alertes de bases comme: la saturation cpu, mémoire ou disque.

Paramétrage d’une destination mail dans l’alertmanager

Comme je définis un volume pour le conteneur alertmanager via mon fichier docker-compose.yml de l’appication de monitoring

   alertmanager:
      image: 'prom/alertmanager'
      restart: always 
      volumes:
        - alertmanager_conf:/etc/alertmanager

Il suffit depuis l’hôte docker de modifier le fichier /var/lib/docker/volumes/monitoring_alertmanager_conf/_data/alertmanager.yml

Voici le contenu qui permet de configurer l’envoi de mail, à modifier pour adapter à votre configuration de mail !

global:
  resolve_timeout: 5m
  smtp_smarthost: 'mon.serveur.smtp.com:587'
  smtp_from: 'monadresse@mail.com'
route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1h
  receiver: 'mail_to_admin'
receivers:
- name: 'web.hook'
  webhook_configs:
  - url: 'http://127.0.0.1:5001/'
- name: 'mail_to_admin'
  email_configs:
  - to: destinataire@mail.com
inhibit_rules:
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning'
    equal: ['alertname', 'instance']

Configuration de prometheus pour utiliser l’alertmanager

L’application de monitoring utilise une image personnalisée de prométheus dont le seul but est de fournir une configuration de base visible dans le fichier prometheus.yml.

La partie importante est celle-ci:

rule_files:
  - '/etc/prometheus/rules/*'
alerting:
  alertmanagers:
  - static_configs:
    - targets: ['alertmanager:9093']
    scheme: http
    timeout: 10s
    api_version: v1

Ajout d’un alerte d’occupation disque

Dans le fichier de configuration prometheus.yml on a indiqué de prendre tous les fichiers du répertoire /etc/prometheus comme règles. Il suffit alors d’ajouter dans ce répertoire les fichiers de règles des alertes. Comme prométheus est dans un conteneur, il faudra aller sur machine hôte dans le répertoire /var/lib/docker/volumes/monitoring_prometheus_conf/_data/rules/

Voici par exemple le contenu d’un fichier qui donne l’alerte quand l’occupation disque dépasse 80%

groups:
- name: disk
  rules:
  - alert: diskUsage
    expr: 1 - node_filesystem_free_bytes / node_filesystem_size_bytes > 0.8
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: consommation disque eleve

Règles enregistrées

On pourra factorisé les calculs de métriques qui peuvent être coûteux et partager le résultat dans des définitions d’alerte. Ainsi dans l’exemple suivant on calcul un seul fois l’occupation d’overcommit et 2 alertes réutilisent le résultat:

groups:
- name: memoire
  rules:
  - record: memoire:overcommit
    expr: node_memory_Committed_AS_bytes / (node_memory_MemTotal_bytes + node_memory_SwapTotal_bytes) 
  - alert: overcommit
    expr: memoire:overcommit > 0.9
    for: 10m
    labels:
      severity: critical
    annotations:
      summary: surconsommation memoire
  - alert: overcommit
    expr: memoire:overcommit > 0.8 and memoire:overcommit <= 0.9
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: surconsommation memoire

L’étape suivante sera la surveillance de l’espace disque occupé par docker. Il peut être intéressant de suivre l’évolution de cette métrique et se sera l’occasion d’apprendre à étendre le node-exporter de prométheus. La suite au prochain billet…

Catégories
Application Paramétrage

Docker sur VM et réseau

J’ai eu surprise de voir que ma surveillance ne fonctionnait plus avant hier. Pourtant d’après la capture prise vendredi soir tout semblait fonctionner.

Il y a 2 jours la connexion entre mon conteneur Prometheus et les conteneurs prom-node et cAdvisor situés sur des VM étaient devenu impossible. Toute la configuration reseau est du standard à savoir:

  • conteneur avec reseau bridge dédié par défaut avec docker-compose
  • VM avec reseau NAT par défaut avec virsh/KVM
connexion conteneur sur hôte vers conteneur sur VM impossible

Un test avec telnet m’a alors montré que depuis la machine hôte on pouvait joindre les conteneurs sur VM avec l’IP des VM gérée par KVM. Cependant depuis le conteneur sur l’hôte si l’accès à l’hôte lui-même était possible, un telnet vers les IP des VM échouait

Il faut dire que tout le paramètrage réseau mis en place par KVM et docker est un peu mystèrieux pour moi et je fais confiance à ceux qui savent plus que moi paramétrer le réseau…

Solution rapide

Comme depuis l’hôte la connexion vers les conteneurs sur VM NAT est possible alors une solution rapide est d’indiquer à Docker de mettre le conteneur Prometheus dans un réseau de type hôte. Dans le fichier docker-compose.yml au même niveau que image ajouter:

network_mode: "host"
Solution rapide, passer par l’hôte

Solution pérenne : le réseau overlay

La solution précédente enlève l’isolation reseau du conteneur Prometheus avec l’hôte et cela me gêne. De plus le conteneur grafana ne pouvait plus accéder à prometheus par son nom. Il fallait le faire passer par l’IP de l’hôte.

Une autre solution serait de mettre le conteneur prometheus dans une VM, car les VM se voient entre-elles par défaut. Un test telnet m’avait montré que les conteneurs d’une VM pouvait via l’IP des autres VM accéder aux conteneurs de ces VM.

Cette autre solution me gêne également car elle fait reposer la connectivité sur un paramétrage réseau géré par virsh/KVM. Idealement on voit aisément que les conteneurs dévolus au monitoring doivent être dans le même réseau et ce réseau doit chevaucher plusieurs démons docker sur des hôtes différents. C’est un réseau overlay !

Solution idéale : le reseau overlay

La mise en place du reseau overlay est une opération un peu complexe car il faut initialiser un neoud swarm maître sur l’hôte de prometheus, créer un réseau overlay dédié au monitoring, sur les hôtes de cAdvisor/prom-node il faut déclarer docker comme membre du swarm et enfin indiquer des les fichiers docker-compose que tous les conteneurs doivent utiliser le reseau overlay précédemment créé. Ici on avait créé un réseau appelé monitoring-net

networks:
  default:
    external:
       name: monitoring-net

Je ne suis pas allé au bout de la solution idéale de l’overlay car en créant seulement le reseau overlay et en y mettant prometheus, tout est retombé en marche. Je suis alors revenu en arrière et tout continue de fonctionner comme vendredi soir…. Je n’aime pas quand les choses tombent en marche. Affaire à suivre en gardant ce billet sous le coude.

Catégories
Application Paramétrage

Monitorer ses applications (docker) avec Prometheus et Grafana

Après avoir réglé mes soucis de mise à jour de Owncloud, je me suis remis à mes aventures avec Prometheus et Grafana.

Config de Prometheus embarquée

Comme mon infrastructure ne change pas entre mes environnements, j’ai tout d’abord pensé mettre le fichier de configuragion /etc/prometheus/prometheus.yml dans l’image docker de prometheus. Le code source final de cette petite manipulation se trouve ici https://gitlab.bressure.net/docker/services/prometheus

Enrichissement de la couche infra

Puis il suffit de construire l’application monitoring avec docker-compose en ajoutant le service grafana. Le tout devra s’executer sur mon instance docker que je qualifie d’infrastructure car sémantiquement ce n’est ni un poste de développement (bien qu’il ait aussi ce rôle dans les faits), ni de la production.

Nous obtenons alors une application de monitoring dont la seule source de métrique est l’instance de prometheus elle-même qui expose ses propres valeurs. Quand à grafana il faudra lui ajouter une source de données de type prometheus qui sera désignée par son url http://prometheus:9090/. La résolution du nom prometheus sera faite par le DNS de docker au sein du réseau construit par ses soin grâce au docker-compose.yml.

Mon objectif est de faire de prometheus le centralisateur de toutes les métriques et grafana sera le traceur de graphique avec comme unique source de données prometheus.

Ajout des sources à monitorer

Il faut donc ajouter des sources de données dans prometheus. C’est ce qui s’appelle dans la terminologie de prometheus des job avec pour chacun d’eux des endpoints c’est-à-dire des adresses exposant au bon format les valeurs des métriques. Ainsi prometheus lui-même est un endpoint comme vu plus haut.

Gitlab

Mon conteneur GitLab est capable d’exposer des métrique applicative (données métiers) au format prometheus. Cela sans grand effort. Il suffit d’activer prometheus dans GitLab…. même pas c’est sans déjà la cas ! Il ne faut même pas chercher à modifier la configuration dz Gitlab pour rendre le endpoint visible de l’exterieur du conteneur, GitLab fournit déjà une url avec un token secret pour accéder aux metriques. La contrepartie de cette facilité est que le endpoint prometheus du GitLab sera accédé via une url externe ie celle du gitlab !

Voilà pourquoi ma configuration de Prometheus ne peut pas être entièrement dans l’image Prometheus car le token secret dépend de l’instance GitLab c’est donc applicatif et pas structurel. De plus ce secret ne doit pas aller dans le code source que je veux public !

Métriques systèmes

Sur le schéma précédent on voit en vers Prometheus servant à lui lui-même de endpoint et en bleu la liaison avec GitLab.

Une fonction de munin, qui est sans doute la première, est le monitoring des constantes du système (mémoire, cpu, disque ….). Avec prometheus, ce sont les node exporter installé sur chaque machine qui vont exposer ses métriques sous forme de endpoint Prometheus. J’installe donc ces node exporter sur chacune de mes VM, bien entendu dans leur version dockerisée what else ? Le source trivial de cette manipulation se trouve ici https://gitlab.bressure.net/docker/applications/prom-node

Métriques docker

L’application docker, le démon docker, est elle-même une application intéressante à surveiller. Avec munin j’utilisais une sonde qui remontait l’utilisation cpu et mémoire de chaque conteneur. Pour Prometheus j’ai testé 2 solutions.

Le démon docker lui-même peut exporter des métriques prometheus. Il faut activer cette fonction expérimentale dans le fichier /etc/docker/daemon.json

{
"metrics-addr" : "IP_HOTE:9323", "experimental" : true
}

L’autre solution s’appelle cAdvisor une image docker dont google est à l’origine et qui expose un plus grand nombre de métrique que celles exposées par le démon docker lui-même. Comment ce fait-il ? En montant les répertoires systèmes de l’hôte dans le conteneur cAdvisor:

sudo docker run \ --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:ro \ --volume=/sys:/sys:ro \ --volume=/var/lib/docker/:/var/lib/docker:ro \ --volume=/dev/disk/:/dev/disk:ro \ --publish=8080:8080 \ --detach=true \ --name=cadvisor \ gcr.io/google-containers/cadvisor:latest

Node exporter, cAdvisor, démon docker

Le trio gagnant des outils d’export de métriques semble être:

  • Le démon docker lui-même mais exporte seulement les données essentielles et ce n’est pas une fonctionnalité pérenne
  • cAdvisor qui est beaucoup plus complet mais demande un accès également complet au système de fichiers hôte en lecture certes mais….
  • Le node exporter de prometheus moins riche que cAdvisor mais avec une possibilité d’extension
Trio gagnant des sondes à métriques

On voit que les sondes node exporter de prometheus et cAdvisor de google, sont des composants réutilisables et installables en bloc sur mes différents environnements: infra, staging et production. Je vais donc avantageusement les regrouper dans un projet docker compose prom-node. Finalement l’architecture de monitoring devient la suivante:

Bilan

Avec quelque configuration qui se résument à assembler des conteneurs entre eux, j’arrive à avoir une solution uniquement visuelle pour l’instant, de surveillance de mon infra. Je m’appuie pour cela sur:

  1. une image de Prométheus avec une configuration taillée sur mesure. Ce point est facultatif et je pouvais me contenter de l’image originale https://gitlab.bressure.net/docker/services/prometheus
  2. une application combinant Prometheus pour la collecte et Grafana pour la restitution https://gitlab.bressure.net/docker/applications/monitoring
  3. Des sondes sous forme de conteneur qui expose les métriques pour Prometheus https://gitlab.bressure.net/docker/applications/monitoring
  4. Un configuration des démons docker pour exposer des métriques Prometheus. Attention fonctionnalité expérimentale selon docker.

La prochaine étape sera d’ajouter des alertes afin de reproduire toutes les fonctions de munin.