Risoluzione dei problemi dei servizi Linux con systemctl e journalctl

Un flusso di lavoro pratico per il debug di servizi Linux falliti o non funzionanti con systemctl e journalctl.

Risoluzione dei problemi dei servizi Linux con systemctl e journalctl

Quando un servizio Linux fallisce, il percorso più veloce di solito non è una ricerca sul web. Sono tre controlli locali: cosa pensa systemd che sia successo, cosa ha registrato il servizio e cosa è cambiato prima del fallimento. systemctl e journalctl ti danno queste risposte senza dover indovinare.

Questa guida utilizza come esempi fallimenti comuni dei servizi: un servizio che non si avvia, un processo che è in esecuzione ma non svolge lavoro utile e un servizio che termina dopo essere sembrato sano. I comandi si applicano alla maggior parte dei servizi gestiti da systemd, ma i nomi esatti delle unità e le posizioni dei log variano in base alla distribuzione e al pacchetto.

Comprendere systemctl e journalctl

Prima di addentrarci nella risoluzione dei problemi, è fondamentale comprendere i ruoli di questi due strumenti principali:

  • systemctl: Questo comando è l'utilità centrale per controllare e interrogare il gestore di sistema e servizi systemd. Ti permette di avviare, fermare, riavviare, controllare lo stato e abilitare/disabilitare i servizi.
  • journalctl: Questo comando viene utilizzato per interrogare il journal di systemd, che è un sistema di logging centralizzato. Raccoglie log dal kernel, dai servizi di sistema e dalle applicazioni, fornendo una visione unificata degli eventi di sistema. journalctl è prezioso per capire perché un servizio è fallito o si è comportato in modo inaspettato.

Scenari comuni di risoluzione dei problemi e soluzioni

Esploriamo i problemi tipici e come affrontarli:

1. Servizio non riuscito ad avviarsi

Questo è forse il problema più comune. Provi ad avviare un servizio e fallisce immediatamente.

Passo 1: Controlla lo stato del servizio

Usa systemctl status per ottenere una panoramica immediata dello stato del servizio e delle voci di log recenti.

sudo systemctl status apache2.service

Output previsto (illustrativo - il tuo potrebbe variare):

● apache2.service - The Apache HTTP Server
     Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
     Active: **failed** (result: exit-code) since Tue 2023-10-27 10:00:00 UTC; 1min ago
       Docs: https://httpd.apache.org/docs/2.4/
    Process: 12345 ExecStart=/usr/sbin/apachectl start (code=exited, status=1/FAILURE)
   Main PID: 12345 (code=exited, status=1/FAILURE)

Oct 27 10:00:00 your-server systemd[1]: Starting The Apache HTTP Server...
Oct 27 10:00:00 your-server apachectl[12345]: AH00526: Syntax error on line 123 of /etc/apache2/apache2.conf:
Oct 27 10:00:00 your-server apachectl[12345]: Invalid Mutex directory in argument file: '/var/run/apache2/'
Oct 27 10:00:00 your-server systemd[1]: apache2.service: Main process exited, code=exited, status=1/FAILURE
Oct 27 10:00:00 your-server systemd[1]: **Failed** to start The Apache HTTP Server.
Oct 27 10:00:00 your-server systemd[1]: apache2.service: Unit entered failed state.

Analisi: L'output di systemctl status mostra chiaramente Active: failed e fornisce un frammento del messaggio di errore: Invalid Mutex directory in argument file: '/var/run/apache2/'. Questo suggerisce un problema di configurazione.

Passo 2: Indaga sui log con journalctl

Per informazioni più dettagliate, usa journalctl per visualizzare i log specifici per il servizio fallito. Il flag -u specifica l'unità (servizio).

sudo journalctl -u apache2.service -xe
  • -u apache2.service: Filtra i log per l'unità apache2.service.
  • -x: Aggiunge spiegazioni per alcuni messaggi di log.
  • -e: Salta alla fine del journal, mostrando le voci più recenti.

Risultati potenziali: L'output di journalctl potrebbe rivelare più contesto sull'errore di configurazione, problemi di permessi o problemi di dipendenza.

Passo 3: Controlla i file di configurazione

In base al messaggio di errore, esamina i file di configurazione pertinenti. Nell'esempio sopra, punta a /etc/apache2/apache2.conf e alla directory /var/run/apache2/.

sudo nano /etc/apache2/apache2.conf

Soluzione: Problemi come questo spesso derivano da una directory di runtime mancante, una modifica del pacchetto o un file di configurazione che fa riferimento a un percorso che non esiste più. Non creare ciecamente directory da un esempio su Internet. Prima conferma cosa si aspetta l'applicazione sulla tua distribuzione, poi correggi il percorso mancante o la configurazione. Una possibile riparazione potrebbe assomigliare a questa:

sudo mkdir -p /var/run/apache2/
sudo chown www-data:www-data /var/run/apache2/
sudo systemctl start apache2.service

Se l'errore menziona un problema di sintassi, esegui il test di configurazione dell'applicazione stessa prima di riavviare di nuovo:

sudo apachectl configtest
sudo nginx -t
sudo sshd -t

I validatori specifici dell'applicazione rilevano errori che systemd non può comprendere. Systemd sa se il processo è terminato. Non sa se il tuo blocco server di Nginx punta al file di certificato sbagliato o se una direttiva Apache appartiene a un contesto diverso.

2. Il servizio è in esecuzione ma non risponde

A volte, systemctl status mostra un servizio come active (running), ma non sta svolgendo la funzione prevista (ad esempio, un server web non serve pagine).

Passo 1: Verifica lo stato del servizio e il PID

Conferma che sia effettivamente in esecuzione e abbia un ID di processo (PID).

sudo systemctl status nginx.service

Se mostra active (running), annota il PID.

Passo 2: Esamina i log del servizio per errori

Anche se in esecuzione, il servizio potrebbe incontrare errori interni che gli impediscono di funzionare correttamente.

sudo journalctl -u nginx.service -f
  • -f: Segue l'output del log in tempo reale. Questo è utile se puoi attivare il problema (ad esempio, prova ad accedere alla pagina web) mentre journalctl è in esecuzione.

Passo 3: Controlla i log specifici dell'applicazione

Molti servizi scrivono i propri log oltre al journal di systemd. Per server web come Nginx o Apache, controlla le loro tipiche posizioni dei log (ad esempio, /var/log/nginx/error.log, /var/log/apache2/error.log).

sudo tail -n 50 /var/log/nginx/error.log

Passo 4: Controlla l'utilizzo delle risorse

Un sistema sovraccarico può causare la mancata risposta dei servizi.

 top
 htop
 free -h

Cerca un elevato utilizzo di CPU, memoria o I/O del disco da parte dei processi del servizio.

Controlla anche se il servizio è in ascolto dove ti aspetti:

sudo ss -ltnp
sudo ss -lunp

Per un servizio web, vedere nginx attivo in systemctl è solo metà della storia. Devi ancora sapere se è vincolato a 0.0.0.0:80, 127.0.0.1:8080, un socket IPv6 o nessun socket. Una regola del firewall, una mancata corrispondenza del proxy inverso o un indirizzo di bind errato possono far sembrare un processo sano rotto dall'esterno.

Soluzione: Se i log indicano problemi o le risorse sono sotto sforzo, potresti aver bisogno di:

  • Ottimizzare le configurazioni.
  • Riavviare il servizio (sudo systemctl restart <nome_servizio>.service).
  • Investigare i problemi di risorse di sistema sottostanti.
  • Aumentare le risorse di sistema se necessario.

3. Il servizio si ferma inaspettatamente

Se un servizio che era in esecuzione si ferma improvvisamente, spesso è dovuto a un'eccezione non gestita o a un timeout del watchdog.

Passo 1: Controlla la cronologia recente con journalctl

Usa journalctl per vedere cosa è successo appena prima che il servizio si fermasse. I flag --since e --until possono essere utili se conosci l'ora approssimativa.

sudo journalctl -u <nome_servizio>.service --since "1 hour ago"

Oppure, per vedere tutti i log relativi al servizio dall'ultimo avvio:

sudo journalctl -u <nome_servizio>.service -b

Passo 2: Cerca core dump o rapporti di crash

Se il servizio è andato in crash, il sistema potrebbe aver generato un core dump o un rapporto di crash.

ls -l /var/crash/

Passo 3: Rivedi il file dell'unità di servizio di systemd

Esamina il file dell'unità del servizio (di solito in /etc/systemd/system/ o /lib/systemd/system/) per le direttive Restart= e le impostazioni WatchdogSec=. Una configurazione Restart= errata o un WatchdogSec= troppo breve potrebbero causare riavvii o fallimenti imprevisti.

systemctl cat <nome_servizio>.service

Soluzione: Affronta la causa principale identificata nei log. Ciò potrebbe comportare la correzione di bug del codice, la regolazione dei parametri del file dell'unità systemd o l'aumento dei limiti delle risorse.

Se vedi riavvii ripetuti, controlla se systemd ha limitato la frequenza dell'unità:

systemctl status <nome_servizio>.service
journalctl -u <nome_servizio>.service --since "30 minutes ago"

I messaggi su Start request repeated too quickly di solito significano che il servizio è andato in crash più volte in una breve finestra. Dopo aver risolto il problema sottostante, cancella lo stato di fallimento:

sudo systemctl reset-failed <nome_servizio>.service
sudo systemctl start <nome_servizio>.service

4. Problemi con systemctl enable o systemctl disable

Sebbene non sia un fallimento in fase di esecuzione, possono verificarsi problemi nell'abilitazione o disabilitazione dei servizi.

Problema: Un servizio è abilitato ma non si avvia all'avvio, o viceversa.

Controlla lo stato:

sudo systemctl is-enabled <nome_servizio>.service

Questo comando restituirà enabled o disabled.

Risoluzione dei problemi:

  • Assicurati che il file dell'unità di servizio stesso sia valido e posizionato correttamente (ad esempio, /etc/systemd/system/).
  • Dopo aver apportato modifiche a un file di unità, esegui sempre sudo systemctl daemon-reload.
  • Controlla i log per il servizio (journalctl -u <nome_servizio>.service) per eventuali errori di avvio che potrebbero impedirgli di diventare attivo anche se abilitato.

Suggerimenti per una risoluzione dei problemi efficace

  • Inizia con systemctl status: Inizia sempre da qui. Fornisce un'istantanea rapida e spesso ti indica la giusta direzione.
  • Usa journalctl -u <servizio>: Questo è il tuo strumento principale per capire perché sta succedendo qualcosa.
  • Flag -f con journalctl: Estremamente utile per il monitoraggio in tempo reale quando si cerca di riprodurre un problema.
  • systemctl restart <servizio>: Dopo aver apportato modifiche alla configurazione, riavvia sempre il servizio per applicarle.
  • systemctl daemon-reload: Fondamentale dopo aver modificato qualsiasi file di unità .service.
  • Controlla le dipendenze: A volte un servizio fallisce perché un servizio da cui dipende non è stato avviato o sta fallendo a sua volta. systemctl status spesso lo mostrerà.
  • Permessi: Molti fallimenti dei servizi sono dovuti a permessi errati di file o directory. Assicurati che l'utente con cui viene eseguito il servizio abbia l'accesso necessario.
  • Problemi di rete: Se il servizio si basa sulla rete, controlla la connettività di rete, le regole del firewall e la disponibilità delle porte.

Un ordine di risoluzione dei problemi che regge

Quando la pressione è alta, usa sempre lo stesso ordine:

systemctl status <servizio>.service
journalctl -u <servizio>.service -b --no-pager
systemctl cat <servizio>.service
systemctl list-dependencies <servizio>.service

Inizia con lo stato corrente, poi leggi i log dall'avvio corrente, poi ispeziona l'unità esattamente come la vede systemd, poi controlla le dipendenze. Se il servizio è rivolto alla rete, aggiungi ss -ltnp e un test curl o client locale. Se legge un file di configurazione, esegui il validatore di configurazione del servizio stesso.

Il punto è evitare riavvii casuali. Riavviare può essere una correzione valida dopo una modifica della configurazione o un processo bloccato, ma distrugge anche le prove. Leggi abbastanza del journal prima in modo da sapere cosa stai cambiando e perché.

Leggere l'output del journal senza perdersi

journalctl può essere rumoroso, specialmente su server occupati. Inizia in modo ristretto, poi allarga solo quando necessario.

Per un servizio nell'avvio corrente:

journalctl -u <servizio>.service -b --no-pager

Per gli ultimi minuti:

journalctl -u <servizio>.service --since "15 minutes ago" --no-pager

Per l'avvio precedente:

journalctl -u <servizio>.service -b -1 --no-pager

Quella vista dell'avvio precedente è utile quando un servizio è fallito durante l'avvio e poi si è ripreso, o quando l'intera macchina è stata riavviata prima che potessi ispezionarla. Puoi elencare gli avvii con:

journalctl --list-boots

Se il servizio registra campi strutturati o righe lunghe, usa timestamp ISO brevi:

journalctl -u <servizio>.service -o short-iso --no-pager

Quando devi condividere i log, rimuovi segreti, token, hostname interni e dati dei clienti. I log dei servizi spesso includono impostazioni derivate dall'ambiente, URL, intestazioni o stringhe di connessione. Una buona abitudine di risoluzione dei problemi include la redazione prima di incollare l'output da qualsiasi parte.

Quando systemctl dice "Active" ma gli utenti vedono ancora un fallimento

Uno stato active (running) significa solo che systemd ha un processo che corrisponde alle aspettative dell'unità. Non prova che l'applicazione sia sana. Un'applicazione web può essere in esecuzione mentre restituisce HTTP 500. Un worker può essere attivo mentre è bloccato su un messaggio di coda errato. Un proxy di database può essere in esecuzione mentre tutte le connessioni backend falliscono.

Per i servizi di rete, testa dagli stessi livelli da cui dipendono i tuoi utenti:

curl -v http://127.0.0.1:8080/health
curl -v http://localhost/health
curl -v https://service.example.com/health

Questi tre controlli rispondono a domande diverse. Il primo controlla la porta dell'app locale. Il secondo può includere un proxy inverso locale. Il terzo controlla DNS, TLS, routing, regole del firewall e il percorso pubblico.

Per i servizi worker, guarda la cosa che consumano o producono. Un worker di coda potrebbe aver bisogno di un controllo della profondità della coda. Un servizio di backup potrebbe aver bisogno di un file di output recente. Un collettore di metriche potrebbe aver bisogno di una query sul backend delle metriche. systemctl ti dice se la supervisione funziona; i controlli dell'applicazione ti dicono se il servizio è utile.

Correggi una variabile alla volta

Quando un'unità fallisce dopo un deployment, è tentatore cambiare diverse cose e riavviare. Questo può nascondere la vera causa. Preferisci un cambiamento alla volta:

systemctl cat my-app.service
journalctl -u my-app.service --since "30 minutes ago" --no-pager
sudo systemctl edit my-app.service
sudo systemctl daemon-reload
sudo systemctl restart my-app.service

Poi controlla il risultato prima di cambiare la cosa successiva. Se il fallimento è un file mancante, correggi il percorso del file. Se è un errore di permesso, correggi la proprietà o la modalità. Se è una dipendenza, correggi la relazione dell'unità o il comportamento di ripetizione dell'applicazione. Una risoluzione dei problemi lenta e noiosa è spesso più veloce di un ciclo di riavvio con cinque modifiche non tracciate.