Catégorie : Technique

  • ProxySQL : le complément absolu pour MySQL / MariaDB

    ProxySQL : le complément absolu pour MySQL / MariaDB

    ProxySQL est un outil que nous utilisons fortement dès lors que nous sommes en présence de base de données MariaDB / MySQL. Il nous permet de facilement ajouter une couche entre le moteur de bases de données et l’applicatif pour

    • nous permettre de surveiller le trafic qui passe
    • obtenir des statistiques sur l’utilisation des requêtes notamment, celles les plus utilisées / consommatrices / lentes
    • ajouter une petite couche de firewalling sur les requêtes
    • du routage fin dans le cas d’un cluster de bases de données où on veut dédier des serveurs pour la lecture et d’autres pour l’écriture (cluster Galera)
    • ajouter du cache sur des requêtes alors que l’applicatif ne le supporte pas nativement

    ProxySQL a d’autres fonctionnalités que nous n’utilisons pas pour le moment car le cas ne s’est pas présenté, mais il est, par exemple, possible de modifier une requête et de la réécrire. L’idéal est de la corriger à la source mais quand cela n’est pas possible ou que cela demande un certain temps, ce petit « patch » peut vous sauver des productions.

    Comment fonctionne t-il ?

    C’est un daemon qui écoute sur le port 6033 … (les plus alertes auront noté l’utilisation du port du protocole MySQL à l’envers (3306)), et dispose d’un port de gestion qui est le port 6032. Ce port de gestion est utilisable avec le client classique MySQL ou MariaDB pour donner des instructions de configuration à ProxySQL

    ProxySQL écoute sur le port 6033 et se tient prêt à recevoir les connexions utilisateur. Ainsi, une application PHP, Java, Golang … se connectera sur le port 6033 et bénéficiera directement des fonctionnalités de ProxySQL.

    ProxySQL maintient un pool de connexion avec ses clients directs mais également avec le ou les serveurs de base de données. La mise en oeuvre est très simple, il suffit de modifier le port de l’application et c’est fait

    Quelques cas d’usage chez Devclic

    Surveillance du trafic en vue d’optimiser les performances

    Dans le cadre de notre activité d’infogérance, nous utilisons ProxySQL pour surveiller les bases de données que nous avons en gestion en l’activant sur les solutions de serveurs que nous infogérons.

    L’application se connecte à ProxySQL et nous avons alors un log complet de tout ce qui passe par celui-ci et pouvons identifier des requêtes qui sont lentes, non optimisées, la récurrence de celles-ci avec par exemple ce type de requêtes que nous demandons à ProxySQL

    select count_star,sum_time,(sum_time/count_star)/1000 as average_time_ms,digest_text  from stats_mysql_query_digest  where count_star > 100 order by average_time_ms desc limit 4;

    Nous avons alors en sortie la liste des 4 requêtes les plus appelées / consommatrices de temps

    Grâce à ces informations, nous pouvons tester la requête au moyen d’un EXPLAIN et voir les décisions qui sont prises par le moteur pour traiter la requête. On peut avoir la même chose avec le slowlog mais ici, on a une donnée rapide qui est le temps de la requête vis à vis du nombre de requête. Cela évite un long processus couteux de retraitement des logs

    Gestion de la charge dans le cas d’un cluster Galera

    Nous utilisons des clusters Galera pour la gestion des entrées DNS via des applications que nous avons développées et qui répondent au serveur DNS en lui fournissant les enregistrements DNS demandés.

    C’est un savant mélange entre génération à la volée d’enregistrements DNS et de données stockées dans des clusters Galera

    Dans le cas des maintenances que nous sommes amenés à réaliser, ProxySQL va router les requêtes vers les noeuds en fonction de contraintes que nous lui donnons et de l’état de chaque noeud Galera

    Au besoin, nous avons également la possibilité de mettre en place du cache sur des requêtes (exemple un flood sur le DNS)

    Nos noeuds Galera sont répartis entre 5 sites, l’application n’a aucune idée qu’elle fonctionne en cluster, c’est ProxySQL qui s’occupe de gérer cela.

  • En route vers Traefik 3

    En route vers Traefik 3

    Traefik est un load balancer permettant d’appliquer dynamiquement des configurations qui collent aux containers Docker faisant ainsi que la configuration de celui-ci est totalement dynamique grâce aux labels

    Nous l’utilisons depuis la version 1, puis nous sommes passés à la version 2 et dorénavant la version 3

    La version 3 apporte le support de HTTP 3, en effet, nous étions bloqués en version 2

    Pourquoi Traefik ?

    Comme nous le disions plus tôt, quand on a des containers, le plus simple pour les mettre en ligne est de définir la configuration avec des labels, afin que la Traefik se configure et utilise, si plusieurs backends sont présents, les backends déclarés et fasse le load balancing nativement

    Ce qui est surtout intéressant est que chaque container porte sa configuration de load balancing. Ainsi, si on détruit le container, la configuration est effacée avec

    Un autre avantage de Traefik est qu’il gère nativement toute la partie LetsEncrypt et ce, de façon dynamique. Si vous déclarez vouloir un certificat SSL LetsEncrypt, Traefik va se charger de le générer et de gérer le renouvellement. Il faut au passage que tout ceci soit disponible sur internet, sinon cela ne fonctionne pas.

    Comment nous déployons Traefik ?

    Traefik est déployé en entrée de réseau, et écoute les ports HTTP(s) les plus classiques, à savoir les ports 80 et 443.

    Nous lui dédions un sous-réseau nommé gateway ou ingress par exemple, dans lequel on viendra connecter les serveurs Web / load balancer / applications qui sont à présenter sur internet.

    Chaque application est ainsi connectée dans le réseau ingress / gateway avec une adresse IP qui lui est propre où traefik lui adressera le trafic reçu. Chaque application possède également son propre réseau applicatif qui lui est dédié, permettant ainsi une communication sans limite entre les différents composants la formant

    Voici un exemple de configuration :

    Pour la partie traefik

    services:
      reverse-proxy:
        image: traefik:v3
        container_name: traefik
        restart: "always"
        command:
          - "--accesslog=true"
          - "--api.insecure=true"
          - "--providers.docker=true"
          - "--providers.docker.network=gateway"
          - "--providers.docker.exposedbydefault=false"
          - "--entrypoints.web.address=:80"
          - "--entrypoints.websecure.address=:443"
          - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
          - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
          - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
          - "--certificatesresolvers.myresolver.acme.email=XXX@XXX.fr"
          - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
        ports:
          # The HTTP port
          - "80:80"
          - "443:443"
        volumes:
          - "./letsencrypt:/letsencrypt"
          # So that Traefik can listen to the Docker events
          - /var/run/docker.sock:/var/run/docker.sock
        networks:
          - default
        logging:
          driver: "json-file"
          options:
            max-size: "10M"
            max-file: "3"
    
    networks:
      default:
          name: gateway

    Pour une application (ici notre blog)

    services:
      blog_devclic_website:
          image: XXXXXXXX
          restart: always
          ulimits:
           memlock:
            soft: -1
            hard: -1
          networks:
            - default
          labels:
            - "traefik.enable=true"
            - "traefik.http.routers.blog_devclic_fr.rule=Host(`blog.devclic.fr`)"
    
    networks:
      default:
          name: gateway

    Notre blog n’a pas de base de données au sens propre, de ce fait, il n’a pas besoin d’un réseau dédié. Mais si vous avez une base de données quelconque, type MongoDB, MySQL ou autre, vous pouvez alors créer un réseau pour votre application et l’utiliser avec votre applicatif, cela vous permet de séparer la couche présentation des autres couches applicatives

    Et pour mettre à jour Traefik, nous utilisons watchtower, nous nous retrouvons ainsi, avec la dernière version de Traefik stable sans que nous ayons besoin de nous en occuper

  • Lets’Encrypt ne permet pas de sécuriser une url contenant une adresse IP

    Lets’Encrypt ne permet pas de sécuriser une url contenant une adresse IP

    Un certificat SSL sur une adresse IP ?

    Récemment, nous sommes tombés sur le cas où un besoin était de fournir un certificat SSL valide mais pour une adresse IP

    Le problème provenait d’un outil qui fait des tests de sécurité et indique une score. Cet outil, ne fait pas la distinction entre nom de domaine et adresse IP et attribue le même score, dès qu’un certificat auto-signé est fourni

    A notre sens, cela ne sert à rien et c’est un problème de l’outil. En effet, personne ne va consulter le contenu qui est présent sur une adresse IP directement … et pour ces raisons :

    • Les noms de domaine existent pour justement ne pas retenir une adresse IP mais aussi permettre d’héberger plusieurs contenus derrière la même adresse IP
    • Un certificat auto-signé n’est pas grave en soit, le protocole SSL fonctionne tout de même et les échanges entre le client et le serveur sont chiffrés

    Comment résoudre ce problème ?

    Vu que Lets’Encrypt ne propose pas de sécuriser des adresses IP via des certificats SSL, il faut donc passer par une autre autorité de certification comme GlobalSign par exemple qui elle le propose à travers ses certificats Organization.

    Cela commence à faire cher pour juste mettre en place un certificat SSL sur une adresse IP

  • Docker et cron : comment faire ?

    Docker et cron : comment faire ?

    Récemment, sur un projet, nous utilisons, afin de séparer les environnements, des conteneurs Docker. Ce projet utilise des crons pour diverses opérations, la question que nous nous posions est comment exécuter des crons dans un conteneur Docker ?

    Qu’est ce qu’un cron ?

    Un cron est un « programme » ou un script executé automatiquement par un système informatique et selon un planning bien défini.

    On peut ainsi exécuter des taches précises à des moments précis. Les crons fonctionnent aussi bien sous Linux, Unix que Windows. Dans le cas de notre article, ici, nous traitons de la partie Linux

    On peut par exemple utiliser des crons pour sauvegarder des données, transférer des données, importer des données et bien d’autres possibilités sont offertes par cette fonctionnalité

    Crontab à la rescousse

    Etant donné qu’ici, il s’agit d’un serveur exécutant des conteneurs, nous pouvons utiliser tout bêtement la crontab et déclarer les exécutions voulues de cette façon :

    0 18 * * 1-5 /usr/bin/docker exec XXXX php lechemindemonfichier.php

    Ici, pour faire simple, on lance tout simplement un cron normalement et on demande à Docker de lancer dans le conteneur nommé XXXX de lancer la commande précisée, ici, une commande PHP

    Attention

    Cela fonctionne plutôt bien, dès lors que nous ne mettons pas l’instruction -it demandant à docker de lancer un pseudo terminal et forçant le cron à ne pas s’exécuter correctement

    Les symptômes sont simples, on voit le cron se lancer mais rien ne s’exécute à cause de ces arguments dans la commande

  • Xdebug et JIT ne font pas bon ménage

    Xdebug et JIT ne font pas bon ménage

    Il arrive parfois d’installer un peu follement beaucoup de paquets sur les distributions et d’arriver à avoir XDebug activé. Il nous est arrivé un cas ou JIT ne fonctionnait pas et n’avait aucun impact positif sur les performances

    Il suffit pourtant de lire la documentation

    Nous ne comprenions pas le pourquoi du comment et c’est en fouillant que la documentation de Xdebug nous a éclairé :

    PHP 8 JIT

    Xdebug does not work with PHP’s JIT engine, which is implemented in Opcache. When Xdebug is loaded with PHP’s JIT on, you will get a warning, and JIT will be disabled.

    Si Xdebug rencontre JIT, il le désactive tout simplement.

    Xdebug : à n’utiliser que pendant le développement

    Au final, n’activez pas Xdebug sur votre production et si vous l’avez sur un autre environnement et que vous faites des tests de charge, pensez à le désactiver temporairement pour que vous puissiez avoir un test proche du réel

  • Récupérer un fichier dans une machine virtuelle à l’aide des VMWare Tools

    Récupérer un fichier dans une machine virtuelle à l’aide des VMWare Tools

    Dans le cadre d’un projet pour un client, nous avons été amené à récupérer des fichiers présents dans une machine virtuelle à l’aide des VMWare Tools. Pour ce faire, rien de plus simple, il faut utiliser l’API de VMWare, dans notre cas, nous avons fait le choix d’utiliser du Python et pyvmomi

    But de l’opération ?

    Sur une machine par exemple piratée, il est alors possible, en déconnectant la machine du réseau, de récupérer son contenu qui pourrait ne pas avoir été sauvegardé, ou bien encore, à travers une autre API de VMWare, lancer un exécutable qui écrirait dans un fichier de logs le résultat et en récupérer le résultat pour analyser.

    On peut récupérer des fichiers mais on peut également en envoyer et on peut également lancer des commandes à travers les VMWare Tools. La récupération de données ne peut se faire que sur des fichiers, il faut donc zipper le contenu si vous avez besoin de récupérer un ensemble de fichiers.

    On veut du code …

    from pyVim.connect import SmartConnectNoSSL, Disconnect
    from pyVmomi import vim, vmodl
    import argparse
    import getpass
    
    def get_args():
        parser = argparse.ArgumentParser(description='Arguments for talking to vCenter')
        parser.add_argument('--host', required=True, action='store', help='vCenter host')
        parser.add_argument('--user', required=True, action='store', help='User name to use')
        parser.add_argument('--password', required=False, action='store', help='Password to use')
        parser.add_argument('--vm-name', required=True, action='store', help='Name of VM to interact with')
        parser.add_argument('--file-path', required=True, action='store', help='Path of the file to retrieve from the VM')
        parser.add_argument('--guest-user', required=True, action='store', help='Guest OS user')
        parser.add_argument('--guest-password', required=True, action='store', help='Guest OS password')
        args = parser.parse_args()
    
        if not args.password:
            args.password = getpass.getpass(prompt='Enter password for vCenter: ')
    
        return args
    
    def main():
        args = get_args()
    
        # Connect to the host without SSL certification verification
        si = SmartConnectNoSSL(host=args.host, user=args.user, pwd=args.password)
        content = si.RetrieveContent()
    
        # Find the VM
        vm = None
        for child in content.rootFolder.childEntity:
            if hasattr(child, 'vmFolder'):
                datacenter = child
                vmFolder = datacenter.vmFolder
                vmList = vmFolder.childEntity
                for vm in vmList:
                    if vm.name == args.vm_name:
                        break
                if vm:
                    break
    
        if not vm:
            print("VM not found")
            return
    
        # Set up guest file manager
        creds = vim.vm.guest.NamePasswordAuthentication(username=args.guest_user, password=args.guest_password)
        gfm = content.guestOperationsManager.fileManager
    
        # Define the file to retrieve
        guestFilePath = args.file_path
    
        # Generate a URL to download the file
        try:
            fileTransferInformation = gfm.InitiateFileTransferFromGuest(vm, creds, guestFilePath)
            print(f"Download URL: {fileTransferInformation.url}")
        except vmodl.MethodFault as error:
            print("Error: ", error.msg)
    
        # Disconnect from the host
        Disconnect(si)
    
    if __name__ == "__main__":
        main()

    Vous pouvez récupérer votre fichier à l’adresse indiquée par Download URL. Comme vous pouvez le voir, les VMWare tools doivent être installés et fonctionnels. Il faut également un nom d’utilisateur et un mot de passe pour pouvoir récupérer du contenu.