Módulo 1: Fundamentos de Docker

QUÉ VAMOS A CONSTRUIR

  • Entender qué problema resuelve Docker frente a instalar dependencias a mano
  • Distinguir contenedores de máquinas virtuales con criterio técnico, no de memoria
  • Mapear los conceptos clave: Engine, cliente, daemon, imágenes, registros y Docker Hub
  • Un contenedor de Nginx corriendo, con su puerto publicado y accesible desde el navegador

Antes de este módulo ya sabes instalar Docker y arrancar tu primer contenedor a ciegas. Toca entender qué está pasando realmente por debajo, porque sin esto el día que algo falle vas a estar a oscuras.

#Qué problema resuelve Docker

El problema de siempre es el «funciona en mi máquina pero no en el servidor»: diferencias de versiones de librerías, dependencias del sistema operativo, configuraciones que nadie documentó. Docker empaqueta tu aplicación junto con todo lo que necesita para correr (librerías, binarios, configuración) en una unidad portable que se comporta igual en tu portátil, en un servidor de producción o en la nube.

#Contenedores frente a máquinas virtuales

La confusión más habitual es pensar que un contenedor es «una VM más ligerita». No lo es: una VM virtualiza hardware completo con su propio kernel, mientras que un contenedor es un proceso aislado que comparte el kernel del sistema host.

Aspecto Máquina Virtual Contenedor Docker
Capa de virtualización Hipervisor (VMware, Hyper-V) Docker Engine sobre el kernel del host
Sistema operativo Kernel propio, completo Comparte el kernel del host
Tamaño típico Varios GB MB o pocos GB
Tiempo de arranque Decenas de segundos o minutos Segundos o milisegundos
Aislamiento Completo, a nivel de hardware A nivel de proceso, algo menor
Densidad por host Pocas VMs por máquina Cientos de contenedores por máquina

NOTA TÉCNICA

El hecho de compartir kernel es también la principal debilidad de seguridad de los contenedores frente a las VMs: una vulnerabilidad grave en el kernel del host puede en teoría afectar a todos los contenedores que corren sobre él.

#Conceptos esenciales

  • Docker Engine: el motor completo, compuesto por daemon, API REST y cliente CLI
  • Cliente (docker): el comando que escribes en terminal, habla con el daemon vía API
  • Daemon (dockerd): el proceso en background que realmente crea, ejecuta y gestiona contenedores
  • Imagen: plantilla de solo lectura con el sistema de archivos y la configuración de una aplicación
  • Contenedor: una instancia en ejecución de una imagen, con su propia capa de escritura encima
  • Registro (registry): servidor donde se almacenan y distribuyen imágenes
  • Docker Hub: el registro público oficial, donde vive la imagen nginx que vamos a usar en la práctica

#Ciclo de vida de un contenedor

Cuando ejecutas docker run, en realidad estás encadenando dos operaciones internas: primero se crea el «esqueleto» del contenedor a partir de la imagen (estado created), y después se arranca el proceso principal dentro de él (estado running).

bash
docker pull nginx
docker create --name mi-nginx -p 8080:80 nginx
docker start mi-nginx
docker ps
docker pause mi-nginx
docker unpause mi-nginx
docker stop mi-nginx
docker rm mi-nginx

Qué hemos hecho: descargamos la imagen (pull), creamos el contenedor sin arrancarlo (created), lo arrancamos (running), lo pausamos y reanudamos (pausedrunning), lo detenemos (exited) y finalmente lo eliminamos, desapareciendo de la lista de contenedores por completo.

#Qué se conserva y qué se pierde al borrar un contenedor

¡CUIDADO!

Al ejecutar docker rm, todo lo que el contenedor escribió en su capa de escritura interna se pierde para siempre: logs, archivos temporales, cambios de configuración hechos «a mano» dentro del contenedor. Solo sobrevive lo que hayas guardado en un volumen o en un bind mount explícito.
  • Se pierde: capa de escritura del contenedor (cualquier archivo modificado o creado dentro sin usar volúmenes)
  • Se conserva: la imagen original (sigue en tu disco, intacta, lista para crear otro contenedor nuevo)
  • Se conserva: los volúmenes nombrados y bind mounts, que viven fuera del contenedor

#Práctica: ejecutar Nginx, publicar un puerto y entrar desde el navegador

bash
docker run -d --name mi-web -p 8080:80 nginx
docker ps
curl http://localhost:8080

Contexto: ejecutado en tu máquina local, donde tienes Docker instalado. Qué hemos hecho: -d lo arranca en segundo plano (detached), -p 8080:80 mapea el puerto 80 del contenedor (donde Nginx escucha por defecto) al puerto 8080 de tu máquina host, y el curl valida por terminal que responde antes de ir al navegador.

Validación en navegador: abre http://localhost:8080 y deberías ver la página de bienvenida por defecto de Nginx («Welcome to nginx!»).

#Troubleshooting Frecuente

PROBLEMA COMÚN

Error «port is already allocated»: significa que otro proceso o contenedor ya usa el puerto 8080 en tu host. Cambia el mapeo a otro puerto libre, por ejemplo -p 8081:80, o localiza y detén el proceso ocupante con sudo lsof -i :8080.

PROBLEMA COMÚN

El navegador no carga nada aunque docker ps muestra el contenedor «Up»: revisa que el mapeo de puertos sea host:contenedor y no al revés, y confirma con docker port mi-web qué puerto exacto está expuesto.

#Plan de Rollback / Limpieza

bash
docker stop mi-web
docker rm mi-web
docker rmi nginx

Qué hemos hecho: detenemos y eliminamos el contenedor de prueba, y borramos también la imagen local si no piensas volver a usarla de inmediato.

El siguiente paso lógico es meterte con el Dockerfile: en lugar de usar la imagen genérica de Nginx, vas a construir tu propia imagen personalizada partiendo de la estructura de carpetas que ya montaste en el módulo anterior.

#Hoja de trucos

xml

Tarea Comando Clandestino / Ruta
Ver contenedores en ejecución docker ps
Ver todos, incluso detenidos docker ps -a
Ver puertos publicados de un contenedor docker port mi-web
Entrar a un contenedor corriendo docker exec -it mi-web bash
Limpiar todo lo parado de golpe docker system prune