Docker para Principiantes: Una Guía Práctica de Inicio
· 12 min de lectura
📑 Tabla de Contenidos
- ¿Qué es Docker y por qué debería importarte?
- Conceptos Clave: Imágenes, Contenedores y Dockerfiles
- Instalando Docker en tu Sistema
- Comandos Esenciales de Docker que Todo Desarrollador Necesita
- Escribiendo tu Primer Dockerfile
- Docker Compose para Aplicaciones Multi-Contenedor
- Volúmenes: Persistiendo Datos Más Allá del Ciclo de Vida del Contenedor
- Fundamentos de Redes en Docker
- Mejores Prácticas Listas para Producción
- Depuración y Solución de Problemas Comunes
- Herramientas e Integraciones Populares
- Preguntas Frecuentes
Docker revolucionó el desarrollo de software al resolver el infame problema de "funciona en mi máquina". En lugar de instalar dependencias directamente en tu sistema y lidiar con conflictos de versiones, Docker empaqueta todo lo que tu aplicación necesita en contenedores aislados que se ejecutan de manera idéntica en todas partes—desde tu laptop hasta los servidores de producción.
Si aún no has aprendido Docker en 2026, ahora es el momento. Se ha convertido en el estándar de facto para el despliegue de aplicaciones, utilizado por más de 13 millones de desarrolladores en todo el mundo e integrado en prácticamente todos los flujos de trabajo de desarrollo modernos.
¿Qué es Docker y por qué debería importarte?
Docker es una plataforma de contenedorización que envuelve tu aplicación y todas sus dependencias en una unidad estandarizada llamada contenedor. Piensa en él como un paquete ligero y portátil que incluye todo lo necesario para ejecutar tu software: código, tiempo de ejecución, herramientas del sistema, bibliotecas y configuraciones.
Antes de Docker, los desarrolladores enfrentaban inconsistencias constantes en los entornos. Tu aplicación Node.js podría funcionar perfectamente en tu MacBook con Node 18, pero fallar en la máquina Windows de tu colega ejecutando Node 16. O peor aún, funcionaría en desarrollo pero fallaría misteriosamente en producción debido a diferencias sutiles en las bibliotecas del sistema.
Docker elimina estos dolores de cabeza al crear entornos consistentes y reproducibles. Cuando contenedorizas una aplicación, estás garantizando que se comportará de la misma manera sin importar dónde se ejecute.
Beneficios Clave de Usar Docker
- Consistencia entre entornos: Desarrollo, staging y producción ejecutan contenedores idénticos
- Incorporación más rápida: Los nuevos miembros del equipo pueden comenzar a contribuir en minutos en lugar de pasar días configurando su entorno
- Aislamiento: Ejecuta múltiples proyectos con dependencias conflictivas en la misma máquina sin interferencias
- Uso eficiente de recursos: Los contenedores comparten el kernel del sistema operativo anfitrión, haciéndolos mucho más ligeros que las máquinas virtuales
- Despliegue simplificado: Envía toda tu pila de aplicación como un único artefacto
- Arquitectura de microservicios: Divide aplicaciones monolíticas en servicios manejables y desplegables de forma independiente
Consejo profesional: Docker no es solo para despliegues en producción. Muchos desarrolladores lo usan para ejecutar bases de datos, capas de caché y otros servicios localmente sin saturar su sistema con instalaciones. ¿Necesitas PostgreSQL para un proyecto y MySQL para otro? Ejecuta ambos en contenedores sin conflictos.
Conceptos Clave: Imágenes, Contenedores y Dockerfiles
Comprender tres conceptos fundamentales es esencial antes de sumergirse en los comandos y flujos de trabajo de Docker.
Imágenes de Docker
Una imagen es una plantilla de solo lectura que contiene todo lo necesario para ejecutar una aplicación. Piensa en ella como una clase en programación orientada a objetos—es un plano, no una instancia en ejecución.
Las imágenes se construyen en capas, con cada capa representando un cambio o instrucción. Esta arquitectura en capas permite un almacenamiento y transferencia eficientes porque Docker solo necesita descargar o almacenar las capas que han cambiado.
Puedes descargar imágenes preconstruidas desde Docker Hub (el registro oficial) o construir tus propias imágenes personalizadas. Las imágenes base populares incluyen node, python, nginx, postgres y redis.
Contenedores de Docker
Un contenedor es una instancia en ejecución de una imagen—como un objeto instanciado desde una clase. Una imagen puede generar múltiples contenedores, cada uno ejecutándose de forma independiente con su propio sistema de archivos, red y espacio de procesos aislados.
Los contenedores son efímeros por diseño. Cuando detienes y eliminas un contenedor, cualquier dato escrito dentro de él desaparece a menos que hayas configurado explícitamente almacenamiento persistente usando volúmenes (más sobre esto más adelante).
Dockerfiles
Un Dockerfile es un archivo de texto que contiene instrucciones para construir una imagen de Docker. Es esencialmente una receta que le dice a Docker cómo ensamblar tu entorno de aplicación paso a paso.
Cada instrucción en un Dockerfile crea una nueva capa en la imagen. Docker almacena en caché estas capas de manera inteligente, por lo que reconstruir una imagen solo procesa las capas que han cambiado—haciendo que las construcciones subsecuentes sean extremadamente rápidas.
Aquí hay un Dockerfile mínimo para una aplicación Node.js:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Desglosemos lo que hace cada instrucción:
FROMespecifica la imagen base (Node.js 20 en Alpine Linux, una distribución mínima)WORKDIRestablece el directorio de trabajo dentro del contenedorCOPYtransfiere archivos desde tu máquina anfitriona al contenedorRUNejecuta comandos durante el proceso de construcción (instalando dependencias)EXPOSEdocumenta en qué puerto escucha la aplicaciónCMDdefine el comando predeterminado para ejecutar al iniciar un contenedor
Instalando Docker en tu Sistema
La instalación de Docker varía ligeramente según el sistema operativo, pero el proceso es sencillo en todas las plataformas principales.
macOS y Windows
Descarga e instala Docker Desktop desde el sitio web oficial. Docker Desktop incluye todo lo que necesitas: el Motor de Docker, CLI de Docker, Docker Compose y una interfaz gráfica amigable para gestionar contenedores.
Después de la instalación, Docker Desktop se ejecuta en segundo plano y agrega un icono en la barra de menú (macOS) o icono en la bandeja del sistema (Windows) para acceso rápido a configuraciones y contenedores en ejecución.
Linux
En Linux, instala Docker Engine directamente usando el gestor de paquetes de tu distribución. Para Ubuntu/Debian:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
Cierra sesión y vuelve a iniciarla para que la membresía del grupo surta efecto, permitiéndote ejecutar comandos de Docker sin sudo.
Verificando la Instalación
Confirma que Docker está funcionando correctamente ejecutando:
docker --version
docker run hello-world
El segundo comando descarga una pequeña imagen de prueba y la ejecuta en un contenedor. Si ves un mensaje de bienvenida, Docker está instalado y funcionando correctamente.
Comandos Esenciales de Docker que Todo Desarrollador Necesita
Dominar un puñado de comandos básicos cubrirá el 90% de tu uso diario de Docker. Aquí hay una tabla de referencia completa:
| Comando | Qué Hace | Opciones Comunes |
|---|---|---|
docker build -t myapp . |
Construye una imagen desde un Dockerfile en el directorio actual | -t etiqueta la imagen con un nombre |
docker run myapp |
Crea e inicia un contenedor desde una imagen | -d (desacoplado), -p (mapeo de puertos), --name |
docker ps |
Lista los contenedores en ejecución | -a muestra todos los contenedores (incluyendo detenidos) |
docker stop [id] |
Detiene graciosamente un contenedor en ejecución | Usa ID o nombre del contenedor |
docker rm [id] |
Elimina un contenedor detenido | -f fuerza la eliminación de contenedores en ejecución |
docker images |
Lista todas las imágenes en tu sistema | -a muestra imágenes intermedias |
docker rmi [image] |
Elimina una imagen | -f fuerza la eliminación |
docker logs [id] |
Ver la salida y registros del contenedor | -f sigue la salida de registros en tiempo real |
docker exec -it [id] sh |
Abre un shell interactivo dentro de un contenedor en ejecución | -it habilita terminal interactiva |
docker pull [image] |
Descarga una imagen desde un registro | Especifica etiqueta como nginx:1.25 |
docker compose up |
Inicia todos los servicios definidos en docker-compose.yml | -d ejecuta en segundo plano |
docker compose down |
Detiene y elimina todos los contenedores del archivo compose | -v también elimina volúmenes |
Ejemplos Prácticos de Comandos
Ejecutando un contenedor con mapeo de puertos y variables de entorno:
docker run -d \
--name my-postgres \
-p 5432:5432 \
-e POSTGRES_PASSWORD=secret \
postgres:16
Esto inicia PostgreSQL en segundo plano, mapea el puerto 5432 a tu máquina anfitriona y establece la contraseña de la base de datos.
Viendo registros en tiempo real desde un contenedor:
docker logs -f my-postgres
Ejecutando comandos dentro de un contenedor en ejecución:
docker exec -it my-postgres psql -U postgres
Esto abre un shell interactivo de PostgreSQL dentro del contenedor.
Consejo rápido: No necesitas escribir IDs completos de contenedores. Docker acepta prefijos únicos, así que si tu ID de contenedor es a3f8b2c1d4e5, puedes usar docker stop a3f siempre que ningún otro ID de contenedor comience con esos caracteres.
Escribiendo tu Primer Dockerfile
Construyamos un Dockerfile completo para una aplicación Node.js del mundo real, explicando cada decisión en el camino.
# Usa una versión específica de Node.js en Alpine Linux (tamaño de imagen más pequeño)
FROM node:20-alpine
# Instala dependencias del sistema si es necesario
RUN apk add --no-cache python3 make g++
# Establece el directorio de trabajo
WORKDIR /app
# Copia primero los archivos de paquetes (para mejor caché de capas)
COPY package*.json ./
# Instala solo dependencias de producción
RUN npm ci --production --silent
# Copia el código fuente de la aplicación
COPY . .
# Crea un usuario no root por seguridad
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001 && \
chown -R nodejs:nodejs /app
# Cambia a usuario no root
USER nodejs
# Expone el puerto de la aplicación
EXPOSE 3000
# Verificación de salud para monitorear el estado del contenedor
HEALTHCHECK --interval=30s --timeout=3s \
CMD node healthcheck.js || exit 1
# Inicia la aplicación
CMD ["node", "server.js"]
Mejores Prácticas de Dockerfile
El orden importa para la eficiencia del caché. Coloca las instrucciones que cambian frecuentemente (como COPY . .) cerca del final de tu Dockerfile. De esta manera, Docker puede reutilizar capas en caché para la instalación de dependencias cuando solo cambia tu código fuente.
Usa archivos .dockerignore para excluir archivos innecesarios del contexto de construcción:
node_modules
npm-debug.log
.git
.env
*.md
.DS_Store
Esto acelera las construcciones y reduce el tamaño de la imagen al evitar que Docker copie archivos que no necesitas en el contenedor.
Construcciones Multi-Etapa
Para lenguajes compilados o aplicaciones que requieren herramientas de construcción, usa construcciones multi-etapa para mantener las imágenes finales pequeñas:
# Etapa de construcción
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Etapa de producción
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY --from=builder /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]
La imagen final solo contiene dependencias de producción y artefactos compilados, no herramientas de construcción ni código fuente.
Docker Compose para Aplicaciones Multi-Contenedor
Las aplicaciones del mundo real rara vez consisten en un solo servicio. Típicamente necesitas una aplicación web, base de datos, caché, cola de mensajes y otros servicios de soporte. Docker Compose te permite definir y gestionar aplicaciones multi-contenedor usando un único archivo de configuración YAML.
Aquí hay un docker-compose.yml completo para una pila típica de aplicación web:
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
volumes:
- ./logs:/app/logs
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=secret
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
restart: unless-stopped
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redisdata:/data
restart: unless-stopped
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- web
restart: unless-stopped
volumes:
pgdata:
redisdata:
Trabajando con Docker Compose
Inicia todos los servicios en segundo plano:
dock