Automatisation avancée
Table des matières
- Patterns d'automatisation
- Scripts robustes
- Parallélisation
- Introduction à Ansible
- Orchestration multi-serveurs
- Exercices pratiques
1 - Patterns d'automatisation
Niveaux d'automatisation
| Niveau | Outils | Caractéristiques |
|---|---|---|
| Scripts | Bash, Python | Ad-hoc, rapide |
| Config Management | Ansible, Puppet | Idempotent, déclaratif |
| IaC | Terraform, Pulumi | Infrastructure complète |
| GitOps | ArgoCD, Flux | Git comme source de vérité |
Idempotence
# NON idempotent - problème si relancé
echo "config=value" >> /etc/myapp.conf
# Idempotent - safe à relancer
grep -q "config=value" /etc/myapp.conf || echo "config=value" >> /etc/myapp.conf
# Ou avec sed
sed -i '/^config=/d' /etc/myapp.conf
echo "config=value" >> /etc/myapp.conf
Structure de projet
automation/
├── inventory/
│ ├── production
│ └── staging
├── roles/
│ ├── common/
│ ├── webserver/
│ └── database/
├── playbooks/
│ ├── deploy.yml
│ └── backup.yml
├── scripts/
│ ├── utils.sh
│ └── deploy.sh
└── README.md
🔝 Retour à la table des matières
2 - Scripts robustes
Template de script professionnel
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
#######################
# Configuration
#######################
readonly SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly LOG_FILE="/var/log/${SCRIPT_NAME%.*}.log"
readonly LOCK_FILE="/var/run/${SCRIPT_NAME%.*}.lock"
#######################
# Logging
#######################
log() {
local level="$1"
shift
local message="$*"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
}
log_info() { log "INFO" "$@"; }
log_warn() { log "WARN" "$@"; }
log_error() { log "ERROR" "$@" >&2; }
die() {
log_error "$@"
exit 1
}
#######################
# Locking
#######################
acquire_lock() {
exec 200>"$LOCK_FILE"
if ! flock -n 200; then
die "Une autre instance est en cours d'exécution"
fi
echo $$ > "$LOCK_FILE"
}
#######################
# Cleanup
#######################
cleanup() {
local exit_code=$?
log_info "Nettoyage..."
# Vos actions de nettoyage ici
rm -f "$LOCK_FILE"
exit $exit_code
}
trap cleanup EXIT INT TERM
#######################
# Main
#######################
main() {
acquire_lock
log_info "Démarrage de $SCRIPT_NAME"
# Votre logique ici
log_info "Terminé"
}
main "$@"
Gestion des dépendances
check_dependencies() {
local deps=("jq" "curl" "docker")
local missing=()
for cmd in "${deps[@]}"; do
if ! command -v "$cmd" &> /dev/null; then
missing+=("$cmd")
fi
done
if [ ${#missing[@]} -ne 0 ]; then
die "Dépendances manquantes: ${missing[*]}"
fi
}
Retry pattern
retry() {
local max_attempts="${1:-3}"
local delay="${2:-5}"
shift 2
local cmd=("$@")
local attempt=1
while true; do
if "${cmd[@]}"; then
return 0
fi
if (( attempt >= max_attempts )); then
log_error "Échec après $max_attempts tentatives: ${cmd[*]}"
return 1
fi
log_warn "Tentative $attempt échouée, nouvelle tentative dans ${delay}s..."
sleep "$delay"
(( attempt++ ))
done
}
# Utilisation
retry 5 10 curl -sf http://service/health
🔝 Retour à la table des matières
3 - Parallélisation
Avec background jobs
# Exécuter en parallèle
for host in server{1..10}; do
ssh "$host" "apt update && apt upgrade -y" &
done
wait
echo "Tous les serveurs mis à jour"
Avec xargs
# Parallèle avec limite
cat servers.txt | xargs -P 5 -I {} ssh {} "uptime"
# Avec plusieurs commandes
cat servers.txt | xargs -P 5 -I {} bash -c 'ssh {} "hostname && uptime"'
Avec GNU Parallel
# Installation
apt install parallel
# Exécution parallèle
parallel -j 4 ssh {} uptime ::: server1 server2 server3 server4
# Depuis un fichier
parallel -j 4 -a servers.txt ssh {} uptime
# Avec commande complexe
parallel -j 4 'ssh {} "df -h | grep /dev/sda"' ::: $(cat servers.txt)
Contrôle de concurrence
#!/bin/bash
MAX_JOBS=5
current_jobs=0
run_with_limit() {
while (( current_jobs >= MAX_JOBS )); do
wait -n
(( current_jobs-- ))
done
"$@" &
(( current_jobs++ ))
}
for server in $(cat servers.txt); do
run_with_limit ssh "$server" "some_command"
done
wait
🔝 Retour à la table des matières
4 - Introduction à Ansible
Installation
apt install ansible
# ou
pip install ansible
Inventaire
# /etc/ansible/hosts ou inventory.ini
[webservers]
web1 ansible_host=192.168.1.10
web2 ansible_host=192.168.1.11
[databases]
db1 ansible_host=192.168.1.20
[production:children]
webservers
databases
[all:vars]
ansible_user=admin
ansible_python_interpreter=/usr/bin/python3
Commandes ad-hoc
# Ping tous les serveurs
ansible all -m ping
# Exécuter une commande
ansible webservers -m shell -a "uptime"
# Installer un package
ansible webservers -m apt -a "name=nginx state=present" --become
# Copier un fichier
ansible all -m copy -a "src=/local/file dest=/remote/path"
Playbook basique
# deploy.yml
---
- name: Configurer les serveurs web
hosts: webservers
become: yes
vars:
app_name: myapp
app_port: 8080
tasks:
- name: Mettre à jour apt cache
apt:
update_cache: yes
cache_valid_time: 3600
- name: Installer Nginx
apt:
name: nginx
state: present
- name: Copier la configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/{{ app_name }}
notify: Restart Nginx
- name: Activer le site
file:
src: /etc/nginx/sites-available/{{ app_name }}
dest: /etc/nginx/sites-enabled/{{ app_name }}
state: link
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
Exécuter un playbook
# Exécuter
ansible-playbook deploy.yml
# Avec inventaire spécifique
ansible-playbook -i inventory.ini deploy.yml
# Mode check (dry-run)
ansible-playbook deploy.yml --check
# Limiter aux hosts
ansible-playbook deploy.yml --limit webservers
# Avec variables
ansible-playbook deploy.yml -e "app_port=9090"
🔝 Retour à la table des matières
5 - Orchestration multi-serveurs
Script de déploiement
#!/bin/bash
set -euo pipefail
SERVERS=("web1" "web2" "web3")
DEPLOY_DIR="/var/www/myapp"
ARTIFACT="myapp-$(date +%Y%m%d%H%M%S).tar.gz"
deploy_to_server() {
local server="$1"
echo "Déploiement sur $server..."
# Upload
scp "$ARTIFACT" "$server:/tmp/"
# Deploy
ssh "$server" bash << EOF
set -e
cd $DEPLOY_DIR
tar -xzf /tmp/$ARTIFACT
systemctl restart myapp
rm /tmp/$ARTIFACT
EOF
echo "✓ $server déployé"
}
# Rolling deployment
for server in "${SERVERS[@]}"; do
deploy_to_server "$server"
# Health check
sleep 5
if ! curl -sf "http://$server/health" > /dev/null; then
echo "Échec health check sur $server, rollback..."
exit 1
fi
done
echo "Déploiement terminé sur tous les serveurs"
Orchestration avec Fabric (Python)
# fabfile.py
from fabric import Connection, SerialGroup
hosts = ['web1', 'web2', 'web3']
def deploy():
for host in hosts:
c = Connection(host)
c.run('cd /var/www/myapp && git pull')
c.run('systemctl restart myapp')
print(f"Deployed to {host}")
def parallel_update():
group = SerialGroup(*hosts)
group.run('apt update && apt upgrade -y')
🔝 Retour à la table des matières
6 - Exercices pratiques
Exercice 1 : Script de backup multi-serveurs
Créez un script qui backup plusieurs serveurs en parallèle :
Solution
#!/bin/bash
set -euo pipefail
SERVERS=("server1" "server2" "server3")
BACKUP_DIR="/backup/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
backup_server() {
local server="$1"
echo "Backup de $server..."
ssh "$server" "tar czf - /var/www /etc" > "$BACKUP_DIR/${server}.tar.gz"
echo "✓ $server"
}
for server in "${SERVERS[@]}"; do
backup_server "$server" &
done
wait
echo "Tous les backups terminés dans $BACKUP_DIR"
Exercice 2 : Playbook Ansible
Créez un playbook qui installe et configure un serveur LAMP :
Solution
---
- name: Install LAMP stack
hosts: webservers
become: yes
tasks:
- name: Install packages
apt:
name:
- apache2
- mysql-server
- php
- php-mysql
state: present
update_cache: yes
- name: Start Apache
service:
name: apache2
state: started
enabled: yes
- name: Start MySQL
service:
name: mysql
state: started
enabled: yes
Quiz
Q1. Qu'est-ce que l'idempotence ?
Réponse
Un script/playbook idempotent produit le même résultat qu'il soit exécuté une fois ou plusieurs fois. Le système est toujours dans l'état désiré après exécution.
Q2. Comment exécuter des tâches en parallèle avec xargs ?
Réponse
xargs -P N où N est le nombre de processus parallèles.
🔝 Retour à la table des matières
Points clés à retenir
- Idempotence : scripts qui peuvent être relancés sans effet de bord
- set -euo pipefail : toujours en production
- Locking : éviter les exécutions simultanées
- xargs -P et GNU Parallel pour la parallélisation
- Ansible pour la configuration management
- Toujours inclure des health checks après déploiement