Provisioning Serveur & Scripting Bash

Idempotence, Error Handling, Shellcheck

Utilisez les flèches, cliquez ou glissez pour naviguer

Objectifs de la leçon

1. Idempotence

Le script doit pouvoir tourner N fois sans problème

2. Gestion d'erreurs robuste

set -euo pipefail et trap

3. Scripts modulaires

Fonctions réutilisables

4. shellcheck

Détecter et corriger les erreurs

5. Script de provisioning complet

Node.js, PostgreSQL, Nginx, pare-feu, déploiement application

Plan du cours

1

Recap de la semaine

Bash, processus, réseau, SSH — aujourd'hui on combine tout

2

Patterns de scripting avancés

Idempotence, fonctions réutilisables, gestion d'erreurs

3

set -euo pipefail

Le mode strict Bash et ses subtilités

4

trap

Nettoyer les ressources en cas d'erreur

5

shellcheck

Linter pour scripts Bash, détecte les erreurs courantes

6

Live coding

Construire ensemble le début du script de provisioning

7

Planifier l'après-midi

Les étudiants finissent le script en autonomie

Recap de la semaine

Aujourd'hui on combine tout

Bash & Scripting

Variables, conditions, boucles, fonctions

Processus & Services

systemd, journalctl, cron

Réseau & Diagnostic

TCP/IP, IP, Ports, DNS, Pare-feu

SSH

Connexion distante, clés, sécurité

L'Idempotence : Concept Clé

💡 Le script doit pouvoir tourner N fois sans problème

❌ Sans idempotence

apt install nginx

# Erreur si déjà installé

âś… Avec idempotence

apt install -y nginx

# -y = auto-confirm

⚠️ Pattern : Vérifier avant d'agir

if

! command -v nginx ; then

apt install -y nginx

fi

Fonctions Réutilisables

📦 Encapsuler la logique dans des fonctions

install_package() {

# Vérifier si déjà installé

if ! command -v "$1"; then

apt install -y "$1"

else

echo "$1 already installed"

fi

}

install_package nginx

Réutilisable

install_package postgresql

Testable

install_package nodejs

Maintenable

Gestion d'Erreurs Robuste

❌ Sans gestion d'erreurs

apt install nginx

systemctl start nginx

cp config /etc/nginx/

# Continue même si échec

âś… Avec gestion d'erreurs

set -e

apt install nginx

systemctl start nginx

# Stop à la première erreur

🛡️ Deux outils essentiels :

set -euo pipefail pour arrĂŞter aux erreurs

trap pour nettoyer les ressources

đź’ˇ Qu'est-ce que trap ?

Une commande qui exécute du code quand le script se termine (succès ou erreur)

Comme un finally en JavaScript

Utile pour : supprimer fichiers temporaires, libérer verrous, arrêter services

set -euo pipefail

Le mode strict Bash

-e

Exit immédiatement si une commande échoue

Comme throw en JS

-u

Erreur si variable non définie

Évite les bugs silencieux

-o pipefail

Le pipe échoue si ANY commande échoue

Par défaut, seul le dernier compte

set -e : Exit on Error

set -e

# ArrĂŞte le script si une commande retourne non-zero

❌ Attention aux commandes qui échouent volontairement

grep "pattern" file.txt

# Si pas trouvé = exit code 1 = script s'arrête!

âś… Solution : || true

grep "pattern" file.txt || true

# Continue même si pas trouvé

đź’ˇ Pattern : if command

if grep "pattern" file.txt; then

# trouvé

fi

# if gère le exit code, pas besoin de || true

set -u : Undefined Variables

set -u

# Erreur si une variable non définie est utilisée

❌ Sans set -u

echo $UNDEFINED_VAR

# Affiche une ligne vide

# Bug silencieux!

âś… Avec set -u

echo $UNDEFINED_VAR

# UNDEFINED_VAR: unbound variable

# Script s'arrête immédiatement

💡 Pattern : Valeurs par défaut

echo "${VAR:-default}"

# Utilise "default" si VAR non définie

set -o pipefail : Pipe Failure

set -o pipefail

# Le pipe échoue si ANY commande échoue

❌ Sans pipefail

cat nonexistent.txt | grep "pattern"

# cat échoue mais grep réussit

# Exit code = 0 (succès!)

âś… Avec pipefail

cat nonexistent.txt | grep "pattern"

# cat échoue

# Exit code = 1 (échec)

⚠️ Pourquoi c'est important

Sans pipefail, les erreurs dans les pipes sont ignorées silencieusement

Avec pipefail, set -e fonctionne correctement avec les pipes

Les Trois Ensemble

đź’ˇ Toujours en haut de vos scripts

#!/bin/bash

# Mode strict

set -euo pipefail

set -e

ArrĂŞte aux erreurs

set -u

Variables définies

set -o pipefail

Pipes robustes

📝 Règle d'or

Commencez TOUJOURS vos scripts avec set -euo pipefail

C'est le "use strict" de Bash

trap

Nettoyer les ressources en cas d'erreur

Comme un finally en JavaScript

Exécute du code quand le script se termine (succès ou erreur)

Cas d'usage typiques

  • • Supprimer fichiers temporaires
  • • LibĂ©rer des verrous
  • • ArrĂŞter des services
  • • Restaurer l'Ă©tat initial

Signaux capturés

  • • EXIT (fin normale ou erreur)
  • • ERR (erreur uniquement)
  • • INT (Ctrl+C)
  • • TERM (kill)

Exemple : Cleanup avec trap

cleanup() {

# Nettoyer les ressources

rm -f /tmp/provisioning.lock

echo "Cleanup completed"

}

trap cleanup EXIT

# ... suite du script

✅ Succès

Script termine normalement → cleanup() appelé

❌ Erreur

Script échoue (set -e) → cleanup() quand même appelé

đź’ˇ Pattern : Verrouillage

touch /tmp/provisioning.lock

trap 'rm -f /tmp/provisioning.lock' EXIT

# Le verrou est toujours supprimé, même en cas d'erreur

shellcheck

Linter pour scripts Bash

Détecte les erreurs courantes avant l'exécution

Comme ESLint pour JavaScript

Erreurs de syntaxe

  • • Guillemets manquants
  • • Variables non dĂ©finies
  • • Commandes invalides

Problèmes de style

  • • Code non portable
  • • Variables non quotĂ©es
  • • Patterns obsolètes

Bugs potentiels

  • • Conditions toujours vraies
  • • Variables non utilisĂ©es
  • • Boucles infinies

Exemples shellcheck

❌ Code avec erreurs

name=$1

echo $name

rm -rf $name

⚠️ SC2086: Double quote to prevent globbing

⚠️ SC2115: Use "${var:?}" to check

✅ Code corrigé

name="$1"

echo "$name"

rm -rf "$name"

✅ Variables correctement quotées

đź’ˇ Installation et usage

# Installation

apt install shellcheck

# Usage

shellcheck script.sh

Live Coding

Construire ensemble le script de provisioning

Objectif : Installer et configurer

Logiciels

  • • Node.js
  • • PostgreSQL
  • • Nginx

Configuration

  • • Pare-feu (UFW)
  • • DĂ©ploiement app
  • • Services systemd

Structure du Script

#!/bin/bash

# Mode strict

set -euo pipefail

# Variables de configuration

APP_DIR="/var/www/myapp"

DB_NAME="myapp_db"

# Fonctions utilitaires

install_package() { ... }

configure_nginx() { ... }

# Cleanup

trap cleanup EXIT

# Installation

main() { ... }

main

Installation Node.js

install_nodejs() {

# Vérifier si déjà installé

if ! command -v node; then

# Ajouter repo NodeSource

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -

# Installer Node.js

apt install -y nodejs

else

echo "Node.js already installed: $(node -v)"

fi

}

âś… Idempotence

Vérifie si Node.js est déjà installé avant de tenter l'installation

Installation PostgreSQL

install_postgresql() {

# Vérifier si déjà installé

if ! command -v psql; then

# Installer PostgreSQL

apt install -y postgresql postgresql-contrib

# Démarrer le service

systemctl start postgresql

systemctl enable postgresql

else

echo "PostgreSQL already installed"

fi

}

âś… Services systemd

Utilise systemctl pour démarrer et activer les services au boot

Installation Nginx

install_nginx() {

# Vérifier si déjà installé

if ! command -v nginx; then

# Installer Nginx

apt install -y nginx

# Démarrer le service

systemctl start nginx

systemctl enable nginx

else

echo "Nginx already installed"

fi

}

💡 Prochaines étapes

Configurer le virtual host, SSL, et reverse proxy vers l'application Node.js

Configuration Nginx : Virtual Host

configure_nginx_vhost() {

# Créer le fichier de configuration

cat > /etc/nginx/sites-available/myapp <

server {

listen 80;

server_name myapp.example.com;

root /var/www/myapp/public;

index index.html;

}

EOF

# Activer le site

ln -sf /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/

# Tester la configuration

nginx -t

# Recharger Nginx

systemctl reload nginx

}

Configuration Nginx : Reverse Proxy

đź’ˇ Nginx comme reverse proxy vers Node.js

configure_nginx_proxy() {

cat > /etc/nginx/sites-available/myapp <

server {

listen 80;

server_name myapp.example.com;

location / {

proxy_pass http://localhost:3000;

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection 'upgrade';

proxy_set_header Host $host;

proxy_cache_bypass $http_upgrade;

}

}

EOF

nginx -t && systemctl reload nginx

}

Tester la Configuration Nginx

âś… Toujours tester avant de recharger

test_nginx_config() {

# Tester la syntaxe

nginx -t

# Si succès, recharger

if nginx -t; then

systemctl reload nginx

echo "Nginx reloaded successfully"

else

echo "Nginx config test failed"

exit 1

fi

}

âś… nginx -t

Teste la syntaxe sans appliquer les changements

âś… systemctl reload

Recharge sans couper les connexions existantes

Configuration Pare-feu (UFW)

configure_firewall() {

# Autoriser SSH

ufw allow ssh

# Autoriser HTTP/HTTPS

ufw allow 80/tcp

ufw allow 443/tcp

# Activer le pare-feu

ufw --force enable

}

⚠️ Attention

Toujours autoriser SSH AVANT d'activer le pare-feu pour ne pas se bloquer!

âś… Idempotence

UFW est idempotent par défaut — les règles existantes ne sont pas dupliquées

Déploiement Application

deploy_app() {

# Créer répertoire

mkdir -p "$APP_DIR"

# Copier les fichiers (git clone ou scp)

git clone "$REPO_URL" "$APP_DIR"

# Installer dépendances

cd "$APP_DIR" && npm install

# Créer service systemd

setup_systemd_service

# Démarrer l'application

systemctl start myapp

systemctl enable myapp

}

Points Clés

1. L'idempotence est le concept le plus important

Le script doit pouvoir tourner N fois sans problème

2. set -e arrête le script à la première erreur

Mais attention aux commandes qui échouent volontairement (grep, test)

3. Montrer shellcheck en live

Coller un script avec des erreurs et les corriger une par une

4. trap EXIT permet de nettoyer mĂŞme en cas d'erreur

Comme un finally en JavaScript

5. Le script final est le résumé pratique de toute la semaine

Combine Bash, processus, réseau, SSH

Pièges Courants

❌ set -e interagit mal avec les pipes

C'est pour ça qu'on ajoute pipefail — sans pipefail, seule la dernière commande compte

❌ Oublier de tester l'idempotence

Le script marche une fois mais crash la deuxième — toujours tester plusieurs fois!

❌ Ne pas gérer les différences entre distributions

apt vs yum vs dnf — détecter la distribution et adapter les commandes

❌ Hardcoder des chemins

Utiliser des variables en haut du script pour faciliter la maintenance

Plan de l'Après-midi

Les étudiants finissent le script en autonomie

📝 Tâches à compléter

  • • Finir les fonctions d'installation (Node.js, PostgreSQL, Nginx)
  • • Configurer Nginx comme reverse proxy
  • • CrĂ©er le service systemd pour l'application
  • • Tester le script complet sur une VM vierge

🎯 Objectif

Un script idempotent qui provisionne un serveur complet de A Ă  Z

đź’ˇ Bon courage!

N'hésitez pas à utiliser shellcheck et à demander de l'aide