Usare HEALTHCHECK con Docker
Published: 2024-03-21 13:32:52

---
title: Usare HEALTHCHECK con Docker
published: true
date: 2021-03-30 00:00:00 UTC
tags: 
canonical_url: https://theredcode.it/docker/quando-usare-healthcheck-con-docker/
---

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.

# V **ersione 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

- [Docker](https://amzn.to/3cSVvUG) (disponibile su Amazon)
- [Come installare Docker (e Docker Compose)](https://www.youtube.com/watch?v=Xea_9GYFpaA)
- [Docker cheatsheet](https://www.theredcode.it/docker-cheatsheet-2/)
- [Dockerfile cheatsheet](https://www.theredcode.it/dockerfile-cheatsheet/)
- [Esplorando il Dockerfile](https://www.theredcode.it/esplorando-il-dockerfile/)
- [Canale di Emmecilab](https://www.youtube.com/c/EmmeCiLab/about)