
Docker para Desarrolladores: Containeriza tus Aplicaciones
Aprende Docker desde cero. Containeriza tus aplicaciones y domina Docker Compose para desarrollo local.
Docker para Desarrolladores: Containeriza tus Aplicaciones
Docker ha revolucionado la forma en que desarrollamos, empaquetamos y distribuimos aplicaciones. Esta guía completa te enseña desde conceptos fundamentales hasta Docker Compose avanzado, permitiéndote containerizar tus aplicaciones y eliminar completamente el problema "funciona en mi máquina".
¿Qué es Docker y por qué deberías usarlo?
Docker es una plataforma de containerización que permite empaquetar tu aplicación, código, runtime, sistema operativo y todas sus dependencias en un contenedor standarizado llamado Docker image. Este contenedor puede ejecutarse en cualquier máquina con Docker instalado, independientemente del sistema operativo o configuración.
El problema que Docker resuelve
Alguna vez has escuchado: "Pero funciona perfectamente en mi máquina..."? Docker elimina este problema completamente garantizando que tu aplicación funcione exactamente igual en desarrollo, testing y producción.
Ventajas principales de Docker
- Consistencia: Tu app funciona identicamente en todas partes
- Aislamiento: Cada contenedor es independiente, evita conflictos de dependencias
- Ligereza: Mucho más ligero que máquinas virtuales (MB vs GB)
- Escalabilidad: Ejecuta múltiples instancias fácilmente
- DevOps-friendly: Facilita CI/CD y deployments automáticos
- Microservicios: Ideal para arquitecturas de microservicios
Empresas como Netflix, Uber, Spotify y PayPal dependen de Docker para sus operaciones diarias.
Conceptos fundamentales de Docker
Docker Image - El blueprint
Una Docker image es una plantilla inmutable que contiene:
- Un sistema operativo base (Alpine, Ubuntu, etc)
- Todas las dependencias necesarias
- Tu código de aplicación
- Variables de entorno y configuraciones
- Instrucciones para ejecutar la app
Las images son inmutables: una vez construidas no cambian. Esto garantiza consistencia.
Docker Container - La instancia viva
Un contenedor es una instancia en ejecución de una imagen Docker. Es como la diferencia entre un plano (image) y una casa construida (container).
# Correr un contenedor
docker run -it ubuntu:22.04
# Ver contenedores en ejecución
docker ps
# Ver todos los contenedores (incluyendo detenidos)
docker ps -a
Dockerfile - La receta
Un Dockerfile es un archivo de texto con instrucciones paso-a-paso para construir una imagen Docker.
# Usar imagen base oficial de Node
FROM node:18-alpine
# Establece el directorio de trabajo
WORKDIR /app
# Copia archivos package
COPY package*.json ./
# Instala dependencias
RUN npm ci --only=production
# Copia el código de la aplicación
COPY . .
# Expone puerto
EXPOSE 3000
# Define el comando al iniciar
CMD ["node", "server.js"]
Instrucciones comunes en Dockerfile
- FROM: Especifica la imagen base (siempre debe ser la primera)
- WORKDIR: Establece el directorio de trabajo
- COPY/ADD: Copia archivos del host al contenedor
- RUN: Ejecuta un comando durante la construcción
- ENV: Establece variables de entorno
- EXPOSE: Documenta qué puerto escucha la app
- CMD: Comando por defecto al ejecutar el contenedor
- ENTRYPOINT: Punto de entrada del contenedor
Construir y ejecutar tu primera imagen Docker
Paso 1: Crear un Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Paso 2: Construir la imagen
# Construir imagen con tag
docker build -t mi-app:1.0 .
# Ver imágenes
docker images
Paso 3: Ejecutar un contenedor
# Ejecutar contenedor mapeando puerto
docker run -p 3000:3000 --name mi-contenedor mi-app:1.0
# Ejecutar en background
docker run -d -p 3000:3000 --name mi-contenedor mi-app:1.0
# Ver logs
docker logs mi-contenedor
Mejores prácticas para Dockerfiles
- Usa imágenes base ligeras: alpine vs ubuntu (5MB vs 77MB)
- Multi-stage builds: Separa build de runtime
- Minimiza layers: Agrupa RUN commands
- No ejecutes como root: Crea usuario no-root por seguridad
- Usa .dockerignore: Excluye archivos innecesarios
- Especifica versiones: No uses "latest"
Multi-Stage Builds - Optimizar tamaño de imagen
Los multi-stage builds permiten usar múltiples FROM statements para reducir drásticamente el tamaño final de la imagen.
# Stage 1: Build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Runtime (mucho más pequeño)
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Copiar solo el build desde stage anterior
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["npm", "start"]
Beneficio: La imagen final no incluye herramientas de build, reduciendo tamaño de 500MB a 150MB.
Docker Compose - Múltiples contenedores
Docker Compose permite definir y ejecutar aplicaciones multi-contenedor con un simple archivo YAML.
Un docker-compose.yml real
version: '3.8'
services:
# Aplicación Node.js
web:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://postgres:password@db:5432/myapp
- NODE_ENV=development
depends_on:
- db
volumes:
- .:/app # Hot reload en desarrollo
- /app/node_modules
restart: unless-stopped
networks:
- app-network
# Base de datos PostgreSQL
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=myapp
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
networks:
- app-network
# Redis para caching
redis:
image: redis:7-alpine
ports:
- "6379:6379"
restart: unless-stopped
networks:
- app-network
volumes:
postgres_data:
networks:
app-network:
driver: bridge
Comandos útiles de Docker Compose
# Inicia todos los servicios
docker-compose up
# Modo background
docker-compose up -d
# Ver logs
docker-compose logs -f web
# Ejecutar comando en contenedor
docker-compose exec db psql -U postgres -d myapp
# Detener servicios
docker-compose down
# Reconstruir imágenes
docker-compose build
Volúmenes y Redes de Docker
Volúmenes - Persistencia de datos
Los volúmenes permiten que los datos persistan cuando un contenedor se detiene o elimina.
# Crear un volumen
docker volume create mi-volume
# Usar volumen al ejecutar contenedor
docker run -v mi-volume:/data mi-app
# Bind mount (directorio local)
docker run -v /ruta/local:/ruta/contenedor mi-app
Redes de Docker
Las redes permiten que los contenedores se comuniquen entre sí por nombre de servicio.
# Crear una red
docker network create app-network
# Conectar contenedor a red
docker run --network app-network --name web mi-app
# Los contenedores pueden conectarse por nombre
# Ej: desde web contenedor: curl http://db:5432
Seguridad en Docker
Prácticas de seguridad esenciales
- No ejecutes como root: Crea usuario no-root en Dockerfile
- Scanea imágenes: Busca vulnerabilidades con docker scan o Trivy
- Mantén imágenes actualizado: Aplica parches regularmente
- No incluyas secrets: Usa variables de entorno o secrets managers
- Lee-only filesystem: Hace el filesystem read-only cuando sea posible
- Limita recursos: Establece memory y CPU limits
FROM node:18-alpine
# No ejecutar como root
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# Cambiar a usuario no-root
USER nodejs
EXPOSE 3000
CMD ["node", "server.js"]
Debugging y troubleshooting
Comandos útiles de debugging
# Inspeccionar imagen
docker inspect mi-app
# Entrar a un contenedor en ejecución
docker exec -it mi-contenedor sh
# Ver recursos usados
docker stats
# Ver diferencias en contenedor
docker diff mi-contenedor
# Copiar archivos hacia/desde contenedor
docker cp mi-contenedor:/app/file.txt ./
docker cp ./file.txt mi-contenedor:/app/
Problemas comunes y soluciones
- Puerto ya en uso: `docker run -p 3001:3000` mapea a otro puerto
- Contenedor se detiene inmediatamente: Revisa logs con `docker logs`
- No puedo conectar a base de datos: Asegúrate de usar el nombre del servicio (no localhost)
- Cambios no se reflejan: Reconstruye la imagen después de cambios
Docker es esencial en 2024
Docker se ha convertido en una habilidad fundamental para todo desarrollador moderno. Ya sea que trabajes en startups o empresas grandes, aprender Docker te hace más valioso como ingeniero y facilita enormemente el deployment y la colaboración en equipo.
Comienza hoy mismo containerizando una de tus aplicaciones. Verás cuánto más fácil se vuelve el desarrollo cuando cada componente está aislado y definido claramente.

Sobre el autor
Andres Saumet
Desarrollador Web & Móvil Full Stack · Colombia
Hay mil desarrolladores que pueden hacer que algo funcione. Yo me obsesiono con hacer que funcione y genere dinero.
Soy Andres Saumet, desarrollador Web y Móvil con foco en rentabilidad. Trabajo con startups, emprendedores y empresas que ya tienen una visión clara y necesitan a alguien que la convierta en un producto digital real — uno que los usuarios quieran usar y que el negocio quiera escalar.
Domino React, Next.js, React Native y Node.js. Pero más allá del stack, entiendo cómo piensan los usuarios, cómo fluye un negocio y qué decisiones técnicas impactan directamente en los ingresos.
Cada línea de código que escribo tiene un propósito: que tu producto web o móvil sea más rápido, más usable y más rentable.
¿Tienes un producto que necesita crecer? Construyámoslo juntos.
