Installer un serveur Puppet scalable – partie 2



  • Suite de l’article Installer un serveur Puppet scalable – partie 1 : vous avez maintenant un serveur Puppet qui fonctionne. On va rajouter un backend MySQL pour utiliser toutes les fonctionnalités offertes par Puppet et supprimer le serveur web WEBRick pour installer Apache/Passenger ou Nginx/Passenger. Dans cet article, on part donc de la configuration présentée dans la partie 1 pour arriver à un Puppet Master avec un premier niveau de scalabilité.

    Apache + Passenger

    Installation du module Apache

    • On commence par simplement installer Apache sur notre Puppet Master :
    apt-get install apache2-mpm-worker
    
    gem install passenger
    
    • Il faut maintenant compiler le module pour Apache. On installe les pré-requis pour satisfaire l’installeur :
    apt-get install build-essential apache2-threaded-dev libcurl4-openssl-dev libapr1-dev libaprutil1-dev
    
    • Puis on compile le module Apache :
    passenger-install-apache2-module
    
    • Une fois le module compilé, il faut l’activer au niveau d’Apache. Pour cela on va créer 2 fichiers : un pour gérer le chargement du module (le .so) et un pour gérer la configuration de ce module. On pourrait tout faire au niveau du VirtualHost, mais j’essaie de respecter ici le standard Debian. Pour le fichier /etc/apache2/mods-available/passenger.load :
    LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-3.0.11/ext/apache2/mod_passenger.so
    
    • Pour le fichier /etc/apache2/mods-available/passenger.conf :
    PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-3.0.11
    PassengerRuby /usr/bin/ruby
    
    PassengerHighPerformance on
    PassengerUseGlobalQueue on
    PassengerMaxPoolSize 15
    PassengerPoolIdleTime 300
    PassengerMaxRequests 10000
    
    RackAutoDetect On
    
    • On active le module passenger :
    a2enmod  passenger
    
    • On relance Apache et on vérifie que le module est bien chargé :
    # apachectl restart
    # apachectl -M|grep passenger
    Syntax OK
     passenger_module (shared)
    

    Configuration de l’environnement

    Le module Passenger est installé, il nous reste à créer un VirtualHost dédié au Puppet Master.

    • Créer le fichier /etc/apache2/sites-available/puppetmaster. C’est votre VirtualHost dédié à Puppet. Le contenu de ce fichier est disponible sur github pour plus de lisibilité. Remplacez puppetmaster par le nom de votre Puppet Master.
    • Il faut ensuite installer l’environnement pour ce VirtualHost : après avoir créé le DocumentRoot Apache, on récupère la configuration Puppet de la webapp rack. Attention : la configuration doit absolument appartenir à l’utilisateur puppet. Passenger utilisera ces droits pour exécuter Puppet.
    mkdir -p /var/www/puppetmaster/public
    cp /usr/lib/ruby/gems/1.8/gems/puppet-2.7.9/ext/rack/files/config.ru /var/www/puppetmaster/
    chown puppet:puppet /var/www/puppetmaster/config.ru
    
    • On active ensuite le module SSL et Headers d’Apache ainsi que le VirtualHost tout juste créé :
    a2enmod ssl
    a2enmod headers
    a2ensite puppetmaster
    
    • Relancez votre serveur Apache. Vous pouvez contrôler que tout fonctionne correctement en vérifiant les logs Apache de ce VirtualHost /var/log/apache2/puppetmaster_error.log et en vous assurant que Passenger et Rack sont bien démarrés. Testez un de vos agents via puppet agent -t. Cela doit fonctionner comme décrit dans la partie 1 de cet article.

    Nginx + Passenger

    Vous pouvez choisir d’utiliser Nginx plutôt qu’Apache. Je ne rentre pas dans la comparaison, ce n’est pas le but de l’article. A vous de choisir 😉 A savoir quand même : Nginx ne supporte pas le chargement de modules comme on peut le faire avec Apache. Il faut donc compiler Nginx avec le support de Passenger.

    Installation de Nginx et Passenger

    gem install passenger
    
    • On installe maintenant Nginx via l’installation de Passenger :
    apt-get install build-essential libcurl4-openssl-dev libpcre3-dev
    passenger-install-nginx-module
    

    Vous avez deux possibilités : le choix 1 qui va récupérer les sources de Nginx puis les compiler avec le support Passenger ou le choix 2 pour lequel vous pouvez intervenir sur les options de configuration de Nginx. Je vais continuer en choisissant la deuxième option.

    0_1522746380788_passenger-install-nginx-module1.png

    • Pour le deuxième choix, il faut indiquer le répertoire qui contient les sources de Nginx. Récupérez la dernière version stable de Nginx puis décompressez l’archive dans /usr/local/src. A la date de cet article, la dernière version stable est la 1.0.11.
    • A la première question de passenger-install-nginx-module, j’indique le répertoire des sources que je viens de télécharger :
    Where is your Nginx source code located?
    Please specify the directory: /usr/local/src/nginx-1.0.11
    
    • Puis le prefix d’installation :
    Where do you want to install Nginx to?
    Please specify a prefix directory [/opt/nginx]: /usr/local
    
    • Et enfin, les options de configuration : je force par exemple le chemin de la configuration, des logs, du pid…
    Extra Nginx configure options
    If you want to pass extra arguments to the Nginx 'configure' script, then
    please specify them. If not, then specify nothing and press Enter.
    
    If you specify nothing then the 'configure' script will be run as follows:
    
      sh ./configure --prefix='/usr/local' --with-http_ssl_module --with-cc-opt='-Wno-error' --add-module='/usr/lib/ruby/gems/1.8/gems/passenger-3.0.11/ext/nginx'
    
    Extra arguments to pass to configure script: --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/nginx_error.log --http-log-path=/var/log/nginx/nginx_access.log
    
    • Après avoir validé la ligne de configuration, le compilation démarre. Nginx et Passenger sont installés. Reste à configurer Nginx !

    Un autre façon de faire…

    Vous pouvez installer Nginx et Passenger d’une façon plus classique :

    gem install passenger
    
    • On télécharge l’archive de Nginx que l’on décompresse :
    cd /usr/local/src
    wget http://nginx.org/download/nginx-1.0.11.tar.gz
    tar xvzf nginx-1.0.11.tar.gz
    cd nginx-1.0.11
    
    • On lance la compilation :
    ./configure --prefix=/usr/local --with-http_ssl_module --with-cc-opt='-Wno-error' --add-module=/usr/lib/ruby/gems/1.8/gems/passenger-3.0.11/ext/nginx --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/nginx_error.log --http-log-path=/var/log/nginx/nginx_access.log
    
    make && make install
    

    Configuration de Nginx

    • Vous trouverez sur github un exemple de configuration (/etc/nginx/nginx.conf) qui fonctionne. Remplacez puppetmaster par le nom de votre Puppet Master et adaptez worker_processes et worker_connections selon votre besoin.
    • Pour démarrer Nginx via un script d’init, vous pouvez utiliser celui là récupéré dans le paquet Debian. A installer sous /etc/init.d/nginx et à activer au démarrage via insserv -v nginx.
    • On installe la configuration pour la webapp. Attention aux droits : elle doit appartenir à Puppet.
    mkdir -p /var/www/puppetmaster/public
    cp /usr/lib/ruby/gems/1.8/gems/puppet-2.7.9/ext/rack/files/config.ru /var/www/puppetmaster/
    chown puppet:puppet /var/www/puppetmaster/config.ru
    
    • Vous pouvez démarrer Nginx via /etc/init.d/nginx start et vérifier le log d’erreurs /var/log/nginx/puppetmaster.error.log. Lancez ensuite un de vos agents et vérifiez qu’il fonctionne comme décrit dans la partie 1 de cet article.

    Monitoring de Passenger

    Deux outils sont à votre disposition pour surveiller l’activité de Passenger : passenger-status et passenger-memory-stats. Voici deux captures d’écran pour vous donner une idée de la sortie de ces deux binaires :

    1_1522746405038_passenger-memory-stats.png

    0_1522746405038_passenger-status.png

    MySQL

    Pour utiliser, principalement, les ressources exportées, il faut stocker toute la configuration des agents en base de données en utilisant la notion de Storeconfigs.

    Cette technique, très pratique voir indispensable en production, demande une base de données performante. Je vous déconseille donc d’utiliser, par exemple, sqlite. Dans l’exemple qui suit, nous allons installer MySQL sans se préoccuper de son tuning. Si vous êtes dans un contexte de production avec beaucoup de serveurs “Puppétisés”, cette étape sera indispensable. Évidemment, il est préférable d’utiliser un serveur MySQL dédié plutôt que de faire tourner MySQL en local sur le Puppet Master. Les tables créées utilise le format InnoDB, il faudra donc optimiser MySQL pour l’utilisation de ce moteur. Pour finir sur ces recommandations, il faut savoir que cette base de données n’est pas automatiquement purgée quand vous supprimez un agent/une ressource exportée : il faudra le faire manuellement avec un script. Je reviendrais précisément sur le tuning MySQL et sur le fonctionnement des ressources exportées dans des articles dédiés !

    Installation du serveur MySQL

    • Sur mon serveur MySQL dédié, j’installe le paquet MySQL :
    apt-get install mysql-server
    
    • Par défaut, MySQL écoute uniquement sur 127.0.0.1. Commentez la ligne suivante dans /etc/mysql/my.cnf et relancez MySQL :
    bind-address           = 127.0.0.1
    
    • Il faut créer la database pour Puppet ainsi que le user/pass pour y accéder. Connectez vous à votre serveur MySQL avec mysql -p :
    mysql> create database puppet;
    mysql> grant all privileges on puppet.* to puppet@puppetmaster identified by 'puppet';
    

    Changez ici puppetmaster par le nom de votre Puppet Master (en fqdn) et le mot de passe puppet par quelque chose de plus sûr.

    Configuration du Puppet Master

    • Sur votre Puppet Master, décommentez les lignes suivantes du fichier de configuration disponible sur github et adaptez les en fonction de votre configuration MySQL :
    storeconfigs = true
    dbadapter = mysql
    dbname = puppet
    dbuser = puppet
    dbpassword = puppet
    dbserver = mysql_server
    
    • Décommentez également la ligne suivante : cela permet de stocker l’inventaire facter en base de données et d’en profiter avec le dashboard par exemple.
    facts_terminus = inventory_active_record
    
    • Il faut installer quelques gems pour pouvoir communiquer avec la base de données. On force ici la version du module activerecord, sinon, ça ne fonctionnera pas (Bug #9290) ! Si vous n’installez pas la documentation des Gems, vous pouvez passer les deux premières étapes. Dans le cas contraire, il faut le faire pour éviter une erreur de génération de la documentation :
    gem install rdoc rdoc-data
    rdoc-data --install
    gem install --version 3.0.10 activerecord
    gem install mysql2
    
    • Pour terminer et prendre en compte ces changements, relancez Apache ou Nginx.

    Test et création d’index

    Lancez un client, il ne doit pas y avoir de changement. Après l’exécution d’un premier client, les tables MySQL sont créées :

    mysql> show tables;
    +------------------+
    | Tables_in_puppet |
    +------------------+
    | fact_names       |
    | fact_values      |
    | hosts            |
    | inventory_facts  |
    | inventory_nodes  |
    | param_names      |
    | param_values     |
    | puppet_tags      |
    | resource_tags    |
    | resources        |
    | source_files     |
    +------------------+
    11 rows in set (0.00 sec)
    

    Il faut rajouter des index qui ne sont pas créés automatiquement :

    mysql> use puppet;
    mysql> create index exported_restype_title on resources (exported, restype, title(50));
    

    C’est terminé pour cette seconde partie. Nous avons fait un premier pas dans la scalabilité de Puppet. Il utilise maintenant une base de données MySQL et le serveur WEBRick est remplacé par Apache ou Nginx. Dans la 3ème partie, nous verrons comment rajouter un deuxième Puppet Master avec un partage de charge.