¿Qué es Docker?
Docker es una plataforma de containerización que empaqueta tu aplicación junto con todas sus dependencias en una unidad llamada container. El resultado: tu app corre exactamente igual en la laptop de desarrollo, en el servidor de staging y en producción. Sin "en mi máquina funciona", sin diferencias de versión de Node.js, sin problemas de dependencias del sistema operativo.
Antes de Docker, la solución era documentar minuciosamente qué instalar y en qué orden, rezar para que la versión del servidor coincidiera con la de desarrollo, y dedicar días enteros a reproducir bugs que solo aparecían en producción. Docker eliminó ese problema de raíz.
Containers vs VMs.
Una máquina virtual (VM) emula hardware completo: tiene su propio kernel, sus propios drivers, y ocupa varios GB. Un container de Docker comparte el kernel del sistema operativo host y solo empaqueta la aplicación con sus dependencias a nivel de userspace. El resultado: containers que arrancan en milisegundos y usan MB en lugar de GB.
Podés correr decenas de containers en la misma máquina donde solo cabrían 2-3 VMs. Y cada container está aislado: si uno falla o es comprometido, los demás no se ven afectados. Es el equilibrio perfecto entre aislamiento y eficiencia.
Imágenes y Dockerfile.
Una imagen Docker es la plantilla de solo lectura desde la que se crean los containers. El Dockerfile es el script que define cómo construir esa imagen: qué imagen base usar, qué instalar, qué archivos copiar, cómo iniciar la aplicación. Una imagen bien construida es reproducible, versionada, y se puede compartir en Docker Hub o en un registry privado.
Para una app Node.js, el Dockerfile básico parte de node:20-alpine (imagen oficial de Node con Alpine Linux, muy liviana), instala las dependencias con npm ci, copia el código, y define el comando de inicio. El flag --production en el install y el uso de multi-stage builds pueden reducir el tamaño de la imagen final en un 60-70%.
- FROM — imagen base (node:20-alpine, python:3.12, nginx:alpine)
- WORKDIR — directorio de trabajo dentro del container
- COPY — copiar archivos del host al container
- RUN — ejecutar comandos durante el build
- EXPOSE — declarar el puerto que usa la app
- CMD — comando de inicio del container
Docker Compose.
Docker Compose permite definir y correr aplicaciones multi-container con un solo archivo YAML. En lugar de correr manualmente tu app, tu base de datos, tu cache de Redis y tu servidor de emails, definís todos los servicios en docker-compose.yml y los levantás con docker compose up. Un comando, toda la infraestructura lista.
El docker-compose.yml define los servicios, las redes entre ellos, los volúmenes para datos persistentes, y las variables de entorno. Las dependencias entre servicios se declaran con depends_on. Los volumes permiten que los datos de la base de datos sobrevivan reinicios del container. Es la solución perfecta para entornos de desarrollo.
docker compose up y tenés toda tu infraestructura local corriendo. No hay setup más reproducible que ese.
Para desarrollo local.
El mayor valor de Docker en desarrollo es la paridad con producción. Tu equipo usa el mismo ambiente sin importar si tienen Mac, Windows o Linux. Los onboardings de nuevos developers pasan de "sigue estas 40 instrucciones" a "clona el repo y corre docker compose up". El tiempo de setup baja de horas a minutos.
Para desarrollo activo, los volúmenes de Docker te permiten montar el código de tu máquina directamente en el container, así los cambios se reflejan sin necesidad de rebuild. Combinado con hot reload de frameworks como Next.js o Vite, la experiencia de desarrollo es igual de fluida que sin Docker.
Para deploys.
En producción, los containers de Docker son la base de Kubernetes, AWS ECS, Google Cloud Run y casi cualquier plataforma de deploy moderna. Tu imagen Docker es el artefacto deployable: la buildás en CI/CD, la subís al registry, y la plataforma la corre. El proceso es idéntico independientemente del servidor destino.
Errores comunes.
El error más común es no usar .dockerignore: incluir node_modules en el contexto de build lo hace lentísimo. El segundo error es correr containers como root por omisión: siempre creá un usuario sin privilegios. El tercero es guardar secretos en el Dockerfile o en variables de entorno hardcodeadas en la imagen: usá Docker secrets o variables inyectadas en runtime.