Gestione affidabile delle dipendenze tra container con Docker Compose

Gestione affidabile delle dipendenze tra container con Docker Compose

Docker Compose è uno strumento potente per gestire l'orchestrazione di container Docker. Quando si lavora con un'applicazione complessa composta da più servizi, è essenziale garantire che i container siano avviati e inizializzati in un ordine specifico, specialmente quando esistono dipendenze tra di essi. In questo articolo, esploreremo come gestire in modo affidabile le dipendenze tra container in fase di inizializzazione con Docker Compose.

Comprendere le dipendenze

Prima di affrontare la gestione delle dipendenze, è fondamentale capire quali sono le relazioni tra i vari servizi nel tuo ambiente Docker Compose. Ad esempio, immagina di avere un'applicazione web che dipende da un database. In questo caso, il servizio web dovrebbe aspettarsi che il servizio del database sia completamente inizializzato prima di avviarsi.

Utilizzo di depends_on

Docker Compose offre l'attributo depends_on che consente di dichiarare le dipendenze tra i servizi. Tuttavia, è importante notare che depends_on non garantisce che un servizio sia completamente avviato prima che un altro venga avviato. In altre parole, il fatto che un servizio sia "avviato" non implica che sia pronto per essere utilizzato.

Ecco un esempio di come utilizzare depends_on nel tuo file docker-compose.yml:


version: '3'
services:
  web:
    image: web-app
    depends_on:
      - db
  db:
    image: database

In questo esempio, il servizio web dipende dal servizio db, ma non c'è alcuna garanzia che il database sia pronto per le connessioni quando il servizio web viene avviato.

Opzioni Avanzate di depends_on

condition

L'opzione condition consente di specificare una condizione personalizzata per il servizio dipendente. Ad esempio, puoi utilizzare questa opzione per verificare se un servizio è in uno stato specifico prima di avviare il servizio dipendente. Ecco un esempio:


version: '3'
services:
  web:
    image: web-app
    depends_on:
      db:
        condition: service_healthy
  db:
    image: database

In questo caso, il servizio web avrà un ritardo aggiuntivo se il servizio db non è segnalato come sano.

Poichè abbiamo inserito come condizione lo stato di salute del servizio, è ora necessario inserire un blocco healthcheck nel servizio database ed effettuare un test sullo stato del servizio stesso:


version: '3'
services:
  web:
    image: web-app
    depends_on:
      db:
        condition: service_healthy
  db:
    image: database
    healthcheck:
        test: ["CMD", "dbadmin", "ping", "-h", "127.0.0.1", "--silent"]
        interval: 2s
        timeout: 30s
        retries: 3
        start_period: 3s 

In questo esempio, trascorsi 3 secondi dall'avvio del servizio effettuiamo un ping sul servizio stesso dall'interno del container ripetendo l'operazione per 3 volte con un intervallo di 2 secondi tra un test e l'altro e un timeout nella risposta di 30 secondi.

In questo modo, eseguendo docker compose up -d, vedremo nel terminale se il nostro servizio verrà constrassegnato come Healthy o meno.

max_retries

L'opzione max_retries consente di specificare il numero massimo di tentativi che Docker Compose dovrebbe fare prima di considerare un servizio come pronto. Può essere utile in situazioni in cui un servizio potrebbe richiedere un po' di tempo per essere completamente avviato.


version: '3'
services:
  web:
    image: web-app
    depends_on:
      db:
        max_retries: 10
  db:
    image: database

In questo esempio, Docker Compose farà fino a 10 tentativi di connessione al servizio db prima di considerare che il servizio web può essere avviato.

timeout

L'opzione timeout consente di specificare un limite di tempo per quanto tempo dovrebbe aspettare Docker Compose prima di considerare che un servizio è pronto. Può essere utile per evitare attese indefinite.


version: '3'
services:
  web:
    image: web-app
    depends_on:
      db:
        timeout: 60 seconds
  db:
    image: database

In questo esempio, Docker Compose attende al massimo 60 secondi prima di considerare il servizio db pronto per il servizio web.

Attendere il Servizio con wait-for-it

Per garantire che un servizio sia completamente inizializzato prima di avviare un altro, puoi utilizzare lo script wait-for-it. Questo script attende che un servizio sia disponibile prima di continuare l'esecuzione dello script di avvio.

Scarica lo script wait-for-it.sh:


curl -o wait-for-it.sh https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh
chmod +x wait-for-it.sh

Aggiungi lo script nei tuoi servizi:


version: '3'
services:
  web:
    image: web-app
    command: ["./wait-for-it.sh", "db:5432", "--", "start-web.sh"]
    depends_on:
      - db
  db:
    image: database

In questo esempio, il servizio web utilizza lo script wait-for-it.sh prima di eseguire il comando effettivo (start-web.sh). Questo assicura che il servizio web attenda che il servizio db sia disponibile prima di continuare con l'esecuzione.

Utilizzo di Strumenti di Orchestrazione

Alcune situazioni possono richiedere una soluzione più avanzata. Strumenti come Dockerize o Docker Compose Wait sono progettati specificamente per affrontare problemi legati alla gestione delle dipendenze e possono essere integrati nel tuo processo di inizializzazione dei container.


version: '3'
services:
  web:
    image: web-app
    command: ["dockerize", "-wait", "tcp://db:5432", "-timeout", "1m", "./start-web.sh"]
  db:
    image: database

Questo esempio utilizza Dockerize nel comando di avvio del servizio web per attendere che il servizio del database sia disponibile prima di eseguire start-web.sh.

Conclusioni

Gestire in modo affidabile le dipendenze tra container in fase di inizializzazione con Docker Compose richiede una combinazione di dichiarazioni di dipendenza (depends_on) e strumenti aggiuntivi come wait-for-it o Dockerize. Assicurati di comprendere le esigenze specifiche della tua applicazione e di testare attentamente la configurazione per garantire una corretta gestione delle dipendenze in un ambiente Docker Compose complesso.

Torna su