Qué es Docker y cómo empezar a usarlo en Linux (guía completa)
Si llevas un tiempo en el mundo de Linux habrás oído hablar de Docker en más de una ocasión. Quizás lo has visto en tutoriales, en ofertas de trabajo o en conversaciones técnicas, y te has preguntado qué es exactamente y por qué todo el mundo lo usa. En esta guía lo verás desde cero: qué problema resuelve Docker, cómo funciona por dentro y cómo instalar y ejecutar tu primer contenedor en Ubuntu.
El problema que resuelve Docker
Antes de entender Docker hay que entender el problema que existía sin él.
Imagina que desarrollas una aplicación en tu máquina con Python 3.11 y una serie de librerías instaladas. Funciona perfectamente. La subes al servidor de producción, que tiene Python 3.8 y diferentes versiones de esas librerías, y la aplicación falla. El clásico "en mi máquina funciona".
La solución tradicional eran las máquinas virtuales: crear un sistema operativo completo virtualizado con todo lo necesario. Funciona, pero tiene un coste enorme — una VM ocupa varios gigas, tarda minutos en arrancar y consume muchos recursos aunque la aplicación sea pequeña.
Docker resuelve esto con un enfoque diferente: los contenedores.
Contenedores vs máquinas virtuales
Un contenedor no virtualiza hardware ni instala un sistema operativo completo. En su lugar, comparte el kernel del sistema operativo anfitrión y solo empaqueta lo que la aplicación necesita: sus dependencias, librerías y configuración.
El resultado es que un contenedor:
- Arranca en segundos, no en minutos
- Ocupa megabytes, no gigabytes
- Es reproducible: el mismo contenedor funciona igual en tu portátil, en el servidor o en la nube
- Está aislado: lo que pasa dentro del contenedor no afecta al sistema anfitrión
La diferencia visual es clara:
Máquina Virtual: Contenedor Docker:
┌─────────────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ App │ │ App │ │ App │ │ App │
│ Librerías │ │ Libs │ │ Libs │ │ Libs │
│ SO Guest │ └──────┘ └──────┘ └──────┘
│ Hypervisor │ ──── Kernel compartido ────
│ SO Host │ │ SO Host │
└─────────────┘ └────────────────────────┘
Conceptos clave de Docker
Antes de instalar nada, conviene tener claros cuatro conceptos que aparecerán constantemente:
Imagen: una plantilla de solo lectura que define qué contiene el contenedor. Es como una fotografía del sistema con la aplicación y todo lo necesario para que funcione. Por ejemplo, existe una imagen oficial de Ubuntu, de Nginx, de PostgreSQL, etc.
Contenedor: una instancia en ejecución de una imagen. Puedes tener varios contenedores corriendo a partir de la misma imagen, cada uno aislado del resto.
Dockerfile: un fichero de texto con las instrucciones para construir una imagen personalizada. Si la imagen oficial de Ubuntu no es suficiente, defines en un Dockerfile qué instalar encima.
Docker Hub: el registro público de imágenes de Docker, como un "GitHub para imágenes". Tiene miles de imágenes oficiales y de la comunidad listas para usar.
Docker Compose: una herramienta para definir y gestionar múltiples contenedores a la vez mediante un fichero docker-compose.yml. La hemos usado en otras guías de este blog para desplegar Jellyfin, el stack Arr y OpenVPN.
Instalación de Docker en Ubuntu
Eliminar versiones antiguas
Si tienes alguna versión antigua de Docker instalada, elimínala primero:
sudo apt remove docker docker-engine docker.io containerd runc
Añadir el repositorio oficial
Instala las dependencias necesarias:
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
Añade la clave GPG de Docker:
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
Añade el repositorio:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Instalar Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Usar Docker sin sudo
Por defecto Docker requiere sudo. Para evitarlo, añade tu usuario al grupo docker:
sudo usermod -aG docker $USER
Cierra la sesión y vuelve a entrar para que el cambio surta efecto.
Verificar la instalación
docker --version
docker compose version
Tu primer contenedor
Con Docker instalado, vamos a ejecutar el primer contenedor. El más clásico para empezar es hello-world:
docker run hello-world
Lo que ocurre en segundo plano cuando ejecutas este comando:
- Docker busca la imagen
hello-worlden local — no la encuentra - La descarga automáticamente desde Docker Hub
- Crea un contenedor a partir de esa imagen
- Ejecuta el contenedor, que imprime un mensaje y termina
Verás un mensaje que empieza con "Hello from Docker!". Enhorabuena, acabas de ejecutar tu primer contenedor.
Comandos básicos que usarás siempre
Gestión de contenedores
# Listar contenedores en ejecución
docker ps
# Listar todos los contenedores (incluidos los parados)
docker ps -a
# Parar un contenedor
docker stop nombre_o_id
# Arrancar un contenedor parado
docker start nombre_o_id
# Eliminar un contenedor
docker rm nombre_o_id
# Ver los logs de un contenedor
docker logs nombre_o_id
# Seguir los logs en tiempo real
docker logs -f nombre_o_id
# Entrar dentro de un contenedor en ejecución
docker exec -it nombre_o_id bash
Gestión de imágenes
# Listar imágenes descargadas en local
docker images
# Descargar una imagen sin ejecutarla
docker pull ubuntu:22.04
# Eliminar una imagen
docker rmi nombre_imagen
# Eliminar imágenes sin usar
docker image prune
Limpieza general
Con el tiempo Docker acumula contenedores parados, imágenes sin usar y volúmenes huérfanos. Para limpiar todo de golpe:
docker system prune -a
Cuidado: este comando elimina todo lo que no esté en uso activo. No lo ejecutes en un servidor de producción sin saber qué tienes corriendo.
Un ejemplo práctico: servidor web con Nginx
Vamos a levantar un servidor web Nginx en un contenedor para ver cómo funciona en la práctica:
docker run -d -p 8080:80 --name mi-nginx nginx
Desglosando el comando:
-d— ejecuta el contenedor en segundo plano (detached)-p 8080:80— mapea el puerto 8080 de tu máquina al puerto 80 del contenedor--name mi-nginx— le da un nombre al contenedornginx— la imagen a usar (se descarga de Docker Hub si no está en local)
Abre el navegador en http://localhost:8080 y verás la página de bienvenida de Nginx. Un servidor web completo corriendo en segundos, sin instalar nada en tu sistema.
Para pararlo y eliminarlo:
docker stop mi-nginx
docker rm mi-nginx
Volúmenes: cómo persisten los datos
Por defecto, todo lo que ocurre dentro de un contenedor desaparece cuando lo eliminas. Para que los datos persistan, Docker usa volúmenes.
Hay dos formas de usarlos:
Bind mount — mapea una carpeta de tu sistema al contenedor:
docker run -d -p 8080:80 \
-v /home/rafa/web:/usr/share/nginx/html \
--name mi-nginx nginx
Ahora Nginx sirve los ficheros de /home/rafa/web. Cualquier cambio en esa carpeta se refleja inmediatamente en el contenedor.
Volumen gestionado por Docker — Docker gestiona dónde se almacena:
docker volume create mis-datos
docker run -d -v mis-datos:/datos ubuntu
Los bind mounts son más cómodos para desarrollo. Los volúmenes gestionados son más seguros para producción.
Variables de entorno
Muchas imágenes Docker se configuran mediante variables de entorno. Por ejemplo, para arrancar una base de datos PostgreSQL:
docker run -d \
--name mi-postgres \
-e POSTGRES_USER=rafa \
-e POSTGRES_PASSWORD=miclave \
-e POSTGRES_DB=mibase \
-p 5432:5432 \
postgres:15
El -e pasa variables de entorno al contenedor. Cada imagen oficial documenta en Docker Hub qué variables acepta.
De aquí a Docker Compose
Cuando tienes un solo contenedor, los comandos docker run son manejables. Pero cuando necesitas varios contenedores que se comunican entre sí — como una aplicación con base de datos, caché y servidor web — gestionar cada uno por separado se vuelve tedioso.
Ahí es donde entra Docker Compose: defines todos los contenedores, sus volúmenes, puertos y variables en un fichero docker-compose.yml y los gestionas con un solo comando.
En este blog tienes guías completas usando Docker Compose para casos reales:
- Jellyfin con Docker Compose en Ubuntu — servidor multimedia completo
- Stack Arr con Docker Compose — automatización de biblioteca multimedia
- OpenVPN-AS con Docker — tu propia VPN
Conclusión
Docker resuelve uno de los problemas más clásicos del desarrollo y las operaciones: que el software funcione igual en cualquier entorno. Con contenedores tienes aplicaciones aisladas, reproducibles y fáciles de gestionar, sin el coste de las máquinas virtuales.
Has visto los conceptos fundamentales, cómo instalarlo en Ubuntu y cómo trabajar con contenedores reales. A partir de aquí el siguiente paso natural es aprender Docker Compose para gestionar stacks de múltiples servicios, y después Dockerfile para construir tus propias imágenes personalizadas — pero eso da para sus propias guías.