Docker Healthcheck: cosa misura davvero e quali limiti ha

Immagine di copertina

I Dockerfile permettono l’inserimento di una istruzione che, di fatto, dovrebbe controllare lo stato di salute del container. L’istruzione HEALTHCHECK definisce infatti un comando che Docker esegue periodicamente per determinare se il container è “sano” o “malato”. Tuttavia, c’è una tendenza diffusa a trattare questo meccanismo come se fosse un sistema di monitoraggio completo, quando in realtà non lo è.

L’idea di questo articolo è semplice: mostrare come un healthcheck che si limita a confermare che il processo risponde possa nascondere interi fallimenti di business, e renda totalmente inutile il suo utilizzo.

Docker healthcheck: cosa dice la documentazione e cosa NON dice

Avevamo già trattato l’argomento parlando di come usare HEALTHCHECK con Docker.: si tratta di un’istruzione che è stata pensata per permettere al container di fornire un codice di stato che indica se il processo principale, ad esempio, è vivo e risponde.

Quello che viene dato per scontato, e che la documentazione ufficiale non chiarisce, è che questo controllo verifichi lo stato reale dell’applicazione o delle sue dipendenze. Come, però?

Il riferimento ufficiale di HEALTHCHECK è chiaro sul suo scopo: l’istruzione HEALTHCHECK definisce un comando che Docker esegue periodicamente all’interno del container per sapere se quel container “funziona”. Se il comando restituisce il codice di uscita 0, il container è sano. Se restituisce 1, ci sono dei problemi. Se restituisce 2, viene ignorato (codice riservato, lo sapevi?).

Un esempio pratico di come viene usato nella documentazione ufficiale è il seguente:

# Esempio minimale dalla documentazione ufficiale
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1

I parametri disponibili sono:

  • --interval: ogni quanto viene eseguito (default: 30s)
  • --timeout: tempo massimo per la risposta del comando (default: 30s)
  • --start-period: periodo di grazia iniziale per l’avvio del container (default: 0s)
  • --retries: quanti fallimenti consecutivi lo marcano come non sano (default: 3)

Quello che la documentazione non dice è che l’endpoint /health verifica lo stato reale dell’applicazione e quella è responsabilità di chi lo implementa. Docker valuta solo il codice di uscita del comando - non legge il corpo della risposta, non analizza JSON, non sa se il database è giù o se una coda sta accumulando messaggi non elaborati. Queste sono tutte verifiche che dipendono dalla progettazione, e che quindi non sono garantite da Docker.

Ed eccoci alla scomoda verità: la maggior parte degli esempi che circolano nei tutorial usa curl -f contro un endpoint che restituisce {"status":"ok"} senza connettersi a nulla di reale. È un healthcheck che conferma soltanto che il processo Node, Go o Java è partito e accetta connessioni TCP. Questo ha valore - ma è un valore molto limitato.

Dove si sbaglia: la ricetta comune e il suo costo nascosto

Il pattern più frequente nei setup Docker pubblici è questo:

# Pattern comune — misura TCP, non logica di business
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1

E lato applicazione, l’endpoint fa qualcosa del genere:

// Handler che conferma solo che il server sta rispondendo
app.get('/health', (req, res) => {
  res.status(200).json({ status: 'ok' });
});

Il container risulta sano, l’orchestratore non lo riavvia e tanti saluti. E nel frattempo, la connessione PostgreSQL potrebbe andare in timeout, il connection pool essere esaurito, o un worker critico essere silenziosamente morto.

Il costo nascosto non è che il healthcheck mente, è che siamo confidenti del corretto funzionamento dell’applicazione più di quanto dovremmo. Quando un team assume che “healthy = app ok”, smette di guardare log, metriche e segnali più ricchi. Per questo, l’istruzione HEALTHCHECK diventa il capro espiatorio invisibile: se la dashboard è verde, il problema deve essere da qualche altra parte.

C’è un controesempio che si applica a qualsiasi sistema tipico: immagina un backend che processa pagamenti. L’endpoint /health restituisce 200, il container è sano, ma il client del gateway di pagamento ha un token scaduto. Ogni transazione fallisce silenziosamente. Docker non ne sa nulla, e intanto si perdono transazioni su transazioni.

Come capire cosa misurare e cosa no

Veniamo quindi a un punto cruciale: cosa misurare con HEALTHCHECK e cosa no. La risposta non è assoluta, ma dipende dal contesto dell’applicazione e dalle sue dipendenze critiche.

Questa matrice che riportiamo non è assoluta, ma è piuttosto un criterio sensato per decidere cosa verificare e da dove:

SegnaleCosa rilevaCosa NON rilevaStrumento migliore
HEALTHCHECK base (curl TCP)Processo avviato, porta apertaFallimenti DB, logica rotta, codeTriage di primo livello
Endpoint /health con ping DBConnettività al databaseDati corrotti, permessi, migrazioniReadiness di base
Endpoint /health approfonditoDipendenze critiche che rispondonoLatenza degradata, errori silenziosiControlli di avvio in prod
Metriche applicazione (Prometheus, log)Errori per route, latenze, codeProblemi fuori dallo scope dell’appOsservabilità reale
Alert esterni (uptime monitor)Disponibilità dall’esterno del containerStato interno del processoSLA e contratti

Per questo motivo, l’healthcheck di base ha senso solo in contesti limitati:

  • Perché Docker riavvii il container se il processo muore o va in stato zombie.
  • Per impedire che un container ancora in avvio riceva traffico (con --start-period).
  • Come strumento di triage di primo livello in sviluppo locale.

Spesso e volentieri è necessario andare ben oltre, e implementare un endpoint /health che verifichi le dipendenze critiche dell’applicazione. Ma questo richiede consapevolezza: non tutti i fallimenti meritano di essere misurati da Docker.

  • Se il servizio ha dipendenze esterne critiche (DB, cache, API di terze parti): queste vanno verificate, ma con attenzione a non introdurre falsi positivi.
  • Se un fallimento silenzioso ha un costo diretto sul business: un esempio è quello relativo ai sistemi di pagamento di prima, dove un errore di token scaduto non viene rilevato da un healthcheck superficiale.
  • Se il container continua a riavviarsi ma il problema persiste perché l’errore non è a livello di processo: questo è probabilmente il caso più insidioso, perché Docker non può sapere se un riavvio risolve davvero il problema, e rischia di creare un loop di riavvii senza fine.

Una domanda utile prima di scrivere l’endpoint: chiediti cosa vuoi che Docker faccia se questo check fallisce. Se la risposta è “riavviare il container”, verifica che riavviarlo risolva davvero quel tipo di fallimento. Se il problema è il tuo database che è giù, riavviare il container non servirà a niente, anzi, potrà innescare un loop di riavvii che peggiorerà solo le cose.

Capire i limiti del meccanismo è il primo passo; il secondo è sapere come usarlo bene. Ma di questo, ne parliamo nel prossimo articolo.

Conosci meglio chi ha scritto questo articolo

Serena Sensini

Ciao! Mi chiamo Serena Sensini e sono la creatrice di @ TheRedCode.it. Ho aperto questo blog nel 2021 per raccontare il mio lavoro e il mondo dell’informatica a parole semplici, in piccole pillole e alla portata di tutte le persone.

Sono un’ingegnera informatica specializzata in ambito AI & NLP. Di giorno lavoro come CTO @ Welyk e come Innovation & Emerging Technologies Leader @ Dedalus, mentre di notte scrivo e sono autrice di 5 libri -per ora-. 🖊️

Foto di Serena Sensini

Partners

Community, aziende e persone che supportano attivamente il blog

Vuoi diventare partner?

Collaboriamo con community, aziende e strumenti del mondo tech che vogliono raggiungere la nostra community di dev ed engineer italiani. Scrivici per proporre una collaborazione.

Vuoi diventare tech content creator? 🖊️

Se ti va di raccontare la tua esperienza nel mondo tech, questo è il posto giusto.

Cerchiamo voci autentiche, esempi pratici e punti di vista utili per chi legge.

Scrivici a collaborazioni[at]theredcode.it con una proposta: idea, taglio del contenuto e una breve presentazione. Non vediamo l'ora di leggere la tua esperienza!

Invia la tua idea