Installer un serveur Puppet scalable – partie 3



  • Suite des articles sur l’installation d’un serveur Puppet scalable (à lire : partie 1 et partie 2). Votre PuppetMaster est installé, nous allons maintenant voir comment rajouter un autre PuppetMaster avec un partage de charge et les problématiques levées par ce fonctionnement (gestions des clés SSL par exemple). Il y a plusieurs solutions pour le partage de charge : nous verrons ici une solution à base d’HAProxy. Dans la deuxième partie de cet article, nous étudierons l’installation du dashboard de Puppet Labs.

    Préparation d’un 2ème noeud

    Une fois que votre deuxième noeud est installé (clonez le 1er noeud si vous pouvez), vous êtes face au 1er problème : comment partager vos modules Puppet, les clés SSL de vos serveurs, les rapports, les sauvegardes de fichiers via filebucket… Il y a plusieurs solutions pour gérer ce partage : un drdb, un bind mount si vous êtes sur du virtuel ou plus simplement un partage NFS. Ce n’est peut-être pas le plus performant, mais les accès disques à ces données sont réduits.

    Pour le cas précis des certificats SSL, les documentations “officielles” sur la scalabilité de Puppet font référence à l’utilisation de certificats SSL chaînés : ne partez pas dans cette direction, ça ne fonctionnera pas avec des versions “2.6” et “2.7.x” (ne fonctionne pas au moment de l’écriture de l’article : bugs à vérifier #3143 et #3770).

    Le serveur NFS a quand même un gros défaut quand on l’utilise pour partager les clés SSL. Aujourd’hui, les certificats SSL Puppet sont générés avec un serial auto-incrémenté. Il m’est arrivé d’observer, lors d’accès concurrents avec un lag NFS, un problème sur le serial SSL qui recommence à un. On se retrouve alors avec des serveurs qui ont le même serial SSL. Si vous révoquez un serveur, la révocation utilise ce serial et révoque donc plus de serveurs que prévu. Pire encore, si vous tombez sur le même serial que votre PuppetMaster, vous révoquez le certificat du PuppetMaster et donc tous les certificats de vos serveurs ! Ce problème peut éventuellement se rencontrer avec d’autres systèmes que NFS si le lock du fichier ne fonctionne pas correctement. Il est impératif de faire un bench de génération/signature de certificats SSL pour être certain de ne pas tomber sur cet problème. Une solution à coupler avec un mécanisme pour envoyer toutes les requêtes de génération/signature SSL sur un seul noeud afin de sécuriser à 100% cette problématique SSL. C’est ce que nous verrons plus loin…

    Un serveur NFS

    Nous allons donc utiliser un serveur NFS pour partager les répertoires utiles à Puppet pour un bon fonctionnement en partage de charge. Pour ce serveur, vous pouvez utiliser un serveur dédié, un filer déjà présent ou votre premier noeud Puppet. Il n’y aura pas beaucoup de trafic, inutile de voir trop grand pour ce service.

    Je passe rapidement sur la configuration du serveur NFS en lui-même. Ce qui est important dans le cadre de cet article, c’est les options de montage NFS des clients, ici les noeuds PuppetMaster.

    Sur une Debian Squeeze, j’installe un serveur NFS via :

    apt-get install nfs-kernel-server
    

    Si vous utilisez un serveur dédié, exportez un répertoire dans lequel on retrouvera les sous-répertoires suivants :

    répertoire fonction
    bucket pour les sauvegardes via filebucket. Si on ne partage pas ce répertoire, il y aura par exemple des erreurs avec le dashboard.
    fact pour les facts… sauf si, comme dans l’exemple donné dans l’article précédent, vous stockez vos facts en BDD.
    reports pour les rapports… sauf si vous supprimez le mot clé “store” du champ “reports” de vos fichiers /etc/puppet/puppet.conf sur vos PuppetMaster.
    ssl la configuration SSL de votre PuppetMaster.
    yaml la déclaration de vos classes/paramètres au format Yaml.
    modules pour vos modules… (et/ou votre répertoire qui contient vos environnements si vous en utilisez.)

    Si vous utilisez votre premier noeud comme serveur NFS, exportez les répertoires suivants :

    /var/lib/puppet/bucket
    /var/lib/puppet/facts
    /var/lib/puppet/reports
    /var/lib/puppet/ssl
    /var/lib/puppet/yaml
    /etc/puppet/modules
    

    Client NFS : montages sur vos PuppetMaster

    Vous devez monter en NFS les répertoires précédemment exportés. Pour résumer, on doit se retrouver avec les répertoires suivants sur le partage NFS :

    /var/lib/puppet/bucket
    /var/lib/puppet/facts
    /var/lib/puppet/reports
    /var/lib/puppet/ssl
    /var/lib/puppet/yaml
    /etc/puppet/modules
    

    D’après les tests que j’ai pu faire et les problèmes rencontrés, je vous conseille de désactiver le cache des attributs. Avec le cache activé, j’ai eu à chaque fois un problème sur le serial SSL (problème expliqué plus haut). Pour désactiver le cache, rajoutez noac ou actimeo=0 dans vos options de montage NFS.

    Comment tester ?

    Voici un moyen pour tester que vous n’avez pas le problème de serial SSL. Sauvegardez votre /var/lib/puppet/ssl avant ! Evitez de faire ces tests si vous avez déjà installé et signé des dizaines de clients Puppet. Vous risquez, en cas de problème, de devoir refaire toute la phase de génération/signature SSL pour tous vos clients. Je pars du principe que vous êtes toujours en phase d’installation 😉

    Sur chacun de vos noeuds, lancez une boucle de génération de certificat. Faites un tail -f sur le fichier /var/lib/puppet/ssl/ca/inventory.txt et assurez-vous que les nouveaux certificats créés ont tous un serial différent (c’est le 1er champ).

    0x006e 2017-03-17T07:31:21GMT /CN=test-ssl88-puppetmaster1
    0x006f 2017-03-17T07:32:38GMT /CN=test-ssl87-puppetmaster2
    

    Voici un exemple de boucle à lancer sur chacun de vos noeuds pour générer des certificats :

    for i in $(seq 100)
    do
      puppetca generate test-ssl${i}-`hostname`
    done
    

    HAProxy

    HAProxy est un logiciel de partage de charge niveau 4 (tcp, ce qui nous intéresse ici) et 7 (http). Nous allons dans un premier temps faire un partage de charge “global” et faire confiance à notre serveur NFS (rapport au bug SSL) puis nous verrons ensuite comme dédier un noeud pour la certification SSL.

    Installation et configuration

    On se base ici sur un nouveau serveur en Debian Squeeze fraichement installé. On installe HAProxy :

    apt-get install haproxy
    

    J’ai déposé sur github un exemple de configuration fonctionnel et commenté. Il vous suffit de l’installer à la place de votre /etc/haproxy/haproxy.cfg. Il vous restera à remplacer :

    • listen puppet 10.0.0.1:8140 : la VIP de votre service.
    • puppetmaster1.domaine:8140 : les différents PuppetMaster partagés derrière cette VIP.

    Relancez HAProxy via son script d’init. Vous pouvez consulter l’interface de stats via http://mon_haproxy:4000/stats :

    0_1522746466704_HAProxy-Stats.png

    Configurez vos clients Puppet pour qu’ils utilisent l’adresse de service correspondant à la VIP que vous déclarez au niveau d’HAProxy. Lancez ensuite plusieurs agents Puppet en parallèle pour valider le bon fonctionnement du HAProxy. Les requêtes doivent s’équilibrer entre les noeuds.

    Pour la certification SSL

    Je vous l’expliquais plus haut, pour sécuriser complètement la problématique SSL, il est possible d’utiliser HAProxy et l’option ca_port des clients Puppet. Toutes les requêtes liées à la signature des certificats SSL seront faites sur le port défini par ca_port de votre PuppetMaster. Il est ensuite facile d’intercepter ces requêtes avec HAProxy pour les envoyer sur un seul noeud. La configuration est disponible ici.

    • Comme dans la configuration précédente, vous devez adapter la configuration en fonction de votre VIP et de vos PuppetMaster.
    • Seule une connexion à la fois est autorisée : on s’assure qu’il n’y aura jamais d’accès concurrents sur le serial SSL.
    • On rajoute l’option abortonclose pour être certain qu’une requête interrompue ne bloquera jamais le service.
    • Seul un noeud est actif. L’autre est en backup du 1er s’il échoue.
    • Rajoutez la ligne ca_port dans le fichier /etc/puppet/puppet.conf de vos clients Puppet :
    [agent]
    ca_port = 8141
    report = true
    server = puppetmaster
    listen = true
    environement = production
    

    Installation du Dashboard

    Voici la procédure pour installer le dashboard Puppet. Je pars du principe que vous avez un serveur MySQL installé (comme décrit dans la partie 2 de cette série d’articles) et que vous installez le dashboard sur un serveur Debian fraichement installé. Vous pouvez simplement installer le paquet Debian proposé par Puppet Labs ou partir de l’archive. Pour la continuité des articles, je pars sur l’archive (cela permettra aussi d’utiliser par exemple Nginx à la place d’Apache). Pour cette installation, il faudra :

    • Récupérer l’archive du dashboard directement sur le site de Puppet Labs. A la date de cet article, c’est la version 1.2.6 :
    wget http://downloads.puppetlabs.com/dashboard/puppet-dashboard-1.2.6.tar.gz
    
    • Décompresser cette archive et déplacer le contenu quelque part sur le disque :
    tar xvzf puppet-dashboard-1.2.6.tar.gz
    mv puppet-dashboard-1.2.6 puppet-dashboard
    mv puppet-dashboard /usr/share/
    
    • Créer un user/group puppet-dashboard et donner les droits sur /usr/share/puppet-dashboard :
    addgroup puppet-dashboard
    adduser --home /usr/share/puppet-dashboard --no-create-home \
                    --ingroup puppet-dashboard \
                    --gecos "Puppet-Dashboard" puppet-dashboard
    chown -R puppet-dashboard:puppet-dashboard /usr/share/puppet-dashboard
    
    • Installer les dépendances Debian nécessaires :
    apt-get install rubygems1.8 ruby1.8-dev libmysqlclient16-dev
    
    • Les gems nécessaires :
    gem install rack rake rdoc rdoc-data mysql
    rdoc-data --install
    
    • Avec le user puppet-dashboard, copier le fichier config/database.yml.example vers config/database.yml et le modifier pour déclarer votre serveur MySQL. Si celui-ci n’est pas hébergé sur la même machine que votre dashboard, rajoutez la ligne suivante sur chacun des environnements que vous souhaitez créer :
    host: mon_sql.domaine
    
    • Créer une database pour le dashboard et rajouter les droits SQL (à faire pour chaque environnement souhaité) :
    mysql> create database dashboard_production;
    mysql> grant all on dashboard_production.* to 'dashboard'@'mon_serveur_dashboard' identified by 'mon_password';
    
    • Pour l’environnement de production, lancer la commande suivante pour créer les bases :
    rake RAILS_ENV=production db:migrate
    
    • Si vous souhaitez un environnement de dev/test :
    rake db:migrate db:test:prepare
    

    Il y a un certain nombre d’avertissements liés à rake. Vous pouvez les ignorer ou passer à une version inférieure de rubygems :

    gem update —system 1.7.2

    > Les bugs liés à ce problème : [#9296](http://projects.puppetlabs.com/issues/9296) et [#11669](http://projects.puppetlabs.com/issues/11669).
    
    ## Configuration du dashboard
    
    Avec votre user *puppet-dashboard*, modifiez le fichier *config/settings.yml* :
    
    * **ca_server** : c'est l'adresse de service de votre PuppetMaster.
    * **enable_inventory_service** : *true* pour avoir vos facts dans le dashboard.
    * **inventory_server** : l'adresse de service.
    * **file_bucket_server** : l'adresse de service.
    * **disable_legacy_report_upload_url** : *true*.
    
    Sur vos PuppetMaster, rajoutez le plugin *http* à la liste des vos "reports" puis décommentez la ligne *reporturl* et indiquez le bon URL (il faudra relancer votre PuppetMaster) :
    
    ```bash
    reports = log, http
    reporturl = http://mon_dashboard/reports/upload
    

    Le dashboard est installé. Toujours avec le user puppet-dashboard, vous pouvez lancer le service Web via la commande :

    ./script/server -e production
    

    Pour lancer les process qui intègrent les rapports Puppet :

    env RAILS_ENV=production script/delayed_job -p dashboard -n 4 -m start
    

    Pour lancer ces process plus proprement, j’ai récupéré du paquet Debian de Puppet Labs les fichiers d’init :

    insserv -v puppet-dashboard-workers
    

    Rendez-vous ensuite sur http://mon_dashboard:3000 :

    0_1522746480307_puppet_dashboard.png

    Avec passenger

    Nous l’avons vu dans l’article précédent, nous avons remplacé le serveur web WEBRick par un Apache/Passenger ou un Nginx/Passenger. Je vous propose la même chose ici. Reprenez l’article précédent sur l’installation du couple de votre choix et rajoutez la configuration correspondant à votre installation :

    Apache

    • Récupérez le fichier puppetdashboard : c’est votre virtualhost Apache a installer dans /etc/apache2/sites-available. Remplacez simplement ServerName par le hostname de votre serveur.
    • Activez votre virtualhost avec la commande a2ensite puppetdashboard et reloadez Apache.
    • Votre dashboard est accessible sur le port 3000. Vous pouvez vérifier le bon démarrage avec par exemple, passenger-status.

    Nginx

    • Récupérez le fichier nginx.conf : c’est la configuration pour votre serveur Nginx. Configuration a placer dans /etc/nginx/nginx.conf. Remplacez le server_name pour le hostname de votre serveur.
    • Relancez Nginx. Le dashboard est accessible sur le port 3000.
    • Vous pouvez valider le démarrage de l’appli avec passenger-status.

    Derrière HAProxy ?

    Pourquoi pas… On rajoute un noeud, un autre dashboard. Quelques petits détails à gérer :

    • Il faudra partager via NFS (ou autre, mêmes remarques que plus haut) le répertoire /usr/share/puppet-dashboard/spool. Ce répertoire est utilisé pour les rapports Puppet avant l’intégration : une fois que vous activez un deuxième noeud, les rapports Puppet sont envoyés sur l’adresse de service (à modifier donc dans la configuration de vos PuppetMaster). Si vous ne partagez pas ce répertoire, les process qui intègrent les rapports généreront des problèmes car ils n’auront pas, un coup sur deux, les rapports à intégrer.
    • Les process d’intégration sont à lancer sur un seul noeud.
    • La configuration HAProxy globale est disponible ici.
    • Vous pouvez ensuite joindre votre dashboard sur son adresse de service (qui utilise le port 80, c’est plus pratique).

    C’est terminé pour cette série d’articles. J’espère qu’ils vous auront été utiles. N’hésitez pas à partager votre expérience sur la scalabilité de Puppet : il y a de multiples solutions et toute expérience est bonne à prendre 😉