Primeres passes amb Docker per a sysadmins
Treballar amb Docker no és difícil, però és fàcil fer-ho malament. Moltes de les guies estan escrites per a desenvolupadors o per a principiants, i si veniu del món de l’administració de sistemes, probablement ja saps lidiar amb serveis, processos, ports, xarxes, permisos, discos i backups. El que no saps encara —fins que et passa— és com aquestes peces es combinen en un entorn basat en contenidors.
1. Instal·lació: quina versió i des d’on
Instal·lar Docker amb apt install docker.io sembla el més directe. El problema és que aquest paquet no està mantingut per Docker Inc., no té les versions actualitzades al dia i de vegades ni tan sols és compatible amb algunes característiques recents. Si has de depurar un error, ningú et pot ajudar amb confiança si no estàs fent servir docker-ce.
Fes servir el repo oficial. A Debian/Ubuntu:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
echo "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io
A CentOS/RedHat:
yum install -y yum-utils
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
yum install docker-ce docker-ce-cli containerd.io
No barregis versions del client (docker) i del daemon (dockerd). He vist casos en què el client nou intenta fer servir flags o sintaxi que el daemon vell no entén, i l’única pista que tens és un error genèric. Si ho instal·les des del mateix repo oficial, això no passa.
2. Usuaris, permisos i el grup docker
Afegir usuaris al grup docker dóna accés total al socket de Docker. Això és equivalent a ser root. Molta gent ho fa perquè així es pot córrer docker sense sudo, però si el teu entorn requereix auditoria o segmentació de privilegis, ho has de tenir clar: algú al grup docker pot modificar el host a través de contenidors maliciosos o simplement mal dissenyats.
En ambients productius o multiusuari:
- No afegeixis usuaris al grup docker sense control.
- Considera executar Docker en mode rootless si l’aïllament ho requereix.
- Fes servir sistemes com sudo, RBAC, o directament apis sobre el socket protegides per un proxy amb autenticació.
3. Primer error comú: no entendre on es guarda tot
Docker guarda dades persistents a /var/lib/docker. Aquí van les capes d’imatges, els contenidors aturats, els logs, els volums… tot. Si tot això està al disc arrel i creix, tenim un problema.
Solució comuna: moure el data-root a un disc dedicat.
Passes:
- Aturar Docker:
systemctl stop docker
- Moure les dades:
rsync -aP /var/lib/docker/ /mnt/docker
- Configurar el nou path:
A /etc/docker/daemon.json:
{
"data-root": "/mnt/docker"
}
- Reiniciar Docker:
systemctl start docker
Sempre faig això al començament. Si ho fas quan ja tens contenidors en producció, has de validar que el rsync ha sigut complet, i si no t’adones d’algun bind mount a disc, el pots perdre.
4. Logs sense control = disc ple
Per defecte, Docker guarda els logs dels contenidors com a arxius JSON plans. No tenen rotació ni mida màxima. En servidors amb serveis verbose, això és un desastre anunciat.
Tenim tres opcions:
Opció 1 (mínim acceptable):Configurar la rotació a /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Opció 2:Enviar logs a syslog o journald, si teniu una solució d’agregació (com rsyslog, journalbeat, etc.).
Opció 3:Fer anar fluentd, gelf, o similars si teniu ELK, Graylog, o algun sistema centralitzat.
5. Xarxes: evitar el default bridge i saber quan fer servir host o macvlan
Quan crees un contenidor sense especificar xarxa, Docker el fica al bridge per defecte (bridge0). Aquest pont té NAT, IPs privades i DNS bàsic (resolt pel daemon). Funciona bé per a entorns simples, però té limitacions:
- No podeu exposar ports duplicats en el host sense fer servir random (-P o –publish-random).
- La resolució DNS entre contenidors és limitada.
- El trànsit és emmascarat, el que complica logs o firewalls externs.
Per a una cosa més organitzada:
Fes servir xarxes pròpies (user-defined bridge):
docker network create --driver bridge xarxa_interna
docker run --network xarxa_interna --name web nginx
Avantatges:
- Resolució de noms entre contenidors (ping web funciona).
- Aïllament parcial: no es barregen amb els del bridge per defecte.
- Podeu mapejar ports al host només quan ho necessites.
Quan serveix host:
- Quan necessites el rendiment màxim de la xarxa.
- Quan fas bind de serveis com snmpd, nginx o iptables directament al host.
Per exemple, un contenidor que monitoritza fent servir snmp no pot funcionar bé amb NAT; aquí –network host és el més directe.
Sobre macvlan:
Fes-ho servir si vols que el contenidor tingui la seva pròpia IP de LAN, com si fos una VM. Necessita configuració més detallada (subxarxa dedicada, gateway ben definit) i no funciona fàcilment amb Wi-Fi o ambients virtualitzats sense ajustos.
6. Volums: bind mount vs managed volumes i backups
Quan necessites persistència, tens dues opcions:
Bind mount:
docker run -v /dades/postgres:/var/lib/postgresql/data ...
Això enllaça el directori exacte del host al contenidor. És explícit, fàcil de veure i de donar suport, però:
- No és portable (ruta absoluta).
- Permisos inconsistents si l’ UID del procés en contenidor no existeix al host.
- El contenidor pot sobreescriure coses en el host per error o mal disseny.
Volums gestionats per Docker:
Docker Volume Crea PostgresData
docker run -v postgresdata:/var/lib/postgresql/data ...
Avantatges:
- Docker gestiona la ruta interna.
- Es pot inspeccionar (docker volume inspect).
- Són més fàcils de migrar entre hosts amb docker volume export + import.
Desavantatge: si no saps on són (/var/lib/docker/volumes/), no els estàs incloent en els backups.
Consell realista: En producció, és preferible bind mounts cap a un path ben controlat (ex. /srv/containers/…) que està muntat des d’un disc dedicat o LVM. Així és fàcil versionar, replicar, o fins i tot snapshotejar.
7. Límits de recursos: si no els poses, no existeixen
Els contenidors no tenen límits de CPU o RAM si no els configures. Això porta a incidents on un procés dins de Docker s’ emporta tota la RAM del host i mata a la resta.
Fes servir almenys:
docker run --memory=512m --cpus=1.0 ...
Tingues en compte:
- –memory limita RAM + Y, no només la RAM real.
- Si vols limitar només RAM real i evitar swap, fes servir –memory-swap=512m.
- –cpus s’ interpreta com a nuclis virtuals.
També pots fer servir cgroups v2 amb un control més fi, però aquí canvia la manera de definir els límits i requereix kernel modern i configuració específica (systemd.unified_cgroup_hierarchy=1 a GRUB).
8. Seguretat: els contenidors no són una presó màgica
Aquest és un dels errors més comuns que es veuen en entorns nous: pensar que el contenidor és un sandbox segur “perquè és Docker”.
No ho és.
Per defecte:
- El contenidor corre amb root, dins del namespace, però continua sent root del host si escapa.
- Pot accedir al kernel, a dispositius muntats si li dones, o a processos compartits si fas servir –pid=host.
- Té accés complet a la xarxa, llevat que el limitis.
Bones pràctiques mínimes:
- Fes servir imatges oficials, signades o auditades.
- Executa processos com a usuari no root a la imatge.
- Limita les capacitats amb –cap-drop=ALL i afegeix només les necessàries.
- Considera seccomp, AppArmor o SELinux si el teu entorn el suporta.
- No facis servir –privileged llevat que sàpigues exactament el que implica.
9. Desplegaments organitzats: docker-compose i beyond
No mantinguis docker run llargs en un .sh o en systemd. Fes servir docker-compose per a serveis que tenen més d’ un contenidor o depenen de configuració reproduïble.
Exemple bàsic:
version: '3.8'
services:
db:
image: postgres:14
restart: always
environment:
POSTGRES_PASSWORD: example
volumes:
- pgdata:/var/lib/postgresql/data
app:
image: miapp:latest
depends_on:
- db
ports:
- 8000:8000
volumes:
pgdata:
Avantatges reals:
- Els serveis s’ aixequen junts, en l’ ordre correcte.
- La configuració està en un sol lloc.
- Pots replicar entorns fàcilment.
Després pots migrar a docker stack o kubernetes, però per a servidors mitjans o entorns de staging, docker-compose continua sent més que suficient.
10. Backups i restauració
Docker no gestiona backups. Això continua sent tasca del sysadmin.
Estratègies típiques:
- Contenidors stateless (app) no requereixen backup.
- Volums i bind mounts han d’ estar en rutes incloses als backups del host.
- Si fas snapshots, fes-los en moments en què els serveis estiguin quiets o amb lògica de quiescing.
- No t’oblidis dels secrets i els arxius .env.
Exemple de suport de volum:
docker run --rm -v postgresdata:/data -v $(pwd):/backup alpine tar czf /backup/pgdata.tar.gz /data
11. Docker rootless: quan sí i quan no
Docker pot córrer sense privilegis de root des de la versió 20.10. La idea sona atractiva: evitar que una fallada en un contenidor escali a comprometre el host. Però a la pràctica hi ha matisos.
Avantatges clars:
- El daemon no té permisos de root sobre el sistema.
- Redueix l’ impacte d’ una fuita de contenidor.
- Útil en entorns multiusuari, on no vols que cadascú tingui privilegis sobretot el node.
Problemes pràctics:
- No pots mapejar ports <1024 (sense hacks com authbind o setcap).
- Algunes operacions amb volums (especialment bind mounts fora del home de l’usuari) fallen.
- El networking canvia: no fa servir iptables ni cgroups com el Docker rootful tradicional.
Quan és recomanable:
- En entorns on no pots confiar en l’usuari que corre el contenidor.
- En estacions de desenvolupament compartides.
- Per córrer pipelines o runners en entorns sense accés root (per política o limitacions del proveïdor).
S’ha d’evitar a:
- Producció amb necessitats de networking complexes o ús de dispositius.
- Contenidors que requereixen accés a recursos del host com /dev o hostPID.
12. Imatges més petites i reproduïbles
No facis servir latest. No facis servir ubuntu:latest. No facis servir node:latest. Si pots, no facis servir imatges base generalistes. Una imatge que pesa 1.5 GB perquè algú va instal·lar curl, git i vim en producció és una recepta per a mals de cap.
Regles que s’apliquen amb consistència:
- FROM alpine quan és viable. Si no, debian:bullseye-slim.
- Evita instal·lar eines que no facis en runtime (fa multi-stage builds).
- Les imatges de base han de tenir versions fixes i verificables (SHA256 o tag explícit).
Exemple de multistage:
FROM golang:1.20 AS build
WORKDIR /src
COPY . .
RUN go build -o app
FROM alpine
COPY --from=build /src/app /usr/local/bin/app
ENTRYPOINT ["/usr/local/bin/app"]
Això genera una imatge mínima, sense Go, sense compiladors, sense coses que puguin ser explotades.
Eines útils:
- dive: per a analitzar capes de la imatge.
- docker history i docker imatge inspect.
13. CI/CD: integració real amb Docker
Una pipeline bona no hauria d’instal·lar Docker en cada execució, ni reconstruir imatges si no canvia el contingut rellevant.
Exemple a GitLab CI:
image: docker:latest
services:
- docker:dind
variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_TLS_CERTDIR: ""
before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
build:
stage: build
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
Errors comuns:
- No deixar a la memòria cau docker build: el torna lent i inútil.
- No versionar imatges: genera bugs difícils de reproduir.
- No separar build i deploy: una pipeline mal separada pot pujar codi trencat.
Solució: separa etapes, fes servir tags explícits, i revisa les capes per a evitar invalidar la memòria cau innecessàriament.
14. docker stack: orquestració simple sense passar-se a Kubernetes
Per a molts entorns mitjans, docker stack és suficient. Funciona sobre docker swarm, però pots ignorar la majoria de les seves complexitats si el fas servir localment o en un petit clúster intern.
Què ofereix respecte a docker-compose?
- Deploys declaratius: docker stack deploy -c docker-compose.yml nombre_stack
- Escalat automàtic per nombre de rèpliques.
- Controls de salut integrats.
- Actualitzacions contínues amb control fino.
Exemple bàsic:
version: '3.9'
services:
web:
image: nginx
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
ports:
- "80:80"
Quan evitar-ho:
- Quan no vols fer servir swarmd, ni lidiar amb el seu mode de xarxa.
- Si ja estàs a Kubernetes o tens un operador que ho prefereix.
Per a entorns petits, és molt menys dolorós que ficar-se amb Helm o manifests complexos.
15. Gestió de secrets
Posar claus a .env està bé per a desenvolupament. Però en producció, necessites alguna cosa més seriosa.
Opcions viables:
- Docker Secrets (si fas servir docker swarm)
- Vault de HashiCorp (amb integració a CI/CD)
- Muntar tmpfs amb secrets a dins, que s’esborren en aturar el contenidor
Alternativa bàsica i funcional:
- Tenir un volum extern encriptat (LUKS o eCryptfs).
- Muntar-ho en iniciar el contenidor i fer que el contenidor llegeixi des d’aquí.
Exemple molt senzill:
docker run -v /secrets/app.env:/run/secrets/app.env --env-file /run/secrets/app.env ...
Consell: Mai fiquis .env o arxius amb claus a les imatges. Ni per accident.
16. Debug real: el que de veritat serveix
Quan alguna cosa es trenca en producció, el que necessites és poder entrar ràpid, veure què passa i sortir sense fer malbé res.
Eines que serveixen:
- docker exec -it <id> bash o sh
- docker logs –tail=100 -f <id>
- strace, si tens la sort que estigui instal·lat
- curl o nc dins del contenidor per testejar accessos sortints o interns
- docker events per a veure esdeveniments de baix nivell
Si tota la resta falla: muntar un contenidor amb –pid=host, –net=host, i fer-ho servir com a punt d’observació.
docker run -it --rm --pid=host --net=host --cap-add=SYS_PTRACE alpine sh
Aquí podeu córrer top, ps, ss, strace i veure què està passant a nivell del host des de dins de l’espai de noms del contenidor.
17. Registry privat: control i autonomia
Muntar el teu propi registre no és difícil i t’evita dependre de tercers per a producció.
Exemple ràpid:
docker run -d -p 5000:5000 --restart=always --name registry registry:2
Això et dona un registry local sense autenticació (perillós en xarxes compartides). Per a producció:
- Posa’l darrere d’un revers proxy (com un nginx amb HTTPS).
- Activa l’ autenticació bàsica.
- Signa les imatges (Docker Content Trust).
També pots:
- Escanejar imatges abans de permetre el seu push.
- Fer retenció automàtica (neteja de tags vells, etc.).
- Integrar-lo amb CI per a pushes automàtics des del teu entorn.
Conclusió
Docker simplifica coses que abans eren complexes, però no elimina els problemes d’arrel: els canvia de forma. La teva tasca continua sent garantir estabilitat, predicibilitat i traçabilitat. El que canvia és que ara el teu entorn pot ser més modular, portable i reproduïble. Però només si estan bé les bases.

