Projets
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 (équivalent au module copy/template d'Ansible)
file { '/etc/nginx/nginx.conf':
ensure => file,
content => template('nginx/nginx.conf.erb'),
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
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
Templates (équivalent Jinja2)
Template ERB
# modules/apache/templates/ports.conf.erb
Listen <%= @port %>
<% if @ssl_enabled -%>
Listen 443 ssl
<% end -%>
ServerName <%= scope['::fqdn'] %>
Conditionnels et boucles
Conditionnels
# 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)
# 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)
# 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
if $facts['custom_role'] == 'webserver' {
include apache
}
Gestion des erreurs et dépendances
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
# Test de syntaxe (équivalent ansible-playbook --syntax-check)
puppet parser validate manifest.pp
# Simulation (équivalent --check mode)
puppet agent --test --noop
# Application manuelle
puppet agent --test
# Voir les facts
puppet facts
# Compilation d'un catalogue
puppet catalog compile nodename
# Validation d'un module
puppet module validate /path/to/module
Exemple complet : Stack LAMP
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
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é) vs Ansible procédural
- Exécution : Puppet pull vs Ansible push
- Agent : Puppet nécessite un agent vs Ansible agentless
- Langage : DSL Puppet vs YAML Ansible
- Gestion d'état : Puppet maintient l'état en continu vs Ansible à la demande
Cette documentation devrait vous donner une base solide pour commencer avec Puppet en vous appuyant sur votre expérience Ansible. Avez-vous des questions spécifiques sur certains aspects ?