Usare HEALTHCHECK con Docker

  • Di
  • 2021-03-30 - 5 minuti
banner

A volte è necessario -e consigliato- poter verificare se il nostro container sta lavorando correttamente; una delle features introdotte a partire dalla versione 1.12 di Docker è l’istruzione HEALTHCHECK, che ci permette di controllare lo stato di integrità del servizio: vediamo quindi come e quando usare HEALTHCHECK con Docker.

Versione breve

Se hai utilizzato dei _container D_ocker in produzione, potresti aver letto nella documentazione che Docker controlla lo stato di un container utilizzando lo stato del processo (abbreviato in PID) avviato dal comando del Dockerfile.

Se il processo viene eseguito correttamente, il container viene considerato _sano; s_ebbene questo controllo sia efficace, ci sono alcune situazioni in cui abbiamo bisogno di maggiori informazioni sui container.

Ad esempio, a volte la nostra applicazione si arresta in modo anomalo ma il processo stesso è ancora in esecuzione; in questo scenario, potremmo non conoscere lo stato esatto del container.

Usare HEALTHCHECK con Docker è semplice: utilizzando questa istruzione all’interno del Dockerfile, abbiamo la possibilità di specificare un comando da eseguire, piuttosto che uno script che dev’essere eseguito, dove vengano definite dei controlli da effettuare che garantiscano l’effettiva funzionalità del nostro sistema: banalmente, se abbiamo un container con una webapp, potremmo verificare che l’applicazione risponda all’indirizzo localhost sulla porta 8080.

Per farlo, possiamo aggiungere questa istruzione:

HEALTHCHECK CMD curl --fail http://localhost:8080|| exit 1

Se il comando_curl_ restituisce 0, allora il controllo è andato a buon fine e il nostro_container_ è pronto all’uso; se invece il codice è pari a 1, sappiamo che c’è stato qualche problema.

Versione lunga

Prendiamo come esempio un’applicazione web in Node.js, dove un tipico Dockerfile potrebbe essere il seguente:

FROM node:alpine 

WORKDIR /usr/src/app 

COPY package*.json ./ 

RUN npm install 

COPY . . 

EXPOSE 3000

CMD ["node","app.js"]

Tramite questo Dockerfile, partiamo dall’immagine base di Node.js (riga 1): dopo aver definito la cartella di lavoro dove verranno anche copiati i file di lavoro (riga 2), copiamo i file relativi alle dipendenze (riga 3), le installiamo (riga 4) e copiamo i file applicativi (riga 5). Dal momento che si tratta di un’applicazione Node.js, informiamo Docker che il nostro container sarà in ascolto sulla porta 3000 (riga 6). In ultimo, andiamo ad eseguire il comando che va ad eseguire l’applicazione (riga 7).

Una volta che abbiamo eseguito il comando docker run per avviare il nostro container, possiamo verificare il suo stato tramite il comando docker ps: se tutto va bene, vedremo che sotto la colonna STATUS c’è un messaggio che descrive da quanto la nostra applicazione è stata avviata; questo però ci dice solo che il processo node è attivo, e non se effettivamente l’applicazione sta funzionando come previsto.

$ docker build -t docker-healthcheck .

$ docker run -d -p 3000:3000  

$ docker-healthcheck:latest 

$ docker ps

In questo caso, possiamo pensare di aggiungere un’istruzione all’interno del Dockerfile, per verificare che effettivamente l’applicazione sia stata avviata correttamente: l’idea è quella di eseguire una chiamata tramite curl alla nostra webapp per vedere se effettivamente Node.js è riuscito ad avviare il servizio e risponde correttamente.

Modifichiamo quindi il Dockerfile in questo modo:

Andando nuovamente ad eseguire il comando di build, run e ps, vediamo che vicino allo stato nella colonna omonima, c’è un messaggio (health: starting): inizialmente, ci vorrà del tempo per avviare il controllo dello stato e l’aggiornamento, indipendentemente dal fatto che l’applicazione sia integra o meno. Se l’applicazione si arresta in modo anomalo o è terminata, lo stato cambierà in unhealthy. Per controllare lo stato, usiamo sempre il comando docker ps.

FROM node:alpine 

WORKDIR /usr/src/app 

COPY package*.json ./ 

RUN npm install 

COPY . . 

EXPOSE 3000 

HEALTHCHECK 

CMD curl --fail http://localhost:3000 || exit 1 

CMD ["node","app.js"]

Il comando curl controlla se l’applicazione è in esecuzione o meno facendo una richiesta a localhost sulla porta 3000. Se la richiesta restituisce un 200, restituirà il codice di uscita 0; se l’applicazione non si è avviata correttamente, restituirà il codice di uscita 1.

Questi codici di uscita sono il modo in cui HEALTHCHECK di Docker determina l’integrità del container.

Le opzioni che possono apparire prima di CMD sono:

  • --interval=[durata] (predefinito: 30 secondi)
  • --timeout=[durata] (predefinito: 30 secondi)
  • --start-period=[durata] (predefinito: 0 secondi)
  • --retries=N (predefinito: 3 volte)

Questi argomenti ci permettono di gestire al meglio il nostro controllo: il parametro_interval_ stabilisce il periodo che è necessario attendere prima di procedere con le verifiche di integrità dell’applicazione, in termine di secondi; l’opzione timeout permette invece di attendere un periodo di tempo specifico prima di dichiarare che il controllo ha esito positivo o negativo.

L’argomento start-period fornisce il tempo di inizializzazione per i container che necessitano di tempo per il bootstrap; un eventuale fallimento del controllo durante questo periodo di tempo non verrà considerato nel numero massimo di tentativi.

Tuttavia, se la verifica ha esito positivo durante questa fase, il container viene considerato avviato e tutti gli errori consecutivi faranno parte del conteggio del numero massimo di tentativi; grazie a retries è possibile specificare il numero di errori consecutivi del controllo necessari per dichiarare lo stato del container unhealthy.

Il controllo dell’integrità proverà solo fino al numero di tentativi specificato; se l’applicazione non risponde correttamente

L’istruzione HEALTHCHECK permette anche di eseguire delle verifiche personalizzate, e quindi non tramite un singolo comando: potremmo ad esempio creare un file Js che permetta di eseguire più chiamate al nostro servizio per verificare che un insieme di endpoint della nostra webapp siano raggiungibili e funzionanti.

Per farlo, possiamo definire il nostro file e poi utilizzarlo all’interno del controllo nel Dockerfile in questo modo:

FROM node:alpine 

WORKDIR /usr/src/app 

COPY package*.json ./ 

RUN npm install 

COPY . .

EXPOSE 3000 

HEALTHCHECK --interval=15s --timeout=15s --start-period=30s \ 

CMD node healthcheck.js 

CMD ["node","app.js"]

Risorse utili

Post correlati

Iscriviti al TheRedCode.it Corner

La tecnologia corre, e tu devi correre più veloce per rimanere sempre sul pezzo! 🚀

Riceverai una volta al mese (o anche meno) con codici sconto per partecipare agli eventi del settore, quiz per vincere dei gadget e i recap degli articoli più interessanti pubblicati sul blog

Ci sto!

Partners

Community, aziende e persone che supportano attivamente il blog

Logo di Codemotion
Logo di GrUSP
Logo di Python Milano
Logo di Schrodinger Hat
Logo di Python Biella Group
Logo di Fuzzy Brains
Logo di Django Girls
Logo di Improove
Logo del libro open source
Logo di NgRome

Vuoi diventare #tech content writer? 🖊️

Se vuoi raccontare la tua sul mondo #tech con dei post a tema o vuoi condividere la tua esperienza con la community, sei nel posto giusto! 😉

Manda una mail a collaborazioni[at]theredcode.it con la tua proposta e diventa la prossima penna del blog!

Ma sì, facciamolo!