DevOps Bootcamp · Lezione

Creare script per controlli e avvisi sullo stato del sistema

Raccolga metriche su carico, memoria e disco e attivi avvisi basati su soglie da script pianificati.

Lezione 4 di 413 passaggi

Creare script per controlli e avvisi sullo stato del sistema è una lezione DevOps Bootcamp gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento DevOps Bootcamp, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso DevOps Bootcamp include 4 lezioni in totale.

Perché i controlli dello stato del sistema sono importanti

I server di produzione possono degradarsi senza segnali evidenti. Picchi della CPU, perdite di memoria e dischi pieni causano interruzioni, ma solo se nessuno se ne accorge in tempo. Gli script di controllo dello stato del sistema automatizzano il ciclo di monitoraggio: raccolgono le metriche, le confrontano con le soglie e inviano avvisi prima che gli utenti riscontrino problemi.

  • Programmati tramite cron, vengono eseguiti ogni pochi minuti senza intervento umano
  • Producono un output coerente con marca temporale, adatto all'aggregazione dei log
  • La logica basata su soglie mantiene significativi gli avvisi: non ogni breve anomalia attiva una chiamata al team reperibile

In questa lezione costruirà da zero uno script di controllo dello stato adatto alla produzione, aggiungendo un livello alla volta i controlli sul load average, sulla pressione della memoria e sull'utilizzo del disco.

Acquisizione del load average

Linux espone i load average di 1, 5 e 15 minuti tramite /proc/loadavg e il comando uptime. Per gli script, /proc/loadavg è la fonte più pulita: non presenta problemi di localizzazione né variazioni nell'analisi tra le diverse distribuzioni.

Il frammento seguente legge il load average di 1 minuto e lo memorizza in una variabile per il confronto con la soglia. cut estrae il primo campo; awk rimuove la parte decimale per il confronto tra interi usando bc per i calcoli in virgola mobile.

#!/usr/bin/env bash
# Read 1-minute load average from /proc/loadavg
LOAD_RAW=$(cut -d' ' -f1 /proc/loadavg)
echo "Raw load average: $LOAD_RAW"

# Number of CPU cores — used to normalise load
CPU_CORES=$(nproc)
echo "CPU cores: $CPU_CORES"

# Compute load percentage (load / cores * 100) using bc
LOAD_PCT=$(echo "scale=2; $LOAD_RAW / $CPU_CORES * 100" | bc)
echo "Load %: $LOAD_PCT"

Confronto con soglie in virgola mobile

Bash non è in grado di confrontare nativamente numeri in virgola mobile: [ 1.5 -gt 1.2 ] genera un errore. Le due soluzioni idiomatiche sono:

  • bc — restituisce 1 (vero) o 0 (falso) a partire da un'espressione di confronto
  • awk — può valutare condizioni in virgola mobile all'interno di una pipeline

L'uso di bc mantiene la logica leggibile e facile da testare. Lo schema $(echo "$A > $B" | bc) restituisce 1 quando la condizione è verificata; può testarlo con [ ... -eq 1 ].

#!/usr/bin/env bash
LOAD_RAW=$(cut -d' ' -f1 /proc/loadavg)
CPU_CORES=$(nproc)
THRESHOLD=80  # alert when load % exceeds 80%

LOAD_PCT=$(echo "scale=2; $LOAD_RAW / $CPU_CORES * 100" | bc)

# bc returns 1 if the expression is true
if [ "$(echo "$LOAD_PCT > $THRESHOLD" | bc)" -eq 1 ]; then
    echo "ALERT: Load is ${LOAD_PCT}% (threshold ${THRESHOLD}%)"
else
    echo "OK: Load is ${LOAD_PCT}%"
fi

Raccolta delle metriche della memoria

/proc/meminfo è la fonte autorevole per le statistiche della memoria in Linux. Campi principali:

  • MemTotal — RAM fisica totale in kB
  • MemAvailable — quantità stimata in kB disponibile per nuove allocazioni senza ricorrere allo swap (più indicativa di MemFree)

Usare awk con una ricerca per modello è il modo più pulito per estrarre questi valori. Dividendo MemAvailable per MemTotal e sottraendo il risultato da 100 si ottiene la percentuale di memoria utilizzata, sulla quale si basa la soglia dell'avviso.

#!/usr/bin/env bash
# Extract memory figures from /proc/meminfo (values in kB)
MEM_TOTAL=$(awk '/^MemTotal:/ {print $2}' /proc/meminfo)
MEM_AVAIL=$(awk '/^MemAvailable:/ {print $2}' /proc/meminfo)

# Used memory percentage
MEM_USED_PCT=$(echo "scale=2; (1 - $MEM_AVAIL / $MEM_TOTAL) * 100" | bc)

echo "Total RAM : ${MEM_TOTAL} kB"
echo "Available : ${MEM_AVAIL} kB"
echo "Used      : ${MEM_USED_PCT}%"

Raccolta delle metriche di utilizzo del disco

Il comando df restituisce le informazioni sull'utilizzo dei filesystem. Per gli script, due opzioni sono essenziali:

  • -h — dimensioni leggibili dall'utente (solo per la visualizzazione; da evitare nei calcoli aritmetici)
  • --output=pcent,target — colonne analizzabili automaticamente (GNU coreutils)

Iterare su tutti i filesystem montati consente allo script di segnalare qualsiasi partizione quasi piena, non solo /. Il simbolo % viene rimosso con tr -d '%' prima del confronto tra interi.

#!/usr/bin/env bash
DISK_THRESHOLD=85

# Skip header line with tail -n +2
# --output=pcent,target gives "85% /var" style lines
df --output=pcent,target | tail -n +2 | while read -r USED_PCT MOUNT; do
    # Remove the % sign for arithmetic
    USED_INT=${USED_PCT//%/}

    if [ "$USED_INT" -ge "$DISK_THRESHOLD" ]; then
        echo "ALERT: Disk $MOUNT is ${USED_PCT} full"
    else
        echo "OK   : Disk $MOUNT is ${USED_PCT} full"
    fi
done

Output strutturato degli avvisi con marche temporali

I messaggi di avviso senza marche temporali sono quasi inutili nei file di log o nei report via email. Un prefisso coerente semplifica notevolmente l'analisi dei log con grep o con gli agenti di invio dei log.

Definisca una piccola funzione di avviso all'inizio dello script. La funzione antepone una marca temporale ISO-8601, un livello di gravità e il nome del controllo. Tutti gli avvisi vengono scritti sia su stdout sia in un file di log tramite tee.

  • date -u +"%Y-%m-%dT%H:%M:%SZ" — marca temporale UTC, indipendente dalla lingua
  • Scrivere su stderr per ALERT e su stdout per OK separa i segnali dal rumore nelle pipeline
#!/usr/bin/env bash
LOG_FILE="/var/log/healthcheck.log"

alert() {
    local LEVEL="$1"   # OK | WARN | ALERT
    local CHECK="$2"
    local MSG="$3"
    local TS
    TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
    local LINE="[$TS] [$LEVEL] [$CHECK] $MSG"

    if [ "$LEVEL" = "ALERT" ]; then
        echo "$LINE" | tee -a "$LOG_FILE" >&2
    else
        echo "$LINE" | tee -a "$LOG_FILE"
    fi
}

# Usage examples
alert "OK"    "DISK"  "/ is 42% full"
alert "ALERT" "DISK"  "/var is 91% full"

Invio di avvisi email con mail e sendmail

Il meccanismo più semplice per gli avvisi sul server è l'invio di email tramite l'MTA locale (postfix, sendmail o msmtp). Il comando mail (fornito da mailutils o bsd-mailx) compone e invia un messaggio con una sola riga.

  • -s — oggetto del messaggio
  • Invii il corpo tramite stdin
  • Sui server senza un MTA locale, sostituisca mail con una chiamata curl a un'API per l'invio transazionale di email

Protegga l'invio con un blocco di deduplicazione, in modo che una singola condizione rumorosa non inondi la casella di posta.

#!/usr/bin/env bash
ALERT_EMAIL="ops@example.com"
LOCK_DIR="/tmp/healthcheck_locks"
mkdir -p "$LOCK_DIR"

send_alert() {
    local CHECK="$1"
    local MSG="$2"
    local LOCK="$LOCK_DIR/${CHECK}.lock"

    # Only send if no lock exists (prevents repeated emails within the hour)
    if [ ! -f "$LOCK" ]; then
        echo "$MSG" | mail -s "[ALERT] $CHECK on $(hostname)" "$ALERT_EMAIL"
        touch "$LOCK"
        # Lock expires after 1 hour via cron or find+delete
        echo "Alert sent for $CHECK"
    else
        echo "Alert suppressed for $CHECK (lock active)"
    fi
}

send_alert "HIGH_LOAD" "Load average exceeded 80% on $(hostname) at $(date)"

Composizione dello script completo per il controllo dello stato

Ora combini tutti e tre i controlli — carico, memoria e disco — in un unico script coerente, con soglie configurabili all'inizio. Questo è il modello usato nell'automazione sysadmin in produzione:

  • Costanti dichiarate all'inizio, per poterle modificare facilmente senza intervenire sulla logica
  • Ogni controllo isolato in una funzione, per migliorare leggibilità e possibilità di eseguire unit test
  • Una funzione main coordina le chiamate
  • Codice di uscita 1 se viene generato almeno un avviso, 0 altrimenti — in questo modo lo script può essere integrato con framework di monitoraggio come Nagios/Icinga
#!/usr/bin/env bash
set -euo pipefail

# ── Thresholds ───────────────────────────────────────────
LOAD_THRESHOLD=80   # percent of CPU capacity
MEM_THRESHOLD=90    # percent used
DISK_THRESHOLD=85   # percent used
ALERT_EMAIL="ops@example.com"
LOG_FILE="/var/log/healthcheck.log"
ALERT_FIRED=0

# ── Helpers ──────────────────────────────────────────────
ts()    { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
log()   { echo "[$(ts)] $*" | tee -a "$LOG_FILE"; }
alert() { log "ALERT: $*"; echo "$*" | mail -s "[ALERT] $(hostname)" "$ALERT_EMAIL" 2>/dev/null; ALERT_FIRED=1; }

# ── Checks ───────────────────────────────────────────────
check_load() {
    local raw cores pct
    raw=$(cut -d' ' -f1 /proc/loadavg)
    cores=$(nproc)
    pct=$(echo "scale=2; $raw / $cores * 100" | bc)
    if [ "$(echo "$pct > $LOAD_THRESHOLD" | bc)" -eq 1 ]; then
        alert "Load ${pct}% exceeds ${LOAD_THRESHOLD}%"
    else
        log "OK load=${pct}%"
    fi
}

check_memory() {
    local total avail pct
    total=$(awk '/^MemTotal:/    {print $2}' /proc/meminfo)
    avail=$(awk '/^MemAvailable:/{print $2}' /proc/meminfo)
    pct=$(echo "scale=2; (1 - $avail / $total) * 100" | bc)
    if [ "$(echo "$pct > $MEM_THRESHOLD" | bc)" -eq 1 ]; then
        alert "Memory ${pct}% used (threshold ${MEM_THRESHOLD}%)"
    else
        log "OK memory=${pct}%"
    fi
}

check_disk() {
    df --output=pcent,target | tail -n +2 | while read -r used mnt; do
        local pct_int=${used//%/}
        if [ "$pct_int" -ge "$DISK_THRESHOLD" ]; then
            alert "Disk $mnt at ${used}"
        else
            log "OK disk $mnt=${used}"
        fi
    done
}

main() {
    log "=== Health check START ==="
    check_load
    check_memory
    check_disk
    log "=== Health check END (alerts=$ALERT_FIRED) ==="
    exit "$ALERT_FIRED"
}

main

Pianificazione con Cron

Uno script per il controllo dello stato è utile solo se viene eseguito automaticamente. cron è lo scheduler standard di Unix. Modifichi il crontab a livello di sistema oppure un file dedicato in /etc/cron.d/ per pianificare l'esecuzione dello script.

  • Esecuzione ogni 5 minuti: */5 * * * *
  • Utilizzi sempre percorsi assoluti in cron — $PATH è minimale nell'ambiente di cron
  • Reindirizzi l'output per impedire a cron di inviare un'e-mail a ogni esecuzione: >> /var/log/healthcheck.log 2>&1
  • Inserisca MAILTO="" all'inizio del crontab per disattivare le e-mail generate direttamente da cron
# /etc/cron.d/healthcheck
# Run the health check every 5 minutes as root
MAILTO=""
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

*/5 * * * * root /usr/local/sbin/healthcheck.sh >> /var/log/healthcheck.log 2>&1

Prevenzione delle raffiche di avvisi con i lock di cooldown

Quando una soglia viene superata continuamente, uno script ingenuo genera un avviso ogni 5 minuti — decine di e-mail prima che un tecnico possa intervenire. Un lock di cooldown sopprime gli avvisi ripetuti per un intervallo configurabile.

Il modello è il seguente: scrivere un file di lock al primo avviso; ignorare gli avvisi successivi finché il file è più recente del periodo di cooldown; find con -mmin controlla in modo atomico l'età del file senza dover eseguire calcoli sulle date.

#!/usr/bin/env bash
LOCK_DIR="/tmp/hc_locks"
COOLDOWN_MIN=60  # suppress repeat alerts for 60 minutes
mkdir -p "$LOCK_DIR"

should_alert() {
    local check="$1"
    local lock="$LOCK_DIR/${check}.lock"

    if [ ! -f "$lock" ]; then
        # No lock — allow alert and create lock
        touch "$lock"
        return 0  # true: send alert
    fi

    # Lock exists — check if it is older than the cooldown
    # find returns the filename only if it's OLDER than COOLDOWN_MIN
    local expired
    expired=$(find "$lock" -mmin +"$COOLDOWN_MIN" 2>/dev/null)

    if [ -n "$expired" ]; then
        touch "$lock"  # refresh lock timestamp
        return 0       # cooldown expired — allow alert
    fi

    return 1  # still within cooldown — suppress
}

# Usage
if should_alert "HIGH_LOAD"; then
    echo "Sending load alert..."
    # mail -s "..." ops@example.com <<< "Load too high"
else
    echo "Load alert suppressed (cooldown active)"
fi

Test e convalida dello script per il controllo dello stato

Prima della distribuzione, convalidi lo script in tre modi:

  • Controllo della sintassi: bash -n healthcheck.sh rileva gli errori di analisi senza eseguire lo script
  • Modalità trace: bash -x healthcheck.sh stampa ogni comando mentre viene eseguito — uno strumento prezioso per il debug
  • Sovrascrittura delle soglie: riduca temporaneamente le soglie quasi a zero, in modo che lo script generi avvisi su un host integro, verificando che il percorso degli avvisi funzioni dall'inizio alla fine

Per il percorso delle e-mail, durante i test reindirizzi mail verso un file di log utilizzando un flag MOCK_MAIL:

#!/usr/bin/env bash
# Smoke-test the alert path without sending real email
MOCK_MAIL=true
ALERT_EMAIL="ops@example.com"

send_mail() {
    local subject="$1"
    local body="$2"
    if [ "$MOCK_MAIL" = true ]; then
        echo "[MOCK MAIL] To: $ALERT_EMAIL | Subject: $subject"
        echo "[MOCK MAIL] Body: $body"
    else
        echo "$body" | mail -s "$subject" "$ALERT_EMAIL"
    fi
}

# Override threshold to guarantee an alert fires
LOAD_THRESHOLD=0   # Any load will exceed 0%
LOAD_RAW=$(cut -d' ' -f1 /proc/loadavg)
CPU_CORES=$(nproc)
PCT=$(echo "scale=2; $LOAD_RAW / $CPU_CORES * 100" | bc)

if [ "$(echo "$PCT > $LOAD_THRESHOLD" | bc)" -eq 1 ]; then
    send_mail "[ALERT] Load on $(hostname)" "Load is ${PCT}%"
fi

Verifica delle conoscenze: strategia di cooldown

Consideri il seguente scenario: il cron job per il controllo dello stato viene eseguito ogni 5 minuti. L'utilizzo del disco in /var supera l'85% e rimane oltre questa soglia per 3 ore. Vuole che il tecnico di reperibilità riceva un avviso una volta all'ora, non ogni 5 minuti. Quale strategia di implementazione è più appropriata?

Riepilogo della lezione: script per il controllo dello stato del sistema

In questa lezione ha creato una pipeline completa e pronta per la produzione per il controllo dello stato del sistema e la generazione di avvisi. Ecco i principi fondamentali da tenere a mente:

  • Fonte autorevole: legga le metriche da /proc/loadavg e /proc/meminfo — sono stabili, indipendenti dalla lingua e disponibili su ogni host Linux
  • Aritmetica in virgola mobile: utilizzi bc per confrontare le soglie in virgola mobile; il confronto tra interi di Bash (-gt) funziona solo con numeri interi
  • Iterazione sui dischi: utilizzi df --output=pcent,target per controllare ogni filesystem montato, non solo /
  • Logging strutturato: anteponga a ogni riga un timestamp UTC e un livello di gravità, così i log saranno facili da elaborare con grep e potranno essere inviati in modo affidabile ai sistemi di logging centralizzati
  • Lock di cooldown: i file di lock controllati con find -mmin impediscono le raffiche di avvisi senza modificare la pianificazione di cron
  • Componibilità: termini con il codice 1 quando viene generato un avviso, così lo script si integra con Nagios, Icinga o altri framework di monitoraggio
  • Test: utilizzi bash -n per i controlli della sintassi, bash -x per il debug tramite trace e un flag MOCK_MAIL per convalidare il percorso degli avvisi su host integri

Pianifichi lo script completato tramite /etc/cron.d/ e la sua infrastruttura controllerà continuamente se stessa, generando avvisi solo quando le soglie vengono superate in modo significativo.

Gratis per iniziare

Impara DevOps Bootcamp con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
142
Lezioni
568

Domande Frequenti

La lezione «Creare script per controlli e avvisi sullo stato del sistema» è gratuita?

Sì — il testo completo di «Creare script per controlli e avvisi sullo stato del sistema» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso DevOps Bootcamp, passa a CoddyKit PRO. Il corso DevOps Bootcamp include 4 lezioni in totale.

Cosa imparerò in «Creare script per controlli e avvisi sullo stato del sistema»?

Raccolga metriche su carico, memoria e disco e attivi avvisi basati su soglie da script pianificati. Eserciti DevOps Bootcamp con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare DevOps Bootcamp?

Non è richiesta alcuna esperienza precedente. DevOps Bootcamp su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Creare script per controlli e avvisi sullo stato del sistema»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione DevOps Bootcamp?

Sì. Ogni lezione DevOps Bootcamp include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Automatizzare la gestione di utenti e gruppi
  2. Controllare i servizi systemd e scrivere file unit
  3. Automatizzare dischi, filesystem e mount
  4. Creare script per controlli e avvisi sullo stato del sistema
← Torna a DevOps Bootcamp