Cosa si intende per utility container
Utility container non è un termine ufficiale nella documentazione Docker. Serve qui per descrivere un uso ricorrente: un container che non avvia un’applicazione long-running (API, frontend, database), ma fornisce un ambiente (runtime, tool) con cui si esegue un comando scelto al momento, spesso in combinazione con un bind mount verso una cartella del progetto sull’host.
Fino a questo punto il focus è stato su container applicativi: immagine costruita con Dockerfile, avvio con docker run o Compose, processo principale che resta in esecuzione. Resta il caso d’uso centrale di Docker.
In parallelo, lo stesso motore può essere usato per automatizzare task (scaffolding, install dipendenze, CLI) senza installare Node, npm, PHP, Composer, ecc. globalmente sulla macchina host.
Il problema che risolvono
Molti linguaggi richiedono tool per creare un progetto (npm init, generatori Laravel, ecc.). Senza Docker, quei tool vanno installati sull’host. Con un utility container si esegue lo stesso comando dentro un’immagine che già contiene l’ambiente.
Il vantaggio è particolare quando lo stack locale sarebbe pesante (PHP, estensioni, versioni multiple). Anche per Node, il pattern resta utile per uniformare versioni e ridurre dipendenze sull’host.
docker run con immagine Node: modalità interattiva
L’immagine ufficiale node può avviarsi in modalità interattiva (-it): il processo predefinito espone una shell REPL di Node. Senza -it, il container può uscire subito.
Uscita tipica: Ctrl+C (a volte due volte) termina il processo e il container si ferma.
docker exec su un container in esecuzione
docker exec esegue un comando aggiuntivo in un container già in eseguzione, senza sostituire il processo principale definito da CMD / ENTRYPOINT.
Sintassi base:
docker exec -it NOME_CONTAINER npm initSenza -i e -t, comandi che richiedono input (come npm init interattivo) possono terminare subito o non ricevere input dal terminale.
Esempio d’uso: ispezionare file, leggere log, lanciare una shell di debug mentre l’app principale continua a girare.
Sovrascrivere il comando di avvio: argomenti dopo il nome immagine
Con docker run, tutto ciò che segue il nome dell’immagine sostituisce il CMD predefinito dell’immagine (se non c’è ENTRYPOINT che lo modifica).
Esempio concettuale:
docker run -it -v "<PERCORSO_PROGETTO>:/app" -w /app node:14-alpine npm initQui non si avvia la REPL di Node: si esegue npm init. Al termine, il processo finisce e il container si arresta.
Questa sintassi è la chiave per i task “una tantum” dentro un ambiente containerizzato.
Dockerfile minimale per utility image
Un’immagine dedicata può essere molto snella:
FROM node:14-alpineWORKDIR /appNessun CMD obbligatorio: il comando viene passato a docker run (o tramite Compose). WORKDIR /app fa sì che i comandi partano da quella directory, coerente con il bind mount su /app.
Build ed esecuzione:
docker build -t node-util .docker run -it --rm -v "<PERCORSO_ASSOLUTO_CARTELLA>:/app" node-util npm initCon --rm il container viene rimosso alla fine del comando, evitando accumulo di container fermi.
Il bind mount fa sì che package.json creato nel container appaia nella cartella del progetto sull’host.
ENTRYPOINT vs CMD: comando fisso e argomenti aggiunti
Nel Dockerfile, CMD può essere sostituito dagli argomenti dopo il nome immagine in docker run.
ENTRYPOINT definisce l’eseguibile (o lo script) fisso; ciò che si passa dopo il nome immagine viene appeso come argomenti all’entrypoint.
Esempio: entrypoint npm, argomenti da riga comando solo init o install:
FROM node:14-alpineWORKDIR /appENTRYPOINT ["npm"]Dopo rebuild:
docker run -it --rm -v "<PERCORSO>:/app" mynpm initdocker run -it --rm -v "<PERCORSO>:/app" mynpm install express --saveVantaggi:
- comandi più corti e meno errori di battitura
- immagine “specializzata” su una CLI (es. solo
npm)
Attenzione: con bind mount, un comando distruttivo nel container può riflettersi sull’host. Restringere l’entrypoint riduce il rischio di lanciare per errore comandi arbitrari.
Docker Compose: un solo servizio “npm”
Compose è utile anche con un servizio, per non riscrivere ogni volta volumi, stdin_open / tty e build.
Esempio schematico:
version: "3.8"
services: npm: build: . stdin_open: true tty: true volumes: - .:/appIl Dockerfile nella stessa cartella può contenere ENTRYPOINT ["npm"] e WORKDIR /app.
docker compose up non è l’ideale per utility one-shot
docker compose up avvia i servizi come processi “da tenere su”. Se l’entrypoint è solo npm senza sottocomando, il comportamento può essere ambiguo o poco utile.
Per eseguire un singolo comando contro la definizione del servizio si usa:
docker compose run --rm npm initrun: crea un container per il servizionpm, esegue il comando indicato (initviene appeso aENTRYPOINT npm), poi esce.--rm: rimuove il container al termine. Senza--rm, i container lasciati darunsi accumulano (verificabili condocker ps -a).
Analogamente: docker compose run --rm npm install express --save.
Confronto rapido
| Comando | Uso tipico |
|---|---|
docker compose up | Avviare servizi che restano in esecuzione |
docker compose run | Eseguire un task una tantum su un servizio (utility) |
docker compose exec | Eseguire comandi in un servizio già avviato con up |
Permessi su Linux
Su Linux, file creati nel container possono risultare di proprietà di un utente diverso da quello dell’host, a seconda di come Docker mappa UID/GID. Nei progetti con utility container e bind mount conviene documentare o automatizzare utente/gruppo (es. opzioni user in Compose o build) secondo le esigenze del team. I dettagli dipendono da distro e configurazione Docker.
Riepilogo
- I container applicativi eseguono il processo principale dell’app.
- Gli utility container forniscono un ambiente per comandi CLI, spesso con bind mount verso il progetto locale.
- Argomenti dopo il nome immagine in
docker runsostituiscono ilCMD(salvo interazione conENTRYPOINT). ENTRYPOINT ["npm"]permette di passare solo sottocomandi (init,install, …).docker compose run --rmè adatto ai task one-shot senza lasciare container orfani.
Esercizi correlati
- Creare un’immagine con solo
FROM+WORKDIR, generarepackage.jsoncondocker rune bind mount, verificare il file sull’host. - Aggiungere
ENTRYPOINT ["npm"]e confrontaredocker run ... initcondocker run ... npm initsenza entrypoint. - Definire il servizio
npmin Compose ed eseguiredocker compose run --rm npm initcon e senza--rm, osservandodocker ps -a. - Avviare un container in background e usare
docker exec -itper un comando interattivo; confrontare condocker runone-shot.