Bones Pràctiques i Depuració
Bones pràctiques per treballar amb Docker
A mesura que utilitzeu Docker més i més, us adonareu que hi ha maneres millors i pitjors de fer les coses. Aquí us explico les pràctiques recomanades que us estalviaran problts i farant que les vostres aplicacions siguin més robustes i mantenibles.
Mantenir les imatges petites
Les imatges grans són problemàtiques: triguen més a descarregar, ocupen més espai al disc, i sovint contenen programari innecessari que podria tenir vulnerabilitats de seguretat. Hi ha diverses tècniques per mantenir les imatges petites.
Primer, utilitzeu imatges base lleugeres quan sigui possible. Les variants "alpine" de les imatges oficials són molt més petites que les variants estàndard. Per exemple, python:3.12-alpine és molt més petita que python:3.12. L'única desavantatge és que Alpine Linux usa musl libc en lloc de glibc, cosa que de vegades pot causar incompatibilitats amb certs paquets, però per la majoria d'aplicacions funciona perfectament.
Segon, minimitzeu el nombre de capes. Cada instrucció RUN al Dockerfile crea una nova capa. En lloc de tenir múltiples instruccions RUN, combineu-les quan tingui sentit:
# Menys òptim - crea 3 capes
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y vim
# Millor - crea només 1 capa
RUN apt-get update && \
apt-get install -y curl vim && \
rm -rf /var/lib/apt/lists/*
Fixeu-vos que també eliminem els fitxers cache d'apt al final per fer la capa més petita.
Tercer, utilitzeu .dockerignore. Aquest fitxer funciona com .gitignore: especifica quins fitxers i directoris NO s'haurien de copiar a la imatge. Per exemple, no necessiteu copiar el directori .git, fitxers temporals, o documentació:
Això fa que el context de construcció sigui més petit i ràpid de processar.
Multi-stage builds: el secret de les imatges professionals
Els multi-stage builds són una tècnica avançada però extremadament útil. La idea és utilitzar múltiples instruccions FROM en un mateix Dockerfile, cadascuna definint una "stage" o etapa de construcció. Això us permet tenir una etapa per compilar o construir l'aplicació (amb totes les eines de desenvolupament), i després una etapa final molt més lleugera que només conté l'aplicació compilada.
Per exemple, per una aplicació Go:
# Etapa 1: Compilació
FROM golang:1.23-alpine AS builder
WORKDIR /build
COPY . .
RUN go build -o app .
# Etapa 2: Imatge final
FROM alpine:3.20
WORKDIR /app
COPY --from=builder /build/app .
CMD ["./app"]
La imatge final no conté el compilador de Go ni els fitxers font, només el binari compilat. Això pot reduir la mida de la imatge de centenars de megabytes a pocs megabytes.
No executeu contenidors com a root
Per defecte, els processos dins dels contenidors s'executen com a usuari root, cosa que és un risc de seguretat. Si algú compromet el vostre contenidor, tindria permisos de root dins del contenidor. Tot i que Docker proporciona aïllament, és millor seguir el principi del mínim privilegi.
Podeu crear un usuari no privilegiat al Dockerfile:
FROM python:3.12-slim
# Crear un usuari no-root
RUN useradd -m -u 1000 appuser
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
# Canviar a l'usuari no-root
USER appuser
CMD ["python", "app.py"]
Utilitzar variables d'entorn per la configuració
Mai codifiqueu en dur coses com contrasenyes, URLs d'APIs, o qualsevol configuració que pugui canviar entre entorns (desenvolupament, staging, producció). Utilitzeu variables d'entorn:
import os
DB_HOST = os.environ.get('DB_HOST', 'localhost')
DB_USER = os.environ.get('DB_USER', 'user')
DB_PASSWORD = os.environ.get('DB_PASSWORD')
Això fa que la mateixa imatge es pugui utilitzar en diferents entorns simplement passant diferents variables d'entorn.
Especificar versions explícites
Ja ho hem dit abans, però és tan important que val la pena repetir-ho: sempre especifiqueu versions concretes de les imatges base i les dependències. No utilitzeu FROM python:latest o RUN pip install flask. Utilitzeu versions específiques:
I al requirements.txt:
Això garanteix que la imatge es construirà de la mateixa manera avui i d'aquí a sis mesos.
Health checks per aplicacions crítiques
Docker permet definir health checks al Dockerfile per monitorar si l'aplicació està funcionant correctament:
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:5000/ || exit 1
Això fa que Docker comprovi cada 30 segons si l'aplicació respon correctament. Si falla 3 vegades seguides, Docker marcarà el contenidor com "unhealthy". Això és molt útil quan s'utilitza amb orquestradors com Kubernetes.
Podeu trobar més bones pràctiques a la documentació oficial: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
Registres d'imatges: Docker Hub i alternatives
Fins ara hem treballat només amb imatges locals o imatges públiques de Docker Hub. Però en un entorn professional, sovint necessitareu compartir les vostres imatges amb altres membres de l'equip o desplegar-les a servidors de producció. Aquí és on entren els registres d'imatges.
Docker Hub: el registre públic per excel·lència
Docker Hub és el registre públic més gran d'imatges Docker. És com GitHub però per imatges Docker. Conté milers d'imatges oficials i milions d'imatges creades per la comunitat. Quan executeu docker pull nginx, Docker automàticament el busca a Docker Hub.
Docker Hub ofereix comptes gratuïts que us permeten tenir un repositori privat i repositoris públics il·limitats. Això és perfecte per aprenentatge i projectes personals. Per a ús professional, Docker Hub ofereix plans de pagament amb més repositoris privats i funcionalitats addicionals.
Pujant imatges a Docker Hub
Per pujar la vostra pròpia imatge a Docker Hub, primer necessiteu crear un compte a https://hub.docker.com. Un cop tingueu el compte, heu de fer login des de la línia de comandes:
Això us demanarà el vostre nom d'usuari i contrasenya. Un cop autenticats, podeu pujar imatges. Però primer, les imatges necessiten tenir el format correcte de nom: usuari/nom-imatge:etiqueta.
Si la vostra imatge es diu la-meva-app:1.0 i el vostre usuari és joanserra, heu de retaggejar la imatge:
Ara podeu pujar-la:
Veureu com Docker puja cada capa de la imatge. Si algunes capes ja existeixen a Docker Hub (perquè es comparteixen amb altres imatges), no cal tornar-les a pujar, fent que el procés sigui molt més ràpid.
Un cop pujada, qualsevol persona (si és pública) o qualsevol membre del vostre equip (si és privada) pot descarregar i utilitzar la imatge:
Registres privats: quan necessiteu més control
Per a empreses i projectes que necessiten més control, privacitat, o que volen allotjar les imatges als seus propis servidors, hi ha alternatives a Docker Hub. Podeu muntar el vostre propi registre privat utilitzant Docker Registry, que és una aplicació de codi obert proporcionada per Docker:
Això arrenca un registre local al port 5000. Ara podeu pujar imatges a aquest registre:
docker tag la-meva-app:1.0 localhost:5000/la-meva-app:1.0
docker push localhost:5000/la-meva-app:1.0
Hi ha també alternatives comercials com Amazon ECR (Elastic Container Registry), Google Container Registry, Azure Container Registry, o GitLab Container Registry, que ofereixen integració amb les seves respectives plataformes de núvol.
Depuració i solució de problemes
Inevitablement, us trobareu amb situacions on alguna cosa no funciona com esperàveu. Docker proporciona diverses eines per depurar i entendre què està passant.
Consultant logs
La primera eina de depuració són els logs. Per veure els logs d'un contenidor:
Això mostra tot el que l'aplicació ha escrit a stdout i stderr. L'opció -f segueix els logs en temps real:
Si només voleu veure les últimes línies:
Entrant dins d'un contenidor
De vegades necessiteu "entrar" dins d'un contenidor per inspeccionar-lo. Utilitzeu docker exec per executar comandes dins d'un contenidor en execució:
Això us dona una shell interactiva dins del contenidor. L'opció -it combina -i (interactiu) i -t (terminal). Si la imatge està basada en Alpine, probablement haureu d'utilitzar /bin/sh en lloc de /bin/bash perquè Alpine no inclou bash per defecte.
Un cop dins, podeu executar qualsevol comanda: ls, ps, cat, etc. Això és molt útil per verificar que els fitxers estan on haurien d'estar, comprovar variables d'entorn, o executar comandes de depuració.
Per sortir del contenidor, simplement escriviu exit.
Inspeccionant contenidors i imatges
La comanda docker inspect us dona informació detallada sobre gairebé qualsevol cosa de Docker:
Això retorna un JSON enorme amb tota la informació sobre el contenidor: la seva configuració, xarxa, volums, variables d'entorn, etc. És massa informació per llegir d'un cop, però podeu filtrar-la:
També podeu usar el format de plantilla per extreure informació específica:
Problemes comuns i les seves solucions
Un problema molt comú és "No puc connectar-me al meu contenidor". Normalment això passa perquè heu oblidat mapegar els ports. Recordeu que un contenidor té la seva pròpia xarxa aïllada. Si l'aplicació escolta al port 80 dins del contenidor, però no heu fet -p 8080:80, no hi podreu accedir des de fora.
Un altre problema freqüent és "El meu contenidor es reinicia constantment". Això normalment vol dir que el procés principal del contenidor està fallant. Consulteu els logs amb docker logs per veure què està passant. Potser falta una variable d'entorn, o el proces s'està executant i acabant immediatament perquè no té res a fer.
"El meu volum està buit o no té les dades que esperava" sol passar per problemes de permisos o rutes incorrectes. Utilitzeu docker inspect per verificar on està muntat exactament el volum, i comproveu que la ruta dins del contenidor coincideix amb la que esperàveu.
Finalment, "Docker diu que el port ja està en ús". Això vol dir que ja teniu alguna cosa (potser un altre contenidor, o una aplicació del vostre sistema) utilitzant el port que intenteu mapegar. Podeu utilitzar un port diferent, o aturar l'altra aplicació/contenidor que està utilitzant el port.