Scrivere Dockerfile essenziali ed entrypoint shell
Scriva script di build multistadio e shim entrypoint robusti, con gestione dei segnali e templating della configurazione.
Scrivere Dockerfile essenziali ed entrypoint shell è una lezione DevOps Bootcamp gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento DevOps Bootcamp, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso DevOps Bootcamp include 4 lezioni in totale.
Perché i Dockerfile snelli sono importanti per il DevOps
Negli ambienti di produzione, ogni megabyte contenuto in un'immagine Docker ha un costo: download più lenti, superfici di attacco più ampie e spazio sprecato nel registry. Dockerfile snelli, combinati con entrypoint shell robusti, sono un segno distintivo di una pratica DevOps matura.
- Le build multi-stage separano gli strumenti necessari durante la build dall'immagine runtime finale, riducendone drasticamente le dimensioni.
- Gli shim di entrypoint sono piccoli script shell che inizializzano i container: generano i file di configurazione dai template, convalidano le variabili d'ambiente, gestiscono i segnali e infine eseguono il processo principale con exec.
- Insieme costituiscono la base per workload containerizzati affidabili e portabili in Kubernetes, ECS e negli ambienti bare metal.
Questa lezione tratta entrambe le discipline dall'inizio alla fine, con pattern adatti alla produzione che può inserire direttamente nelle pipeline.
Anatomia di un Dockerfile multi-stage
Un Dockerfile multi-stage utilizza più istruzioni FROM. Ogni stage è un insieme isolato di layer; nel passaggio allo stage successivo vengono copiati solo gli artifact necessari.
- Stage 0 (builder): installa compilatori, test runner e dipendenze di build.
- Stage 1 (runtime): parte da una base minimale (ad es.
alpine,distroless) e copia solo i binari compilati o i bundle dell'applicazione. - L'immagine finale non contiene mai
gcc,makeo il codice sorgente, a meno che non vengano copiati esplicitamente.
Utilizzi --from=<stage> in COPY per trasferire file oltre i confini tra gli stage. Assegni un nome agli stage con AS <name> per migliorare la leggibilità e selezionare uno stage specifico con docker build --target.
# ---- Stage 0: builder ----
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags='-s -w' -o /app/server ./cmd/server
# ---- Stage 1: runtime ----
FROM gcr.io/distroless/static-debian12
COPY --from=builder /app/server /server
ENTRYPOINT ["/server"]Ridurre i layer e invalidare la cache
Ogni istruzione RUN, COPY e ADD crea un nuovo layer. Un ordine inadeguato delle istruzioni invalida inutilmente la cache di build, rallentando le pipeline CI.
- Copi i manifest delle dipendenze (
package.json,go.mod,requirements.txt) prima di copiare il codice sorgente, così l'installazione delle dipendenze viene memorizzata nella cache in modo indipendente. - Concateni i comandi correlati con
&&ed esegua la pulizia nello stesso layerRUNper evitare di lasciare la cache dei pacchetti nei layer intermedi. - Utilizzi
--no-cachenei package manager e rimuova i file degli indici dopo l'installazione.
FROM python:3.12-slim AS builder
WORKDIR /app
# 1. Install deps first (cached until requirements change)
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
# 2. Copy source (cache busted only when code changes)
COPY src/ ./src/
FROM python:3.12-slim
COPY --from=builder /install /usr/local
COPY --from=builder /app/src /app/src
WORKDIR /app
CMD ["python", "-m", "src.main"]Secret BuildKit e forwarding SSH
Registry privati, chiavi SSH e token API non devono mai comparire nei layer dell'immagine. Docker BuildKit offre due meccanismi sicuri:
--secret: monta un file contenente un secret all'interno di un singolo passaggioRUN, senza incorporarlo in un layer. È possibile accedervi tramite/run/secrets/<id>.--ssh: inoltra il socket dell'agent SSH dell'host nella build, consentendo agit clonedi autenticarsi senza incorporare chiavi private.
Abiliti BuildKit con DOCKER_BUILDKIT=1 oppure tramite docker buildx build. La direttiva # syntax=docker/dockerfile:1 abilita queste funzionalità.
# syntax=docker/dockerfile:1
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
# Mount NPM token as a secret — never stored in the image
RUN --mount=type=secret,id=npm_token \
NPM_TOKEN=$(cat /run/secrets/npm_token) \
npm ci --prefer-offline
# Usage at build time:
# DOCKER_BUILDKIT=1 docker build \
# --secret id=npm_token,src=~/.npmrc-token \
# -t myapp:latest .Scrivere uno shim di entrypoint robusto
Lo shim di entrypoint è uno script shell impostato come ENTRYPOINT nel Dockerfile. Il suo compito è preparare l'ambiente runtime prima di cedere il controllo al processo principale.
Uno shim ben strutturato segue questo ordine:
- Passaggio 1: imposti
set -euo pipefailin modo che qualsiasi errore interrompa subito l'esecuzione. - Passaggio 2: convalidi le variabili d'ambiente obbligatorie e interrompa subito l'esecuzione con un messaggio utile in caso di errore.
- Passaggio 3: generi i file di configurazione a partire dalle variabili d'ambiente.
- Passaggio 4: registri gli handler dei segnali per un arresto ordinato.
- Passaggio 5:
exec "$@"— sostituisca la shell con il processo principale, così il PID 1 è l'applicazione e non lo shim.
Il comando exec finale è fondamentale: senza di esso, i segnali inviati da Kubernetes o dal runtime Docker non vengono inoltrati al processo figlio.
#!/usr/bin/env bash
set -euo pipefail
# Step 2: validate required env vars
REQUIRED_VARS=(DATABASE_URL APP_SECRET PORT)
for var in "${REQUIRED_VARS[@]}"; do
if [[ -z "${!var:-}" ]]; then
echo "[entrypoint] ERROR: required env var '$var' is not set" >&2
exit 1
fi
done
# Step 3: template config (see next scene)
# Step 4: signal handling (see scene after that)
# Step 5: hand off to CMD
exec "$@"Generare configurazioni dai template con envsubst
envsubst (fornito dal pacchetto GNU gettext, presente in Alpine come gettext) sostituisce i segnaposto ${VAR} in un file template con i valori correnti delle variabili d'ambiente.
- Inserisca nell'immagine un template di configurazione
*.tmpl; l'entrypoint lo renderizza all'avvio. - Passi esplicitamente a
envsubstl'elenco delle variabili, così non espanderà accidentalmente altri simboli del dollaro (ad es. nelle regex di nginx). - Scriva il file renderizzato in un percorso scrivibile come
/tmpo in un volume di configurazione dedicato.
#!/usr/bin/env bash
# Template: /etc/nginx/conf.d/app.conf.tmpl contains:
# server { listen ${NGINX_PORT}; server_name ${SERVER_NAME}; ... }
export NGINX_PORT=${NGINX_PORT:-8080}
export SERVER_NAME=${SERVER_NAME:-localhost}
envsubst '${NGINX_PORT} ${SERVER_NAME}' \
< /etc/nginx/conf.d/app.conf.tmpl \
> /etc/nginx/conf.d/app.conf
echo "[entrypoint] nginx config rendered:"
grep -E 'listen|server_name' /etc/nginx/conf.d/app.conf
exec "$@"Gestione dei segnali e arresto ordinato
I container ricevono SIGTERM quando vengono arrestati da Kubernetes, ECS o docker stop. Se lo shim di entrypoint è il PID 1 e non inoltra i segnali, il processo principale viene terminato con SIGKILL al termine del periodo di tolleranza, causando richieste perse o corruzione dei dati.
- Utilizzi
trapper intercettareSIGTERMeSIGINTnello shim. - Inoltri il segnale al PID figlio utilizzando
kill -TERM "$child". - Utilizzi
wait "$child"per attendere la terminazione del processo figlio, quindi propaghi il relativo codice di uscita. - In alternativa, utilizzi
execper sostituire completamente la shell: in questo modo il sistema operativo consegna i segnali direttamente al processo figlio e non serve alcun trap. Questo è il pattern preferito nei casi semplici.
#!/usr/bin/env bash
set -euo pipefail
# Start main process in background
"$@" &
child=$!
# Forward SIGTERM and SIGINT to the child
trap 'echo "[entrypoint] caught SIGTERM, forwarding..."; kill -TERM "$child"' TERM
trap 'echo "[entrypoint] caught SIGINT, forwarding..."; kill -INT "$child"' INT
# Wait for child to exit and capture its exit code
wait "$child"
exit $?Utilizzare tini come processo init minimale
Quando il container genera processi figli (ad es. una shell che crea processi worker), è necessario un vero init che raccolga i processi zombie. tini è un binario init minimale progettato appositamente per i container.
- Aggiunga
tiniall'immagine e lo imposti come wrapper dell'entrypoint. - Raccoglie i processi figli zombie, inoltra correttamente i segnali e termina con il codice di uscita del processo figlio.
- Docker include un tini integrato, attivabile con
docker run --init, ma incorporarlo nell'immagine garantisce un comportamento coerente tra i diversi runtime (Kubernetes, ECS ecc.).
FROM node:20-alpine
# Install tini for proper signal handling and zombie reaping
RUN apk add --no-cache tini
WORKDIR /app
COPY --chown=node:node . .
RUN npm ci --omit=dev
USER node
# tini wraps CMD; forwards SIGTERM and reaps zombies
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "server.js"]Eseguire il processo come utente non root
I container eseguiti come root (UID 0) rappresentano un grave rischio per la sicurezza: una fuga dal container concede l'accesso completo all'host. Passi sempre a un utente senza privilegi prima di eseguire il processo principale.
- Crei un utente e un gruppo di sistema dedicati nel Dockerfile con
addgroup/adduser(Alpine) oppuregroupadd/useradd(Debian). - Modifichi il proprietario dei file dell'applicazione con
COPY --chown=appuser:appgroup, più efficiente rispetto a un layerRUN chownseparato. - Passi all'utente con l'istruzione
USER. L'entrypoint e CMD ereditano questo utente. securityContext.runAsNonRoot: truedi Kubernetes rifiuterà di avviare un'immagine che continua a essere eseguita come root.
FROM python:3.12-slim
# Create non-root user
RUN groupadd --gid 1001 appgroup && \
useradd --uid 1001 --gid appgroup --shell /bin/bash --create-home appuser
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy app files with correct ownership in a single layer
COPY --chown=appuser:appgroup src/ ./src/
COPY --chown=appuser:appgroup entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
USER appuser
ENTRYPOINT ["/entrypoint.sh"]
CMD ["python", "-m", "src.main"]Health check e probe di readiness nell'immagine
Le probe di liveness e readiness di Kubernetes sono definite nei manifest, ma è anche possibile includere un HEALTHCHECK nel Dockerfile per gli ambienti standalone con docker run e Docker Compose.
HEALTHCHECK --interval=10s --timeout=3s --start-period=15s --retries=3 CMD ...- Utilizzi
curl --failowget -qO-per i servizi HTTP; per i demoni non HTTP, esegua il probe su un socket con/dev/tcp/localhost/PORT. - Installi solo ciò che serve: nelle immagini distroless eviti di aggiungere
curlsolo per i health check; utilizzi invece un binario di probe dedicato o il binario di health check dell'applicazione.
FROM nginx:1.27-alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY dist/ /usr/share/nginx/html/
# Lightweight health check using bash TCP pseudo-device
# (no curl needed — works on any image with bash)
HEALTHCHECK --interval=15s --timeout=5s --start-period=10s --retries=3 \
CMD bash -c 'exec 3<>/dev/tcp/localhost/80 && echo -e "GET /health HTTP/1.0\r\n" >&3 && cat <&3 | grep -q "200 OK"' || exit 1
EXPOSE 80Riunire tutti gli elementi: un entrypoint per la produzione
Di seguito è riportato uno shim di entrypoint completo e adatto alla produzione, che combina tutti i pattern di questa lezione: convalida delle variabili d'ambiente, generazione della configurazione dai template, inoltro dei segnali e passaggio del controllo con exec. Questo pattern viene utilizzato in microservizi Node.js, Python e Go reali distribuiti su Kubernetes.
- Ogni sezione è commentata per fungere da template autoesplicativo.
- Lo shim è mantenuto al di sotto delle 50 righe: gli entrypoint dovrebbero essere semplici e facilmente verificabili.
- Noti il comando
exec "$@"finale: completata tutta la configurazione, la shell viene sostituita dal processo dell'applicazione, che diventa il PID 1 e riceve direttamente tutti i segnali del sistema operativo.
#!/usr/bin/env bash
# entrypoint.sh — production-grade container entrypoint shim
set -euo pipefail
# ── 1. Validate required environment variables ──────────────────
REQUIRED=(DATABASE_URL APP_SECRET PORT LOG_LEVEL)
for var in "${REQUIRED[@]}"; do
[[ -n "${!var:-}" ]] || { echo "[entrypoint] FATAL: $var is not set" >&2; exit 1; }
done
# ── 2. Set safe defaults for optional variables ─────────────────
export HOST=${HOST:-0.0.0.0}
export WORKERS=${WORKERS:-2}
# ── 3. Render config template ───────────────────────────────────
if [[ -f /etc/app/app.conf.tmpl ]]; then
envsubst '${DATABASE_URL} ${PORT} ${LOG_LEVEL} ${HOST}' \
< /etc/app/app.conf.tmpl \
> /etc/app/app.conf
echo "[entrypoint] config rendered at /etc/app/app.conf"
fi
# ── 4. Wait for dependent services (optional, fast) ─────────────
if [[ -n "${WAIT_FOR_HOST:-}" ]]; then
echo "[entrypoint] waiting for ${WAIT_FOR_HOST}:${WAIT_FOR_PORT:-5432}..."
until bash -c "exec 3<>/dev/tcp/${WAIT_FOR_HOST}/${WAIT_FOR_PORT:-5432}" 2>/dev/null; do
sleep 1
done
echo "[entrypoint] dependency ready"
fi
# ── 5. Hand off to CMD (PID 1 becomes the application) ──────────
echo "[entrypoint] starting: $*"
exec "$@"Verifica delle conoscenze: gestione dei segnali negli entrypoint
Verifichi la propria comprensione della gestione dei segnali negli script di entrypoint dei container.
Riepilogo: Dockerfile snelli ed entrypoint shell
Ha esaminato tutti gli aspetti della creazione di container per la produzione:
- Le build multi-stage utilizzano più istruzioni
FROMper tenere compilatori e strumenti di build fuori dall'immagine finale, producendo layer runtime snelli e minimali. - L'ordine dei layer — copiare i manifest delle dipendenze prima del codice sorgente — massimizza i riscontri nella cache e accelera le pipeline CI.
- I secret e i mount SSH di BuildKit mantengono le credenziali fuori dalla cronologia dell'immagine senza compromettere le build autenticate.
- Gli shim di entrypoint convalidano le variabili d'ambiente, generano i file di configurazione con
envsubste cedono il controllo all'applicazione tramiteexec "$@". - La gestione dei segnali richiede
exec(in modo che l'applicazione sia il PID 1) oppure un pattern esplicitotrap+kill+waitquando vengono utilizzati job in background. - tini aggiunge la raccolta dei processi zombie e il corretto inoltro dei segnali quando il container genera più processi.
- Gli utenti non root e le istruzioni
HEALTHCHECKcompletano un'immagine sicura e osservabile, pronta per i workload di produzione su Kubernetes.
Combinando questi pattern in modo coerente, le immagini saranno più piccole, più rapide da distribuire e molto più robuste in condizioni di produzione.
Impara DevOps Bootcamp con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 142
- Lezioni
- 568
Domande Frequenti
La lezione «Scrivere Dockerfile essenziali ed entrypoint shell» è gratuita?
Sì — il testo completo di «Scrivere Dockerfile essenziali ed entrypoint shell» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso DevOps Bootcamp, passa a CoddyKit PRO. Il corso DevOps Bootcamp include 4 lezioni in totale.
Cosa imparerò in «Scrivere Dockerfile essenziali ed entrypoint shell»?
Scriva script di build multistadio e shim entrypoint robusti, con gestione dei segnali e templating della configurazione. Eserciti DevOps Bootcamp con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare DevOps Bootcamp?
Non è richiesta alcuna esperienza precedente. DevOps Bootcamp su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.
Quanto tempo richiede la lezione «Scrivere Dockerfile essenziali ed entrypoint shell»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione DevOps Bootcamp?
Sì. Ogni lezione DevOps Bootcamp include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Scrivere Dockerfile essenziali ed entrypoint shell
- Creare template di configurazione con envsubst e heredoc
- Gestire risorse cloud tramite CLI e jq
- Probe di salute, controlli di readiness e cicli di attesa