Acest articol explică ce este un Dockerfile, cum funcționează sistemul de straturi (layers) al Docker și cum poți construi o imagine personalizată pas cu pas.
Un Dockerfile este un fișier text simplu, fără extensie, care conține o succesiune de instrucțiuni ce descriu cum se construiește o imagine Docker.
Procesul de build urmează pașii:
Dockerfiledocker buildFiecare linie dintr-un Dockerfile este o instrucțiune. Ordinea contează - Docker execută instrucțiunile de sus în jos și creează câte un strat (layer) pentru fiecare.
# Comentariile încep cu # INSTRUCȚIUNE argumente
Obligatorie. Prima instrucțiune. Specifică imaginea de bază (base image).
FROM ubuntu:22.04 FROM node:20-alpine FROM python:3.12-slim FROM scratch # imagine goală, pentru binare statice
Recomandare: Folosește varianteslimsaualpinepentru imagini mai mici. Evitălatest- fixează versiunea explicit.
Setează directorul de lucru pentru toate instrucțiunile următoare. Dacă nu există, îl creează.
WORKDIR /app
Echivalentul unui cd /app persistent în imagine.
Copiază fișiere din contextul de build în imagine.
COPY src/ /app/src/ # copiază directorul src/ COPY package.json . # copiază în WORKDIR curent ADD archive.tar.gz /data/ # ADD dezarhivează automat
| Instrucțiune | Dezarhivare automată | URL remote |
|---|---|---|
COPY | Nu | Nu |
ADD | Da (.tar, .gz) | Da |
Recomandare: PreferăCOPYîn loculADDdacă nu ai nevoie de dezarhivare - comportamentul este mai previzibil.
Execută comenzi în shell la momentul build-ului. Fiecare RUN creează un strat nou.
RUN apt-get update && apt-get install -y curl git RUN npm install RUN pip install -r requirements.txt
Recomandare: Combină comenzile cu&&pe o singură linieRUNpentru a reduce numărul de straturi și dimensiunea imaginii.
# Bine
RUN apt-get update \
&& apt-get install -y curl git \
&& rm -rf /var/lib/apt/lists/*
# Evită (3 straturi separate)
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
Setează variabile de mediu disponibile atât la build, cât și la runtime.
ENV NODE_ENV=production ENV PORT=3000 HOST=0.0.0.0
Variabile disponibile doar la build-time, nu în containerul final.
ARG VERSION=1.0 ARG SECRET_KEY # transmis cu --build-arg SECRET_KEY=xyz
Atenție: Nu folosiARGpentru secrete - valorile sunt vizibile în istoricul imaginii (docker history).
Documentează portul pe care aplicația ascultă. Nu publică portul - doar înregistrează intenția.
EXPOSE 3000 EXPOSE 8080/tcp EXPOSE 5353/udp
Publicarea efectivă se face la rulare cu -p 3000:3000.
Definesc comanda implicită la pornirea containerului.
| Instrucțiune | Scop | Poate fi suprascris |
|---|---|---|
CMD | Comandă implicită | Da (docker run … mycommand) |
ENTRYPOINT | Punctul de intrare fix | Greu (–entrypoint) |
# Forma exec (preferată - fără shell intermediar) CMD ["node", "server.js"] ENTRYPOINT ["python", "-m", "gunicorn"] # Forma shell (evită) CMD node server.js
Combinarea lor:
ENTRYPOINT ["python", "app.py"] CMD ["--port", "8080"] # argumente implicite, suprascribile
Declară un punct de montare pentru date persistente.
VOLUME ["/data", "/logs"]
Schimbă utilizatorul pentru instrucțiunile următoare și pentru procesul final.
RUN useradd -m appuser USER appuser
Recomandare de securitate: Rulează întotdeauna aplicațiile ca utilizator non-root.
Adaugă metadate la imagine (autor, versiune, descriere).
LABEL maintainer="echipa@exemplu.ro" LABEL version="2.1.0" LABEL description="API REST pentru serviciul X"
Definește o comandă pentru verificarea stării containerului.
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ CMD curl -f http://localhost:3000/health || exit 1
# ── Etapa 1: dependențe ────────────────────────────────────── FROM node:20-alpine AS deps WORKDIR /app COPY package*.json ./ RUN npm ci --only=production # ── Etapa 2: build ─────────────────────────────────────────── FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # ── Etapa 3: imagine finală ─────────────────────────────────── FROM node:20-alpine AS final LABEL maintainer="dev@exemplu.ro" LABEL version="1.0.0" ENV NODE_ENV=production ENV PORT=3000 WORKDIR /app # Copiază doar ce e necesar COPY --from=deps /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist # Utilizator non-root RUN addgroup -S appgroup && adduser -S appuser -G appgroup USER appuser EXPOSE 3000 HEALTHCHECK --interval=30s --timeout=5s \ CMD wget -qO- http://localhost:3000/health || exit 1 CMD ["node", "dist/server.js"]
Aceasta folosește multi-stage build - o tehnică prin care imaginea finală conține doar artefactele necesare, nu întregul toolchain de build.
Similar cu .gitignore, exclude fișiere din contextul de build (măresc dimensiunea și pot expune date sensibile).
# .dockerignore node_modules/ .git/ *.log .env .env.local dist/ coverage/ **/*.test.ts Dockerfile docker-compose*.yml README.md
# Construiește imaginea cu tag docker build -t myapp:1.0 . # Specifică un Dockerfile cu alt nume docker build -f Dockerfile.prod -t myapp:prod . # Transmite argumente de build docker build --build-arg VERSION=2.0 -t myapp:2.0 . # Fără cache (rebuild complet) docker build --no-cache -t myapp:latest . # Construiește o anumită etapă (multi-stage) docker build --target builder -t myapp:debug . # Rulează containerul docker run -d -p 3000:3000 --name myapp myapp:1.0 # Rulează interactiv (debug) docker run -it --rm myapp:1.0 sh # Inspectează straturile imaginii docker history myapp:1.0 # Publică imaginea docker tag myapp:1.0 utilizator/myapp:1.0 docker push utilizator/myapp:1.0
Docker reutilizează layerele din cache dacă instrucțiunile nu s-au schimbat. Pune fișierele care se schimbă rar sus, cele care se schimbă des jos.
# Bine: package.json se schimbă rar față de codul sursă COPY package*.json ./ RUN npm ci COPY . . # sursele se schimbă des - copiază la final # Evită: orice schimbare în sursă invalidează și npm ci COPY . . RUN npm ci
alpine sau slim ca bazăRUN:RUN apt-get update \
&& apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/*
Separă etapa de compilare de imaginea finală de producție. Rezultatul: imagini de 5–10× mai mici.
USER–secret la build sau variabile de mediu la runtimedocker scout sau trivyUn container = un singur proces principal. Evită să rulezi mai multe servicii (nginx + app + db) în același container.