La famosa frase "en mi máquina funciona" ha pasado de ser una excusa común a un problema del pasado gracias a la adopción de contenedores. Docker permite empaquetar una aplicación con todo su entorno —librerías del sistema, binarios, archivos de configuración y dependencias— garantizando que el software se ejecute de forma idéntica en local, en el servidor de staging y en producción.

Diferencias: Contenedores vs. Máquinas Virtuales

A diferencia de las máquinas virtuales (VM), que requieren un sistema operativo completo y un hipervisor que consume recursos masivos, los contenedores son extremadamente ligeros. Mientras que una VM puede necesitar varios gigabytes de RAM antes de iniciar la app, un contenedor comparte el núcleo (kernel) del sistema operativo anfitrión.

Mediante el uso de espacios de nombres (namespaces) y grupos de control (cgroups) de Linux, Docker aísla los procesos y el sistema de archivos de forma eficiente. Esto se traduce en tiempos de arranque de milisegundos y una densidad de aplicaciones mucho mayor en el mismo hardware.

Conceptos Fundamentales que Debes Conocer

  • Imagen: Es una plantilla de solo lectura que contiene las instrucciones para crear un contenedor. Imagínala como una "clase" en programación orientada a objetos.
  • Contenedor: Es la instancia ejecutable de una imagen. Puedes crear, iniciar, detener o eliminar contenedores fácilmente sin alterar la imagen base.
  • Dockerfile: Un archivo de texto plano donde defines paso a paso cómo se debe construir tu imagen personalizada.
  • Registry (Registro): Un almacén centralizado de imágenes. Docker Hub es el registro público más popular, similar a lo que GitHub es para el código fuente.

Cómo Escribir un Dockerfile Eficiente

Dockerfile para Node.js
# Imagen base oficial de Node.js (versión ligera)
FROM node:20-alpine

# Directorio de trabajo dentro del contenedor
WORKDIR /usr/src/app

# Copiamos los archivos de dependencias primero para optimizar el cache
COPY package*.json ./

# Instalación de dependencias de producción
RUN npm ci --only=production

# Copiamos el resto del código fuente
COPY . .

# Puerto que expone la aplicación
EXPOSE 3000

# Comando para ejecutar el servidor
CMD ["node", "app.js"]

Comandos Esenciales de Docker CLI

Comandos Más Utilizados
# Construir una imagen a partir de un Dockerfile
docker build -t mi-app-web:v1 .

# Ejecutar un contenedor en segundo plano vinculando puertos
docker run -d -p 8080:3000 --name mi-contenedor mi-app-web:v1

# Listar todos los contenedores activos
docker ps

# Ver logs en tiempo real de una aplicación
docker logs -f mi-contenedor

# Detener y eliminar un contenedor
docker stop mi-contenedor && docker rm mi-contenedor

# Limpiar imágenes que no se están usando
docker image prune -a

Orquestación con Docker Compose

En el desarrollo web moderno, una aplicación rara vez vive sola. Suele depender de una base de datos, un servidor de caché y otros servicios. Docker Compose permite definir y gestionar todo este ecosistema multicontenedor mediante un único archivo YAML.

docker-compose.yml
version: "3.9"
services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DB_HOST=postgres
    depends_on:
      - postgres

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: mi_password_seguro
    volumes:
      - datos_db:/var/lib/postgresql/data

  redis:
    image: redis:alpine

volumes:
  datos_db:
Comandos de Docker Compose
# Levantar todos los servicios definidos
docker compose up -d

# Detener y borrar contenedores, redes y volúmenes
docker compose down

# Reconstruir imágenes tras cambios en el código
docker compose up --build -d

Buenas Prácticas para Entornos de Producción

  • Builds Multietapa (Multi-stage): Separa el entorno de compilación del entorno de ejecución para reducir el tamaño final de la imagen.
  • Uso de .dockerignore: Evita subir archivos innecesarios como node_modules o carpetas .git al contexto de construcción.
  • Versiones Específicas: Nunca uses la etiqueta latest. Define versiones exactas (ej. node:20.11-alpine) para garantizar la consistencia.
  • Seguridad de Usuario: Por defecto, los procesos corren como root. Configura un usuario sin privilegios dentro del contenedor.
  • Variables de Entorno: No incluyas credenciales en el Dockerfile; utiliza archivos .env o gestores de secretos de tu proveedor cloud.

Optimiza tu Desarrollo con Nuestras Herramientas

Minifica, formatea y valida tu código al instante de forma totalmente gratuita.