Puppet
Documentation Puppet pour utilisateur Ansible
Introduction
Puppet est un outil de gestion de configuration qui, comme Ansible, permet d'automatiser la configuration et la gestion des systèmes. Contrairement à Ansible qui est agentless et utilise SSH, Puppet fonctionne avec un modèle agent-serveur.
Concepts fondamentaux - Comparaison Ansible vs Puppet
| Concept | Ansible | Puppet |
|---|---|---|
| Architecture | Agentless (SSH) | Agent-Serveur |
| Langage | YAML (Playbooks) | DSL Puppet (Manifests) |
| Idempotence | Modules | Resources |
| Inventaire | Inventory files | Node definitions |
| Exécution | Push (à la demande) | Pull (agent check régulier) |
Architecture Puppet
┌─────────────────┐ ┌─────────────────┐
│ Puppet Server │◄───┤ Puppet Agent │
│ (Puppet Master)│ │ (Node) │
└─────────────────┘ └─────────────────┘
│ │
│ │
┌─────────┐ ┌─────────┐
│ Forge │ │ Catalog │
│ Modules │ │ Apply │
└─────────┘ └─────────┘
Installation
Puppet Server (Master)
# Ubuntu/Debian
wget https://apt.puppet.com/puppet7-release-focal.deb
sudo dpkg -i puppet7-release-focal.deb
sudo apt update
sudo apt install puppetserver
# Fedora/RHEL
sudo rpm -Uvh https://yum.puppet.com/puppet7-release-el-8.noarch.rpm
sudo dnf install puppetserver
# Démarrage du service
sudo systemctl enable puppetserver
sudo systemctl start puppetserver
Puppet Agent
# Ubuntu/Debian
sudo apt install puppet-agent
# Fedora/RHEL
sudo dnf install puppet-agent
# Configuration de l'agent
sudo systemctl enable puppet
sudo systemctl start puppet
Structure des fichiers
Équivalence avec Ansible
| Ansible | Puppet | Description |
|---|---|---|
playbook.yml |
manifest.pp |
Fichier principal de configuration |
roles/ |
modules/ |
Composants réutilisables |
inventory |
site.pp |
Définition des nodes |
group_vars/ |
hiera/ |
Variables et données |
Arborescence Puppet
/etc/puppetlabs/code/environments/production/
├── manifests/
│ └── site.pp # Point d'entrée (comme site.yml)
├── modules/ # Modules personnalisés
│ └── mymodule/
│ ├── manifests/
│ ├── files/
│ ├── templates/
│ └── metadata.json
├── hieradata/ # Données (comme group_vars)
│ ├── common.yaml
│ └── nodes/
└── Puppetfile # Dépendances modules
Syntaxe de base
Resources (équivalent des modules Ansible)
# Package (équivalent au module package d'Ansible)
package { 'nginx':
ensure => installed,
}
# Service (équivalent au module service d'Ansible)
service { 'nginx':
ensure => running,
enable => true,
require => Package['nginx'],
}
# File avec un template (équivalent au module template d'Ansible)
file { '/etc/nginx/nginx.conf':
ensure => file,
content => template('nginx/nginx.conf.erb'),
notify => Service['nginx'],
}
# File en copie statique (équivalent au module copy d'Ansible)
# Le fichier source doit se trouver dans le dossier 'files/' du module 'nginx'
file { '/etc/nginx/mime.types':
ensure => file,
source => 'puppet:///modules/nginx/mime.types',
notify => Service['nginx'],
}
Comparaison syntaxe
Ansible Playbook:
- name: Install and configure nginx
hosts: webservers
tasks:
- name: Install nginx
package:
name: nginx
state: present
- name: Start nginx service
service:
name: nginx
state: started
enabled: yes
Puppet Manifest:
node 'webserver.example.com' {
package { 'nginx':
ensure => installed,
}
service { 'nginx':
ensure => running,
enable => true,
require => Package['nginx'],
}
}
Variables et Hiera (équivalent group_vars)
Fichier hiera.yaml
---
version: 5
defaults:
datadir: hieradata
data_hash: yaml_data
hierarchy:
- name: "Per-node data"
path: "nodes/%{::trusted.certname}.yaml"
- name: "Per-OS data"
path: "os/%{facts.os.family}.yaml"
- name: "Common data"
path: "common.yaml"
Utilisation dans les manifests
# Récupération de données Hiera
$web_port = lookup('web_port', Integer, 'first', 80)
$db_password = lookup('mysql::root_password')
class { 'apache':
port => $web_port,
}
Modules et Classes
Un module Puppet est une collection structurée et autonome de code et de données, équivalent à un rôle Ansible. Une classe est un bloc de code nommé qui permet de regrouper des ressources pour configurer un aspect du système (ex. installer et démarrer Apache).
init.pp: Le fichier d'entrée obligatoire d'un module. Il contient la classe principale qui doit porter le même nom que le module.- Paramètres de classe : Définis entre parenthèses juste après le nom de la classe, ils permettent d'injecter des configurations personnalisées (semblables aux variables de rôle Ansible).
Structure d'un module
# modules/apache/manifests/init.pp
class apache (
String $package_name = 'apache2',
String $service_name = 'apache2',
Integer $port = 80,
) {
package { $package_name:
ensure => installed,
}
service { $service_name:
ensure => running,
enable => true,
require => Package[$package_name],
}
file { '/etc/apache2/ports.conf':
content => template('apache/ports.conf.erb'),
notify => Service[$service_name],
}
}
Utilisation du module
Les classes s'appellent via la déclaration class { 'nom': } (avec paramètres) ou l'instruction include nom (charge la classe avec ses valeurs par défaut).
Templates (équivalent Jinja2)
Puppet utilise le moteur de template ERB (Embedded Ruby, basé sur la syntaxe Ruby) ou EPP (Embedded Puppet, basé sur Puppet). Les templates permettent de générer dynamiquement le contenu de fichiers à partir de variables.
<%= @variable %>ou<%= scope['::variable'] %>: Évalue et insère la valeur d'une variable.<% if ... -%> ... <% end -%>: Bloc conditionnel (le-supprime le retour à la ligne inutile).
Template ERB
# modules/apache/templates/ports.conf.erb
Listen <%= @port %>
<% if @ssl_enabled -%>
Listen 443 ssl
<% end -%>
ServerName <%= scope['::fqdn'] %>
Conditionnels et boucles
Conditionnels
Puppet dispose d'instructions de contrôle de flux classiques (if, unless - le contraire de if) et de sélecteurs / structures case. Cette dernière est très utilisée pour adapter la configuration selon le système d'exploitation cible.
# Conditionnel basé sur les facts
case $facts['os']['family'] {
'RedHat': {
$package_name = 'httpd'
$service_name = 'httpd'
}
'Debian': {
$package_name = 'apache2'
$service_name = 'apache2'
}
default: {
fail("OS ${facts['os']['family']} not supported")
}
}
Boucles (équivalent with_items / loop)
Contrairement à Ansible qui boucle sur les tâches à l'aide de paramètres de tâche (loop), Puppet intègre des fonctions d'itération directement dans son langage (comme .each ou .map) s'appliquant sur des tableaux ou des hashes.
# Création de plusieurs utilisateurs
$users = ['alice', 'bob', 'charlie']
$users.each |String $username| {
user { $username:
ensure => present,
home => "/home/${username}",
shell => '/bin/bash',
}
}
Facts (équivalent gather_facts)
Les Facts sont des variables système collectées sur l'agent par l'outil Facter avant la compilation du catalogue (ex: OS, adresses IP, interfaces réseau). Ils sont accessibles globalement via le hash $facts.
# Utilisation des facts système
notify { "Operating System: ${facts['os']['name']}" }
notify { "IP Address: ${facts['networking']['ip']}" }
notify { "Memory: ${facts['memory']['system']['total']}" }
# Facts personnalisés (custom facts)
if $facts['custom_role'] == 'webserver' {
include apache
}
Gestion des erreurs et dépendances
Puppet étant purement déclaratif, l'ordre d'écriture des ressources dans le code n'influe pas sur l'ordre de leur application. Puppet crée un graphe orienté de dépendances avant d'appliquer les configurations. Pour ordonner les tâches, on utilise des métaparamètres de relation :
require: La ressource ciblée doit être appliquée avant (ex: installer le paquet mysql-server avant de configurer/démarrer le service).before: Cette ressource doit s'appliquer avant la ressource ciblée.notify: Si cette ressource change, elle envoie un signal de rafraîchissement à la cible (équivalent aux handlers Ansible, ex: redémarrer un service après modification de sa configuration).subscribe: L'inverse de notify : la ressource écoute les changements d'une autre.- Chaînage (
->et~>) : Flèches permettant d'exprimer graphiquement des dépendances séquentielles (->pour l'ordre simple,~>pour notifier).
Relations entre resources
# Ordering avec require/before
package { 'mysql-server':
ensure => installed,
}
service { 'mysql':
ensure => running,
require => Package['mysql-server'], # Après l'installation
}
file { '/etc/mysql/my.cnf':
content => template('mysql/my.cnf.erb'),
notify => Service['mysql'], # Redémarre le service si changement
}
# Chaînage avec ->
Package['mysql-server'] -> File['/etc/mysql/my.cnf'] -> Service['mysql']
Commandes utiles
Voici les principales commandes de l'agent et du serveur à connaître pour diagnostiquer ou appliquer les configurations :
# Test de syntaxe d'un manifeste (équivalent ansible-playbook --syntax-check)
puppet parser validate manifest.pp
# Lancement manuel de l'agent en mode simulation/test sans appliquer les changements (équivalent à --check)
puppet agent --test --noop
# Exécution manuelle immédiate de l'agent (pull les configurations du serveur et les applique)
puppet agent --test
# Afficher l'ensemble des facts collectés sur la machine locale (équivalent à ansible -m setup)
puppet facts
# Compiler et afficher le catalogue final pour un nœud spécifique (côté serveur)
puppet catalog compile nodename
# Valider la structure et les métadonnées d'un module Puppet
puppet module validate /path/to/module
Exemple complet : Stack LAMP
Cet exemple regroupe l'appel d'un nœud, la structuration en sous-classes dépendantes et l'utilisation de Hiera pour configurer un serveur Web Apache, une base de données MySQL et PHP.
site.pp
# manifests/site.pp
node 'lampserver.example.com' {
include lamp_stack
}
node default {
notify { 'No configuration defined for this node': }
}
Module LAMP
# modules/lamp_stack/manifests/init.pp
class lamp_stack {
include lamp_stack::apache
include lamp_stack::mysql
include lamp_stack::php
# On s'assure que MySQL et PHP sont configurés avant de lancer/configurer Apache
Class['lamp_stack::mysql'] -> Class['lamp_stack::php'] -> Class['lamp_stack::apache']
}
# modules/lamp_stack/manifests/apache.pp
class lamp_stack::apache {
$web_port = lookup('lamp_stack::web_port', Integer, 'first', 80)
package { 'apache2':
ensure => installed,
}
service { 'apache2':
ensure => running,
enable => true,
require => Package['apache2'],
}
file { '/etc/apache2/ports.conf':
content => template('lamp_stack/ports.conf.erb'),
notify => Service['apache2'],
}
}
# modules/lamp_stack/manifests/mysql.pp
class lamp_stack::mysql {
$root_password = lookup('lamp_stack::mysql_root_password')
package { 'mysql-server':
ensure => installed,
}
service { 'mysql':
ensure => running,
enable => true,
require => Package['mysql-server'],
}
}
# modules/lamp_stack/manifests/php.pp
class lamp_stack::php {
$php_packages = ['php', 'php-mysql', 'libapache2-mod-php']
package { $php_packages:
ensure => installed,
}
}
Données Hiera
# hieradata/common.yaml
lamp_stack::web_port: 80
lamp_stack::mysql_root_password: 'SecurePassword123!'
Différences clés à retenir
- Philosophie : Puppet est déclaratif (état désiré / idempontence forte) vs Ansible procédural / séquentiel (exécute les tâches dans l'ordre d'écriture).
- Exécution : Puppet pull (l'agent interroge régulièrement le serveur) vs Ansible push (exécuté manuellement ou via orchestrateur en SSH).
- Agent : Puppet nécessite un agent en tâche de fond sur chaque node vs Ansible agentless.
- Langage : DSL Puppet typé et déclaratif vs YAML Ansible simple mais parfois verbeux.
- Gestion d'état : Puppet maintient l'état en continu en corrigeant les dérives ("drift configuration") automatiquement à chaque run de l'agent.
Liens et ressources recommandées pour des exemples
- Puppet Forge : Le dépôt central officiel des modules Puppet (l'équivalent de Ansible Galaxy). C'est le meilleur endroit pour explorer le code de modules officiels et éprouvés (comme
puppetlabs/apache,puppetlabs/mysql, etc.). - Vox Pupuli : Un collectif de la communauté Puppet qui maintient et met à jour des dizaines de modules open source majeurs avec des standards de code modernes. Leurs dépôts GitHub regorgent d'excellents exemples.
- Documentation officielle Puppet Reference : La documentation complète pour comprendre l'architecture, la configuration et Hiera.
- Référence des types de ressources (Resource Types) : La liste exhaustive des paramètres de chaque ressource native (
file,package,service,exec,user, etc.).