Docker: qué es y cómo usarlo para ejecutar contenedores

- ¿Qué es Docker?
- Sistemas operativos compatibles
- Tu primer contenedor (5 minutos)
- Del código a la imagen: escribe tu Dockerfile
- Persistencia de datos: volúmenes y bind mounts
- Orquesta servicios con Docker Compose (v2)
- Buenas prácticas (seguridad, rendimiento y mantenimiento)
- Cuándo usar contenedores (y cuándo no)
- Checklist rápido para pasar a producción
- En pocas palabras
- Conclusión y siguientes pasos
¿Quieres desplegar apps con menos fricción y el mismo resultado en cualquier máquina? Docker te permite empaquetar tu aplicación con sus dependencias en un contenedor ligero que corre igual en desarrollo, pruebas y producción. A continuación, entenderás qué es Docker, cómo funciona, cómo escribir un Dockerfile, cómo levantar proyectos con Docker Compose, cómo persistir datos y qué buenas prácticas seguir para que todo sea seguro y reproducible.
¿Qué es Docker?
Docker es una plataforma de contenedores que aísla tu app del sistema operativo anfitrión (host). En lugar de instalar bibliotecas directamente en el host, construyes una imagen inmutable con todo lo necesario; después, ejecutas esa imagen como uno o varios contenedores. Así evitas el clásico “en mi máquina funciona”.
Conceptos clave:
- Imagen: plantilla de solo lectura (capa sobre capa) que define tu app.
- Contenedor: instancia en ejecución de una imagen.
- Registro: repositorio de imágenes (Docker Hub, GitHub Container Registry, registro privado).
- Docker Engine: servicio que construye/ejecuta contenedores.
Sistemas operativos compatibles
- Linux: el entorno natural de Docker.
- macOS (Intel y Apple Silicon): vía Docker Desktop, que usa virtualización ligera.
- Windows 10/11: con WSL 2 y Docker Desktop para una experiencia nativa.
Tu primer contenedor (5 minutos)
Comprueba la instalación y levanta un Nginx de prueba.
# prueba de instalación
docker run --rm hello-world
# servidor web temporal en http://localhost:8080
docker run -d --name web -p 8080:80 nginx:alpine
# ver logs y detener
docker logs -f web
docker stop web && docker rm web
Del código a la imagen: escribe tu Dockerfile
Un Dockerfile describe cómo construir una imagen. En 2025 conviene usar multi-stage builds, un usuario no root y un .dockerignore para excluir archivos innecesarios.
Ejemplo (Node.js + multi-stage, no-root, producción)
# syntax=docker/dockerfile:1.7
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:20-alpine AS runtime
ENV NODE_ENV=production
WORKDIR /app
# crear usuario no root
RUN addgroup -S app && adduser -S app -G app
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
USER app
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s \
CMD node -e "fetch('http://localhost:3000/health').then(r=>r.ok?process.exit(0):process.exit(1)).catch(()=>process.exit(1))"
CMD ["node", "dist/server.js"]
.dockerignore recomendado (reduce tamaño y filtraciones):
node_modules
.git
Dockerfile
.dockerignore
dist/*.map
*.log
.env*
Construye y ejecuta tu imagen
# construir con etiqueta (tag)
docker build -t miapp:1.0.0 .
# ejecutar mapeando puerto
docker run -d --name miapp -p 3000:3000 miapp:1.0.0
# ver contenedores, logs y entrar a la shell
docker ps
docker logs -f miapp
docker exec -it miapp sh
Persistencia de datos: volúmenes y bind mounts
Los cambios dentro del contenedor son efímeros. Para guardar datos usa:
- Volúmenes (gestionados por Docker): portables y desacoplados del host. Ideal para bases de datos.
- Bind mounts (carpetas del host): útiles en desarrollo para sincronizar código.
# volumen con PostgreSQL
docker volume create pgdata
docker run -d --name db \
-e POSTGRES_PASSWORD=secret \
-v pgdata:/var/lib/postgresql/data \
-p 5432:5432 postgres:16
Orquesta servicios con Docker Compose (v2)
Docker Compose define servicios, redes y volúmenes en un único archivo. Desde 2023, el comando oficial es docker compose (sin guion). Levanta pilas completas con una sola orden.
Ejemplo Compose: app web + Postgres + Redis
# docker-compose.yml (Compose Spec; no es obligatorio 'version:')
services:
app:
build: .
ports:
- "3000:3000"
env_file: .env
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:3000/health || exit 1"]
interval: 30s
timeout: 3s
retries: 3
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: appdb
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 3s
retries: 10
cache:
image: redis:7-alpine
command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"]
volumes:
- redisdata:/data
volumes:
pgdata:
redisdata:
# levantar en segundo plano
docker compose up -d
# ver logs agrupados
docker compose logs -f
# ejecutar comandos dentro de un servicio
docker compose exec app node -v
# detener y borrar contenedores (con volúmenes)
docker compose down -v
Buenas prácticas (seguridad, rendimiento y mantenimiento)
- Minimiza la imagen: usa distros ligeras (alpine, distroless) o multi-stage para compilar en una imagen y ejecutar en otra.
- Usuario no root: reduce superficie de ataque con
USERy permisos mínimos. - .dockerignore: evita subir secrets, logs y artefactos innecesarios al contexto de build.
- Variables y secretos: configura con
env_filey proveedores de secretos; no hagasENV PASSWORD=...en la imagen. - Healthchecks: añade
HEALTHCHECKpara que orquestadores sepan cuándo reiniciar. - Etiquetas inmutables: fija versiones (
postgres:16) en lugar delatest. - Límites de recursos: en Compose usa
deploy.resources(CPU/RAM) cuando el destino lo soporte. - Escaneo de vulnerabilidades: integra Docker Scout/Trivy en CI para auditar imágenes.
- Logs y observabilidad: redirige stdout/stderr y usa drivers/stack de logs para producción.
Cuándo usar contenedores (y cuándo no)
- Sí: microservicios, APIs, trabajos por lotes, workers, pruebas de integración, entornos de desarrollo replicables.
- Tal vez: apps monolíticas heredadas; evalúa costo/beneficio de contenedorizarlas.
- No: cargas que requieren privilegios persistentes sobre el host, o software que depende de drivers/GUI específicos sin soporte en contenedores.
Checklist rápido para pasar a producción
- Fija versiones de base y dependencias.
- Implementa multi-stage y usuario no root.
- Agrega healthchecks y métricas.
- Define volúmenes para datos y backups programados.
- Automatiza build/push en CI y despliega con tags firmados.
En pocas palabras
Docker empaca tu app en una imagen y la corre como contenedor, igual en todas partes. Compose te permite definir pilas completas (app + base de datos + cache) con un archivo. Con volúmenes guardas datos; con buenas prácticas, mantienes tus despliegues seguros y reproducibles.
Conclusión y siguientes pasos
Arranca con el ejemplo de arriba, crea tu Dockerfile y usa docker compose para levantar tu stack. Si trabajas en Windows, verifica WSL 2 y acelera tu flujo con atajos de terminal. Lee también nuestra guía interna para optimizar tu equipo antes de desarrollar (reemplaza con URL real del sitemap): buenas prácticas en Windows para programar.
Descargar ejemplos de Dockerfile (WordPress)
