Instalación
Un motor en marcha y los comandos que de verdad importan.
Instalación y primeros pasos
Instalar Docker lleva cinco minutos si se sigue el procedimiento correcto, y una tarde entera si se sigue el equivocado. La trampa más habitual: el paquete docker.io o docker que ofrece el gestor de paquetes de tu distribución. Existe, se instala, funciona más o menos… y suele ir varias versiones mayores por detrás, a veces sin el plugin de Compose, lo que te hará buscar durante veinte minutos por qué un comando de la documentación oficial «no existe» en tu máquina.
La segunda trampa está en otro sitio, y casi todo el mundo cae en ella una vez: tras una instalación perfectamente correcta, el primer comando responde permission denied while trying to connect to the Docker daemon socket. No es un fallo de instalación. Es una consecuencia directa de la arquitectura vista en la lección anterior —el cliente habla con un daemon privilegiado a través de un socket— y se resuelve con una sola línea, siempre que entiendas cuál y por qué.
Esta lección te ayuda a superar ambos obstáculos según tu sistema y después se centra en lo que realmente importa: una decena de comandos que cubren el 90 % del trabajo diario. No una lista exhaustiva de opciones —para eso está la documentación—, sino el pequeño conjunto que teclearás cada día, con lo que ocurre detrás de cada uno.
Al terminar, sabrás iniciar un contenedor, entrar en él, leer sus registros, entender por qué se ha detenido y recuperar las decenas de gigabytes que Docker habrá acumulado discretamente en tu disco.
Instalar Docker Engine en Linux
En Linux, Docker funciona de forma nativa: sin máquina virtual intermedia ni capa de traducción. Es el entorno más sencillo y el de mayor rendimiento. El método recomendado pasa por el repositorio oficial de Docker, que garantiza las actualizaciones y la presencia de los plugins modernos.
En Debian y Ubuntu:
# 1. Retirer les paquets anciens ou concurrents, s'ils sont presents
for p in docker.io docker-doc docker-compose podman-docker containerd runc; do
sudo apt-get remove -y "$p"
done
# 2. Ajouter la cle GPG officielle de Docker
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# 3. Declarer le depot (le nom de code de la distribution est detecte)
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 4. Installer le moteur ET les plugins (buildx, compose)
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
Los dos últimos paquetes son los que se suelen olvidar, y son los que proporcionan docker buildx y docker compose. En Debian, sustituye las dos apariciones de ubuntu por debian en las URL. Para Fedora o RHEL, el procedimiento equivalente utiliza dnf y el repositorio docker-ce.repo; está detallado en docs.docker.com/engine/install.
Queda asegurarse de que el daemon arranque, ahora y en cada reinicio de la máquina:
# --now demarre le service, enable l'active au demarrage
sudo systemctl enable --now docker
# Verifier son etat
systemctl status docker --no-pager
Existe una alternativa para un equipo desechable o una máquina de pruebas: el script de instalación oficial.
curl -fsSL https://get.docker.com -o get-docker.sh
# Toujours lire un script avant de l'executer en root
less get-docker.sh
sudo sh get-docker.sh
Es práctico, pero Docker desaconseja expresamente su uso en producción: adivina tu distribución y toma decisiones por ti, algo que no queremos en un servidor que debe poder reconstruirse de forma idéntica.
«permission denied»: el grupo docker
Este es el error que espera a todo el mundo en el primer comando:
permission denied while trying to connect to the Docker daemon socket
at unix:///var/run/docker.sock
El daemon escucha en un socket UNIX, /var/run/docker.sock, cuyo propietario es root y cuyo grupo es docker. Tu usuario solo pertenece a ese grupo si lo has añadido a él.
# Le groupe existe deja apres l'installation ; la commande est idempotente
sudo groupadd -f docker
# Ajouter votre utilisateur (-a = append, indispensable :
# sans lui, usermod REMPLACE la liste des groupes)
sudo usermod -aG docker "$USER"
# L'appartenance a un groupe est lue a l'ouverture de session.
# Ouvrez une nouvelle session, ou forcez-la pour le shell courant :
newgrp docker
# Verifier
id -nG | tr ' ' '\n' | grep docker
docker run --rm hello-world
Olvidar el -a en usermod -aG es un error que sale caro: elimina al usuario de todos sus demás grupos, incluido sudo.
Conviene saber qué autoriza realmente esta operación. El daemon se ejecuta como root, y la API que expone permite, entre otras cosas, montar cualquier carpeta del host en un contenedor. Pertenecer al grupo docker equivale, por tanto, a tener acceso de superusuario a la máquina. Es aceptable en tu equipo de trabajo; en un servidor compartido, merece una decisión consciente. Para los casos en los que esta elevación de privilegios es inaceptable, Docker ofrece un modo rootless que ejecuta el daemon bajo tu propia cuenta.
macOS y Windows: el rodeo por una máquina virtual
Recordatorio de la lección 1: una imagen Linux exige un kernel Linux. Ni macOS ni Windows lo proporcionan. En estos sistemas, Docker Desktop instala y gestiona por ti una pequeña VM Linux; el cliente docker de tu terminal habla con el daemon que se ejecuta dentro. Todo funciona de forma transparente, pero hay dos consecuencias que se dejan notar con regularidad: las operaciones de entrada/salida sobre los archivos compartidos con el host son más lentas, y la memoria asignada a la VM es un límite global.
En macOS, la instalación se hace con el paquete .dmg descargado desde docs.docker.com/desktop/install/mac-install, o con Homebrew:
brew install --cask docker
# Puis lancer l'application Docker une premiere fois : c'est elle
# qui installe le daemon et demarre la VM.
docker version
Ojo con la arquitectura: en los Mac con Apple Silicon (M1 y posteriores), el procesador es arm64. Una imagen publicada únicamente para amd64 se emulará, con lentitud, o se negará a arrancar. Si es necesario, se fuerza la arquitectura:
# Voir l'architecture du daemon
docker info --format '{{.Architecture}}'
# Forcer une plateforme, au prix de l'emulation
docker run --rm --platform linux/amd64 alpine:3.20 uname -m
En Windows, la configuración correcta es WSL2 (Windows Subsystem for Linux versión 2), que proporciona un auténtico kernel Linux. El antiguo modo «Hyper-V» de Docker Desktop conviene evitarlo, y el modo «contenedores Windows» responde a una necesidad distinta (imágenes de Windows Server).
# Dans PowerShell en administrateur : installe WSL2 et une Ubuntu par defaut
wsl --install
# S'assurer que la version 2 est celle utilisee par defaut
wsl --set-default-version 2
# Verifier : la colonne VERSION doit afficher 2
wsl -l -v
A continuación, instala Docker Desktop y activa en sus ajustes, en Settings > Resources > WSL Integration, la distribución que utilices. Así podrás escribir tus comandos docker directamente desde el shell de Ubuntu.
Un consejo de rendimiento que lo cambia todo en Windows: trabaja dentro del sistema de archivos de Linux, es decir, bajo /home/tu-usuario/proyectos, y no bajo /mnt/c/Users/.... Los archivos montados desde el disco de Windows atraviesan una capa de traducción; un npm install puede ser diez veces más lento allí.
Comprobar que la instalación es correcta
Bastan tres comandos, y cada uno responde a una pregunta distinta.
# 1. Le client et le daemon se parlent-ils, et en quelle version ?
# Si la section "Server" manque, le daemon est injoignable.
docker version
# 2. Etat detaille : pilote de stockage, nombre de conteneurs, memoire
docker info
# 3. Le chemin complet fonctionne-t-il : pull depuis un registre + execution
docker run --rm hello-world
El tercero es la verdadera prueba de extremo a extremo: valida la resolución DNS, el acceso al registro, la escritura en la caché local y la creación de un contenedor. El --rm elimina el contenedor en cuanto termina: un reflejo que conviene adquirir para cualquier contenedor desechable, pues de lo contrario se acumulan.
Anatomía de docker run
docker run es el comando más utilizado y el más denso. En realidad encadena tres operaciones: descargar la imagen si no está, crear un contenedor y arrancarlo.
docker run [OPTIONS] IMAGE [COMMANDE] [ARGUMENTS...]
El orden no es negociable: lo que precede al nombre de la imagen configura Docker, y lo que lo sigue se pasa al proceso del contenedor. Colocar -p 8080:80 después del nombre de la imagen no produce un error de sintaxis: pasa -p 8080:80 como argumento al programa lanzado, que se queda desconcertado.
Las opciones que importan, con lo que hacen de verdad:
docker run \
-d \ # detache : rend le terminal, le conteneur tourne en fond
--name api \ # nom stable, sinon Docker en invente un aleatoire
-p 8080:80 \ # publie le port : 8080 sur l'hote -> 80 dans le conteneur
-e LOG_LEVEL=debug \ # variable d'environnement
-v mes-donnees:/data \ # volume nomme monte sur /data
-w /app \ # repertoire de travail initial
--restart unless-stopped \ # relance apres un crash ou un reboot de l'hote
--memory 512m \ # plafond memoire (cgroups)
nginx:1.27-alpine
Hay dos modos contrapuestos que responden a necesidades distintas. -d desacopla: es el modo de los servicios. -it combina -i (mantener abierta la entrada estándar) y -t (asignar un pseudoterminal): es el modo de las sesiones interactivas.
# Une session shell jetable dans une Alpine, supprimee a la sortie
docker run --rm -it alpine:3.20 sh
# Un shell Python temporaire, sans installer Python sur l'hote
docker run --rm -it python:3.12-slim python
# Remplacer la commande par defaut de l'image
docker run --rm nginx:1.27-alpine nginx -v
Esta última línea ilustra una idea que conviene recordar: el comando declarado en la imagen no es más que un valor por defecto, que se puede sustituir al lanzar el contenedor.
El ciclo de vida de un contenedor
Un contenedor pasa por distintos estados, y muchas confusiones vienen de leer demasiado deprisa la salida de docker ps.
docker create
(image) ─────────────────────> created
│ docker start
v
docker stop / le processus finit
exited <─────────────────────── running <──> paused
│ │ (pause/unpause)
│ docker start │ docker restart
│ v
└──> docker rm ──> (disparu) running
# Ne montre QUE les conteneurs en cours d'execution
docker ps
# -a montre aussi les conteneurs arretes. C'est la commande a reflexe
# quand "mon conteneur a disparu" : il est la, en statut Exited.
docker ps -a
# Format personnalise, bien plus lisible que la sortie par defaut
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
El punto poco intuitivo: un contenedor vive tanto como su proceso principal (PID 1). No «contiene» una máquina encendida a la espera. Si su proceso termina, el contenedor pasa a Exited de inmediato.
# Ce conteneur s'arrete instantanement : echo finit son travail.
docker run --name test-court alpine:3.20 echo "bonjour"
docker ps -a --filter name=test-court # Exited (0)
# Celui-la tourne 30 secondes puis sort.
docker run -d --name test-sleep alpine:3.20 sleep 30
Esto explica el malentendido clásico de «mi contenedor se detiene solo»: la imagen no lanza ningún servicio duradero, o el servicio se pone en segundo plano y devuelve el control, algo que nunca debe hacerse dentro de un contenedor.
Los comandos de control:
docker stop api # SIGTERM, puis SIGKILL apres 10 s de grace
docker stop -t 30 api # allonger le delai de grace a 30 s
docker kill api # SIGKILL immediat, aucune chance de finir proprement
docker start api # redemarre un conteneur existant (etat disque conserve)
docker restart api
docker rm api # supprime le conteneur arrete, et sa couche d'ecriture
docker rm -f api # arrete et supprime d'un coup
La diferencia entre stop y kill no es cosmética. stop envía SIGTERM, lo que deja a la aplicación tiempo para cerrar sus conexiones y vaciar sus búferes; kill corta en seco, con el riesgo de corromper datos que se estén escribiendo. Una aplicación contenerizada correctamente diseñada debe interceptar SIGTERM.
Entrar en un contenedor y observarlo
Cuando un servicio no responde, el instinto es mirar dentro. Tres herramientas, en este orden.
Primero los registros, porque la mayoría de las veces bastan. Docker captura la salida estándar y la salida de error del proceso principal.
docker logs api # tout depuis le demarrage
docker logs -f api # suivre en direct (comme tail -f)
docker logs --tail 50 api # les 50 dernieres lignes
docker logs --since 10m api # les 10 dernieres minutes
docker logs --timestamps api # avec horodatage
Corolario fundamental: una aplicación contenerizada debe escribir sus registros en la salida estándar, no en un archivo interno. De lo contrario, docker logs aparecerá vacío y sus registros morirán con el contenedor.
Después, abrir un shell en un contenedor en ejecución:
# bash quand l'image en dispose (Debian, Ubuntu)
docker exec -it api bash
# sh sur les images Alpine et les images minimales : bash n'y est pas
docker exec -it api sh
# Executer une commande unique sans session interactive
docker exec api ls -la /etc/nginx
docker exec api env
Fíjate bien en la distinción: docker exec añade un proceso a un contenedor que ya se está ejecutando, mientras que docker run crea uno nuevo. Y todo lo que modifiques durante esa sesión vive en la capa de escritura del contenedor: se perderá al eliminarlo. Este modo sirve para diagnosticar, nunca para configurar de forma duradera.
Por último, la inspección y las mediciones:
# Toda la configuración del contenedor, en JSON
docker inspect api
# Apuntar a un valor concreto con una plantilla de Go
docker inspect --format '{{.State.Status}}' api
docker inspect --format '{{.State.ExitCode}}' api
docker inspect --format '{{range $p, $c := .NetworkSettings.Ports}}{{$p}} {{end}}' api
# Consumo en directo (CPU, memoria, red, E/S)
docker stats
# Procesos que se ejecutan en el contenedor
docker top api
# Archivos modificados respecto a la imagen (A añadido, C cambiado, D eliminado)
docker diff api
# Copiar un archivo en ambos sentidos
docker cp api:/etc/nginx/nginx.conf ./nginx.conf
docker cp ./nginx.conf api:/etc/nginx/nginx.conf
El código de salida merece atención: 137 significa casi siempre que el proceso ha recibido un SIGKILL (128 + 9), a menudo porque ha superado su límite de memoria y el kernel lo ha matado. Es una información que ningún mensaje de error de la aplicación le dará.
Limpiar: Docker llena el disco en silencio
Cada imagen descargada, cada contenedor detenido, cada capa intermedia de build permanece en el disco. En un equipo de desarrollo con mucha actividad, esto supone muy pronto decenas de gigabytes.
# El balance: lo que ocupa Docker y lo que es recuperable
docker system df
# Detalle por objeto
docker system df -v
La limpieza se hace con grados de contundencia crecientes.
# 1. Los contenedores detenidos
docker container prune
# 2. Las imágenes sin nombre (las "dangling", <none>), producidas por los rebuilds
docker image prune
# 3. Los volúmenes que ningún contenedor utiliza
# ATENCIÓN: son sus datos. Compruébelo antes.
docker volume ls
docker volume prune
# 4. La caché de build, a menudo la partida más grande
docker builder prune
# 5. Todo de golpe, incluidas las imágenes no utilizadas
docker system prune -a
docker system prune -a es el comando que hay que conocer y manejar con prudencia: elimina todas las imágenes que ningún contenedor utiliza, incluidas aquellas que volverá a descargar mañana. Sin -a, se limita a los objetos realmente huérfanos.
Algunos encadenamientos prácticos, que conviene entender antes de pegarlos:
# Detener todos los contenedores en ejecución (-q solo devuelve los identificadores)
docker stop $(docker ps -q)
# Eliminar todos los contenedores, incluidos los que están en ejecución
docker rm -f $(docker ps -aq)
# Eliminar las imágenes de un repositorio determinado
docker images --filter reference='mon-app' -q | xargs -r docker rmi
Una observación para macOS y Windows: el espacio ocupado por la VM de Docker Desktop no siempre se devuelve al sistema anfitrión tras un prune. El archivo de disco de la VM mantiene el tamaño de su pico. Docker Desktop ofrece una acción de recuperación de espacio en sus ajustes.
Conclusiones
- En Linux, instale desde el repositorio oficial de Docker, nunca desde el paquete de la distribución, y no olvide
docker-buildx-pluginydocker-compose-plugin: sin ellos,docker composeno existe. - El error
permission denieden/var/run/docker.sockse resuelve consudo usermod -aG docker $USERseguido de una nueva sesión. Tenga en cuenta que esto equivale a un acceso root en la máquina. - En macOS y Windows, Docker se apoya en una VM Linux. En Windows, utilice WSL2 y guarde sus proyectos en el sistema de archivos de Linux, no en
/mnt/c, so pena de sufrir lentitud importante. - Un contenedor vive exactamente tanto como su proceso PID 1. «Se detiene solo» casi siempre significa que ese proceso ha terminado.
docker ps -amuestra los contenedores detenidos;docker ps, no. - El día a día cabe en ocho comandos:
run,ps -a,logs -f,exec -it,stop,rm,inspect,system df. Adquiera el reflejo de usar--rmpara cualquier contenedor desechable. - Vigile
docker system dfcon regularidad: las imágenes, los volúmenes y las cachés de build llenan un disco sin avisar.
Consejo: ejecute
docker run --rm -it alpine:3.20 shy explore con libertad. Un contenedor desechable es el entorno de experimentación más seguro que existe:exit, y no queda nada.
Comentarios
Los comentarios funcionan con GitHub Discussions
Inicia sesión con GitHub para participar en la discusión