Aller au contenu principal

Automatisation avancée


Table des matières

  1. Patterns d'automatisation
  2. Scripts robustes
  3. Parallélisation
  4. Introduction à Ansible
  5. Orchestration multi-serveurs
  6. Exercices pratiques


1 - Patterns d'automatisation

Niveaux d'automatisation

NiveauOutilsCaractéristiques
ScriptsBash, PythonAd-hoc, rapide
Config ManagementAnsible, PuppetIdempotent, déclaratif
IaCTerraform, PulumiInfrastructure complète
GitOpsArgoCD, FluxGit 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

🔝 Retour à la table des matières


← Chapitre précédent | Chapitre suivant : Troubleshooting →