Qué es Docker y por qué cambió DevOps para siempre
Contenedores, imágenes, capas y por qué Docker se convirtió en el estándar de facto para empaquetar y desplegar software desde 2013.
El problema que Docker vino a resolver
Antes de 2013, desplegar una aplicación consistía en pelearse con "en mi máquina funciona". Cada servidor tenía versiones distintas de Python, glibc, OpenSSL. Los scripts de deploy incluían decenas de apt-get install y rezos. Las VMs virtualizaban el hardware completo: gigabytes de disco por instancia, minutos para arrancar.
Docker cambió el modelo: empaqueta tu aplicación con todas sus dependencias en una imagen inmutable y ejecútala en un contenedor: un proceso aislado del host mediante namespaces y cgroups del kernel Linux. Lo que corre en tu portátil corre bit a bit igual en producción.
Imagen, contenedor, capa: el vocabulario básico
- Imagen: plantilla inmutable, definida en un
Dockerfile. Contiene tu app, sus dependencias y un mini sistema operativo (raramente el kernel; los contenedores comparten el del host). - Contenedor: instancia ejecutándose de una imagen. Es un proceso aislado con su propio filesystem, red y árbol de procesos.
- Capa: cada instrucción del Dockerfile (
RUN,COPY,ADD) crea una capa. Docker las cachea por hash: si no cambia el contexto, reutiliza la capa.
Este modelo de capas es lo que hace que un rebuild típico dure segundos en vez de minutos.
El Dockerfile mínimo y por qué cada línea importa
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
USER 1001
EXPOSE 3000
CMD ["node", "server.js"]
FROM node:20-alpine— base ligera (~180 MB) con Node 20 fijado. Nunca usesnode:latest: rompe builds cuando cambia la mayor.WORKDIR /app— todos los comandos posteriores parten de aquí.COPY package*.json ./— copiamos primero solo los manifiestos.RUN npm ci— instala dependencias. Al copiar antes solo lospackage*.json, esta capa se cachea salvo que cambien las dependencias. Este es el truco de cache más importante en Node.COPY . .— ahora sí el código fuente.USER 1001— corremos como usuario no privilegiado.CMD— comando de arranque.
Este patrón se aplica igual en Python (requirements.txt primero), Go (go.mod y go.sum), Rust (Cargo.toml), etc.
Multi-stage build: pasar de 1.2 GB a 80 MB
La técnica más impactante para reducir tamaño y superficie de ataque. Ejemplo con Go:
# Fase 1: build
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /app ./cmd/server
# Fase 2: runtime
FROM gcr.io/distroless/static
COPY --from=builder /app /app
USER nonroot
CMD ["/app"]
La imagen final pesa ~15 MB, contiene solo el binario y una raíz mínima. Sin shell, sin package manager, sin nada que un atacante pueda usar tras un compromiso.
Nuestro generador de Dockerfile aplica todos estos patrones por defecto.
Docker Compose: el paso siguiente
Una app real rara vez es un solo contenedor. Necesita base de datos, cache, cola de mensajes, reverse proxy. Docker Compose describe todo eso en un YAML declarativo:
services:
web:
build: .
ports: ["3000:3000"]
depends_on: { db: { condition: service_healthy } }
db:
image: postgres:16.2-alpine
environment: { POSTGRES_PASSWORD_FILE: /run/secrets/db_pw }
volumes: [db-data:/var/lib/postgresql/data]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
volumes:
db-data:
Un docker compose up -d levanta todo. Para producción de baja escala en un VPS, Compose sigue siendo suficiente y evita la complejidad de Kubernetes. Usa nuestro generador de Docker Compose para arrancar rápido.
Docker vs Kubernetes: cuándo usar cada uno
- 1 servidor, pocos contenedores → Docker Compose es perfecto.
- Múltiples servidores, alta disponibilidad, autoscaling → Kubernetes. La curva de aprendizaje es dura pero paga a partir de cierta escala.
- Entre medias: Docker Swarm (más simple que K8s) o Nomad. En 2026 la comunidad se ha concentrado casi por completo en Kubernetes.
Seguridad de contenedores: lo mínimo que debes hacer
1. Fija versiones exactas de imagen base. No :latest. 2. Escanea con Trivy, Grype o Snyk antes de subir a registry. 3. Ejecuta como usuario no-root (USER 1001). 4. Read-only rootfs (docker run --read-only) más volúmenes específicos para lo que escriba. 5. Firma imágenes con cosign para verificar cadena de suministro (supply-chain attacks). 6. Minimiza la superficie: distroless o Alpine, nunca full Ubuntu si puedes evitarlo.
El impacto real en DevOps
Docker no fue solo una tecnología: fue un cambio cultural. Popularizó infra como código, immutable deployments, build once, deploy anywhere y allanó el camino para prácticas hoy estándar: pipelines CI/CD reproducibles, entornos de desarrollo homogéneos, microservicios manejables. Sin Docker, Kubernetes no habría despegado; sin ambos, la nube pública no sería lo que es hoy.
Diez años después, sigue siendo la primera pieza que instalas al empezar cualquier proyecto serio.
Herramientas relacionadas
Construye archivos docker-compose.yml de forma visual, con servicios, puertos, variables y volúmenes.
Genera Dockerfiles optimizados para Node.js, Python, Go, Java o sitios estáticos, con multi-stage y usuario no-root.
Planifica redes bridge y overlay para tus contenedores calculando IPs disponibles y prefijo óptimo.