Mise en place de Puppet, un gestionnaire de configuration Linux/Unix

Puppet est un logiciel libre de gestion de configuration centralisée. En d'autres termes, au lieu de devoir gérer les configurations de chaque machine d'un parc à la main, nous allons mettre en place un serveur Puppet, auquel se connecteront les postes clients, qui appliqueront automatiquement les configurations spécifiées par Puppet. Il pourra s'agir aussi bien de commandes à lancer, que de logiciels à installer, ou encore de fichiers de configuration à modifier. Vous l'avez compris, une telle automatisation peut vous faire gagner beaucoup de temps.

À noter qu'il existe d'autres gestionnaires de configuration, comme Chef ou Cfengine. Si vous hésitez entre telle ou telle solution, d'autres personnes débattent déjà de cela (par exemple ici ou ), et je vous conseille dans tous les cas de tester vous-même afin de mieux apprécier les qualités et les défauts de chacune.

Dernière chose à savoir, Puppet est compatible Linux, dérivés Unix (MacOS X, BSD), et il tend vers une compatibilité Windows (basique et expérimentale pour le moment).

Principe de fonctionnement


Le tout fonctionne sur un modèle client-serveur. Le serveur Puppet est appelé le puppetmaster. Nous définissons sur celui-ci une configuration de référence : l'état dans lequel on souhaite retrouver le système. Les clients, via le démon Puppetd vont entreprendre les actions nécessaires pour correspondre à cet état. Puppetd doit donc faire en sorte que la machine ait à tout moment le même état que la configuration de référence. Il est intéressant de noter que si la machine se trouve déjà dans cet état, le démon ne fera rien : il y a idempotence.

Installation et configuration de Puppet


Puppet étant écrit en Ruby, il est possible de l'installer via les paquets Gems. Vu que Debian propose les paquets .deb directement depuis les dépôts, nous pouvons les installer par aptitude. Pour le serveur, on installe le paquet puppetmaster ainsi que ses dépendances :

server:~# aptitude install puppetmaster

Pour le client, on installe le démon puppetd :

client:~# aptitude install puppet

La première chose à faire est de renseigner le FQDN du serveur dans la section main du fichier /etc/puppet/puppet.conf du client.

client:~# vim /etc/puppet/puppet.conf
[main]
server=FQDN-du-serveur

Génération des certificats


Puppet utilise une couche SSL pour ses communications. Il va donc falloir générer des certificats. Il suffit de tenter une connexion depuis le client :

client:~# puppetd --test --waitforcert 60

Sur le serveur, la commande

# puppetca --list

permet de lister les certificats en attente de validation. Vous devriez retrouver votre client.

Pour le valider :

server:~# puppetca --sign le-FQDN-du-client

ou bien, pour valider tous les clients d'un coup :

server:~# puppetca --sign --all

Si la connexion ne passe pas, pensez aux firewall : puppet utilise le port 8139.

Lancement du démon puppetd au démarrage

Lorsque l'on tente de lancer l'agent puppet, nous obtenons :

client:~# /etc/init.d/puppet start
Starting puppet agent
puppet not configured to start, please edit /etc/default/puppet to enable.

Ainsi soit-il.

client:~# vim /etc/default/puppet
# Start puppet on boot ?
START=yes

Le démon puppetd se lancera maintenant automatiquement au démarrage.
Dans le cadre de cet article, nous prendrons soin de désactiver le démon, car nous le lancerons à chaque fois en mode "test", c'est à dire non-démon, afin de pouvoir débugger et vérifier que tout se déroule convenablement.

Configuration du puppetmaster

Nous attaquons à présent le vif du sujet. Au lieu de foncer tête baissée dans la configuration, prenons le temps de bien comprendre la logique des fichiers de config. Voici à quoi ressemble l'arborescence du dossier /etc/puppet :

server:/etc/puppet$ tree
.
??? auth.conf
??? fileserver.conf
??? manifests
?   ??? nodes.pp
?   ??? site.pp
??? modules
?   ??? test
?       ??? files
?       ?   ??? test.txt
?       ??? manifests
?           ??? init.pp
??? puppet.conf
??? templates

Lorsqu'il consultera le puppetmaster, l'agent lira les fichiers de configuration dans un certain ordre :

- En premier, le fichier manifests/site.pp. On renseigne dans ce fichier des configurations globales. On spécifiera également d'importer les "nodes", que nous allons voir tout de suite.

- Le fichier manifests/nodes.pp est lu lors de l'import. Dans ce fichier, nous renseignons les FQDN des clients ainsi que les modules qui leur sont associés.

- Ensuite, direction le fichier modules/$nom_du_module/manifests/init.pp. Bien entendu, ne seront parsés que les modules qui ont été renseigné dans les nodes. Dans ce fichier, nous allons retrouver des classes. Puppet a un fonctionnement similaire à la POO : on définit des classes, qui seront en quelque sorte instanciées lors de l'appel d'un agent. Dans ces classes, on retrouve les configurations de référence.

- S'il y a des fichiers à uploader, on les place dans modules/$nom_du_module/manifests/files.

Pas de panique si tout vous semble confus, nous allons voir un exemple concret. Il faut savoir que l'on pourrait se contenter de modifier et de mettre toutes nos configs dans le fichier manifests/site.pp. C'est possible, ça marche, mais ce n'est pas propre. Cela revient à tout coder dans le main, si l'on fait le parallèle avec la programmation. Nous allons donc nous attacher à nous appuyer le plus possible sur les modules et le fractionnement des fichiers de configuration. Si vous voulez plus de détails sur les bonnes pratiques de puppet, je vous propose d'aller lire ce lien.

Exemple

Dans cet exemple, nous voulons que le client ait un fichier /etc/test.txt tel que nous le spécifions sur le serveur, ainsi que qu'un démon ssh installé et lancé.

manifests/site.pp

import "nodes"

# global defaults
# Les deux lignes suivantes servent pour le transfert de fichiers

filebucket { main: server => "FQDN-du-serveur" }
File { backup => main }

Exec { path => "/usr/bin:/usr/sbin:/bin:/sbin" }

manifests/nodes.pp

node basenode {
include test
}
node 'FQDN-du-client' inherits basenode{
include ssh
}

Comme vous le voyez, on peut définir un node de base, puis faire hériter d'autres nodes pour hériter des modules du basenode et ajouter des modules spécifiques.

modules/test/manifests/init.pp

class test {
file { "/etc/test.txt":
owner => root,
group => root,
mode => 644,
source => "puppet:///test/test.txt"
}
}

Cette classe permet de s'assurer que le fichier /etc/test.txt est créé sur le client, avec les droits 644, l'utilisateur et le groupe root. Le contenu du fichier est renseigné dans modules/test/files/test.txt

modules/ssh/manifests/init.pp

class ssh{
package { "openssh-server":
ensure => latest,
}
service { ssh:
ensure          => running,
hasrestart      => true,
}
}

Cette classe permet de s'assurer que la dernière version du paquet openssh-server est installée, et que le service est lancé.

On relance le puppetmaster pour que les configurations soient bien prises en compte.

server:~# /etc/init.d/puppetmaster restart

Enfin, on lance un puppetd en test pour vérifier si tout fonctionne :

server:~# pupeptd --test

Et voilà, à présent, le fichier test.txt se retrouve dans le /etc/ du client, et ssh a été installé et lancé.

 

Aller plus loin...

Il y a encore beaucoup à dire sur Puppet. Il est possible de faire bien plus de choses. Nous n'avons vu que la base. Malgré tout, je vais m’arrêter la pour l'instant. Un prochain article sera consacré à des fonctionnalités un peu plus avancées, comme la personnalisation des configs grâce aux templates, des commandes pour puppetmaster, et autres joyeusetés. À bientôt, donc.

Vus : 1123
Publié par Jeyg : 33