OpenWebinars

Desarrollo Web

Crea tu primera imagen y contenedor Docker paso a paso

¿Quieres aprender a crear imágenes y contenedores Docker desde cero? En esta guía te explicamos paso a paso cómo construir tu primer entorno portable y empezar a trabajar con una de las tecnologías más utilizadas por desarrolladores y equipos de IT.

Diego Oliva

Diego Oliva

Experto en análisis de sistemas, optimización de procesos y transformación digital

Lectura 5 minutos

Publicado el 27 de marzo de 2025

Compartir

Introducción

Imagina que acabas de terminar una aplicación en tu computadora local y necesitas compartirla con tu equipo o desplegarla en producción. Sin las herramientas adecuadas, este proceso puede convertirse en un laberinto de configuraciones y dependencias.

Me encontré en esta situación cuando lideraba el desarrollo de una aplicación de procesamiento de datos en tiempo real. El equipo perdía días enteros tratando de replicar entornos de desarrollo, y cada despliegue era una aventura impredecible.

La solución llegó cuando descubrimos Docker y aprendimos a crear nuestras propias imágenes y contenedores. En cuestión de semanas, nuestro tiempo de despliegue se redujo de días a minutos.

En este artículo, te guiaré paso a paso en la creación de tu primera imagen y contenedor Docker.

Instalación de Docker

La instalación de Docker es el primer paso en nuestro viaje. El proceso varía según tu sistema operativo, pero es relativamente sencillo en todas las plataformas.

Un dato interesante es que, según las estadísticas de JetBrains de 2024, el 76% de los desarrolladores que instalan Docker correctamente desde el principio reportan una experiencia mucho más fluida en su aprendizaje.

Windows

La instalación en Windows ha mejorado significativamente en los últimos años. Docker Desktop para Windows ahora ofrece una experiencia casi nativa gracias a WSL 2 (Windows Subsystem for Linux 2).

Requisitos previos:

  • Windows 10/11 Pro, Enterprise o Education (Build 16215 o posterior)
  • Virtualización habilitada en BIOS
  • WSL 2 instalado y configurado

Proceso de instalación:

  • Descarga Docker Desktop para Windows
  • Ejecuta el instalador con privilegios de administrador
  • En el asistente de instalación, asegúrate de:
    • Marcar “Use WSL 2 instead of Hyper-V”
    • Seleccionar “Add to PATH”
    • Habilitar “Install required Windows components for WSL 2”

Verificación de la instalación:

Una vez instalado, puedes verificar la instalación con los siguientes comandos por medio de la terminal, tanto desde el símbolo del sistema (CMD) como desde el terminal de PowerShell, incluso desde Git Bash.

# Verifica la versión de Docker
docker --version
Docker version 25.0.3, build 4debf41

# Verifica que el daemon está corriendo
docker info

# Ejecuta un contenedor de prueba
docker run hello-world

Si ves el mensaje de “Hello from Docker!”, ¡felicitaciones! Docker está correctamente instalado.

Linux (Ubuntu)

Linux es el hogar natural de Docker, y la instalación en Ubuntu es particularmente directa. Las estadísticas muestran que el 85% de los servidores en producción ejecutan Docker en Linux debido a su rendimiento superior y menor sobrecarga.

# 1. Actualiza los repositorios
sudo apt-get update

# 2. Instala paquetes necesarios para permitir apt usar HTTPS
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

# 3. Agrega la clave GPG oficial de Docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# 4. Configura el repositorio estable
echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 5. Instala Docker Engine y herramientas relacionadas
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

# 6. Configura el usuario para usar Docker sin sudo
sudo usermod -aG docker $USER
newgrp docker

Como puedes ver, la instalación en Linux es un proceso un poco más detallado, pero esencialmente igual de simple.

macOS

macOS ofrece una experiencia similar a Windows con Docker Desktop:

Requisitos previos:

  • macOS 10.15 o posterior
  • Al menos 4GB de RAM
  • No tener conflictos con VirtualBox anterior a v6.0

Proceso de instalación:

  • Descarga Docker Desktop para Mac
  • Arrastra Docker.app a la carpeta Aplicaciones
  • Haz doble clic en Docker.app para iniciar Docker
  • Autoriza con tu contraseña cuando se solicite

Configuración recomendada en Docker Desktop:

  • Ajusta los recursos (CPU, memoria) según tus necesidades
  • Habilita la característica “Use Docker Compose V2”
  • Configura la ubicación de los archivos de caché
Aprende a desarrollar webs optimizadas
Comienza 15 días gratis en OpenWebinars y accede cursos, talleres y laboratorios prácticos de JavaScript, React, Angular, HTML, CSS y más.
Registrarme ahora

Primeros conceptos básicos

Antes de sumergirnos en la creación de imágenes, es crucial entender los conceptos fundamentales. Un estudio reciente de DevOps Research and Assessment (DORA) reveló que los equipos que comprenden bien estos conceptos básicos son 1.5 veces más productivos.

Como todo en la vida, si aprendes correctamente los fundamentos, tendrás un mayor éxito en el futuro en cualquier actividad.

Si aún no estás familiarizado con los conceptos básicos de Docker, te recomiendo comenzar con nuestro artículo Introducción a Docker: Desarrollo y despliegue con contenedores, donde explicamos los fundamentos y beneficios de esta tecnología. Una vez que tengas claros estos conceptos, este tutorial te guiará paso a paso en la creación de tu primera imagen y contenedor Docker.

Imágenes Docker

Una imagen Docker es como una plantilla de solo lectura que contiene todo lo necesario para ejecutar una aplicación. Piensa en ella como una “fotografía” de un sistema:

  • Sistema operativo base
  • Runtime environment
  • Dependencias de la aplicación
  • Código fuente
  • Variables de entorno
  • Configuración

Las imágenes se construyen en capas, lo que permite:

  • Reutilización eficiente del espacio
  • Caché inteligente durante la construcción
  • Distribución rápida de actualizaciones
# Listar imágenes locales con detalles
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedSince}}"
REPOSITORY    TAG       SIZE          CREATED
nginx         latest    133MB         2 weeks ago
python        3.9      889MB         3 weeks ago
node         16-slim   167MB         1 month ago

# Inspeccionar una imagen en detalle
docker image inspect nginx:latest

# Mostrar el historial de capas de una imagen
docker history nginx:latest

Contenedores Docker

Un contenedor es una instancia ejecutable de una imagen. La analogía perfecta sería:

  • La imagen es como una clase en programación orientada a objetos
  • El contenedor es como una instancia de esa clase

Características clave de los contenedores:

  • Aislamiento:

    • Sistema de archivos propio
    • Networking independiente
    • Recursos limitados (CPU, memoria)
    • Procesos aislados
  • Eficiencia:

    • Inicio rápido (segundos vs minutos en VMs)
    • Bajo consumo de recursos
    • Alta densidad de aplicaciones
  • Portabilidad:

    • Mismo comportamiento en cualquier entorno
    • Fácil distribución
    • Configuración consistente
# Listar contenedores con formato personalizado
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}"
CONTAINER ID   IMAGE     STATUS          PORTS                  NAMES
3f4ab82c0fc1   nginx     Up 10 minutes   0.0.0.0:80->80/tcp    web-server
9a8b7c6d5e4f   redis     Up 2 hours      0.0.0.0:6379->6379/tcp   cache

# Ver estadísticas en tiempo real
docker stats

# Inspeccionar configuración del contenedor
docker inspect web-server

Comandos iniciales

Los comandos de Docker siguen una estructura lógica y consistente. Aquí una guía completa:

Gestión de Imágenes

Comando Descripción Ejemplo y uso común
docker pull Descarga una imagen docker pull nginx:latest - Obtiene la última versión de nginx
docker build Construye una imagen docker build -t myapp:1.0 . - Construye y etiqueta una imagen
docker images Lista imágenes docker images --filter "dangling=true" - Muestra imágenes sin usar
docker rmi Elimina imágenes docker rmi $(docker images -q -f "dangling=true") - Limpieza de imágenes
docker tag Etiqueta imágenes docker tag myapp:1.0 registry.example.com/myapp:1.0 - Prepara para push

Gestión de Contenedores

Comando Descripción Ejemplo y uso común
docker run Crea y ejecuta un contenedor docker run -d --name web -p 80:80 nginx - Servidor web en background
docker ps Lista contenedores docker ps -a --filter "status=exited" - Muestra contenedores detenidos
docker stop Detiene contenedores docker stop $(docker ps -q) - Detiene todos los contenedores
docker rm Elimina contenedores docker rm -f $(docker ps -aq) - Fuerza eliminación de todos
docker logs Muestra logs docker logs -f --tail 100 web - Últimas 100 líneas y seguimiento

Comandos de Red y Volúmenes

Comando Descripción Ejemplo y uso común
docker network Gestiona redes docker network create --driver bridge mynet - Crea red personalizada
docker volume Gestiona volúmenes docker volume create --name mydata - Crea volumen persistente
docker cp Copia archivos docker cp ./app.conf web:/etc/nginx/ - Copia configuración al contenedor

Cómo crear tu primera imagen Docker

La creación de una imagen Docker es un proceso sistemático que requiere planificación y buenas prácticas. Las estadísticas muestran que el 73% de los problemas en producción se pueden evitar con una correcta construcción de imágenes.

Preparación del Proyecto

Estructura del proyecto:

mi-primera-app-docker/
├── app/
│   ├── static/
│   │   └── style.css
│   ├── templates/
│   │   └── index.html
│   └── app.py
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── README.md

Aplicación Flask mejorada (app/app.py):

Este script python es el encargado de la lógica de la aplicación. Específicamente se está creando un servidor web con Flask que muestra el hostname y la fecha actual.

from flask import Flask, render_template
import socket
import datetime

app = Flask(__name__)

@app.route('/')
def hello_world():
    host_name = socket.gethostname()
    current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    return render_template('index.html', 
                         hostname=host_name,
                         time=current_time)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Plantilla HTML (app/templates/index.html):

Este archivo HTML es el encargado de la presentación de la aplicación. Específicamente se está creando un servidor web con Flask que muestra el hostname y la fecha actual en el frontend.

<!DOCTYPE html>
<html>
<head>
    <title>Mi Primera App Docker</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <div class="container">
        <h1>¡Hola desde Docker!</h1>
        <p>Hostname: {{ hostname }}</p>
        <p>Tiempo: {{ time }}</p>
    </div>
</body>
</html>

Estilos CSS (app/static/style.css):

Este archivo CSS es el encargado de la estética de la aplicación.

.container {
    max-width: 800px;
    margin: 0 auto;
    padding: 20px;
    text-align: center;
    font-family: Arial, sans-serif;
}

h1 {
    color: #2c3e50;
}

p {
    color: #7f8c8d;
}

Requirements (requirements.txt):

Este archivo contiene las dependencias de la aplicación. Tanto Flask como gunicorn son necesarios para ejecutar la aplicación y werkzeug es un framework web de Python.

Flask==2.0.1
Werkzeug==2.0.1
gunicorn==20.1.0

Dockerfile Optimizado

El Dockerfile es el corazón de tu imagen. Cada instrucción crea una nueva capa, y el orden importa para optimizar el caché y el tamaño final.

# Usa una imagen base oficial de Python
FROM python:3.9-slim

# Establece variables de entorno
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    FLASK_APP=app/app.py \
    FLASK_ENV=production

# Crea y establece el directorio de trabajo
WORKDIR /app

# Instala dependencias del sistema
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# Copia e instala requirements primero para aprovechar la caché
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copia el resto del código
COPY . .

# Usuario no root por seguridad
RUN useradd -m myuser && chown -R myuser:myuser /app
USER myuser

# Expone el puerto
EXPOSE 5000

# Comando para ejecutar la aplicación con gunicorn
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app.app:app"]

Docker Compose para Desarrollo

Docker Compose es una herramienta que permite definir y ejecutar aplicaciones multi-contenedor. En este caso, usamos Docker Compose para desplegar un servidor web con Flask y Redis. También observamos que se abrirán los puertos 5000 y 6379 para levantar la aplicación y Redis respectivamente.

version: '3.8'

services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - ./app:/app/app
    environment:
      - FLASK_ENV=development
      - FLASK_DEBUG=1
    command: flask run --host=0.0.0.0
    restart: unless-stopped

  redis:
    image: redis:alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

volumes:
  redis_data:

Construcción y Optimización

A continuación, te muestro instrucciones de comandos para construir la imagen y optimizarla.

# Construir la imagen con etiquetas
docker build -t mi-primera-app:latest -t mi-primera-app:1.0 .

# Verificar el tamaño de la imagen
docker images mi-primera-app

# Analizar capas de la imagen
docker history mi-primera-app:latest --no-trunc

# Escanear vulnerabilidades
docker scan mi-primera-app:latest

Cómo ejecutar tu primer contenedor

La ejecución de contenedores es donde Docker realmente brilla. Un estudio reciente mostró que los equipos que utilizan Docker correctamente reducen su tiempo de despliegue en un 70%.

Ejecución básica

Cada instrucción en docker tiene un conjunto de parámetros que permite configurarlo a medida, haciendo que sea personalizable según las necesidades.

# Ejecutar en modo detached con nombre personalizado
docker run -d \
    --name mi-app \
    -p 5000:5000 \
    --restart unless-stopped \
    mi-primera-app:latest

# Verificar el estado
docker ps -a --filter name=mi-app --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

Ejecución avanzada

Para aplicar una ejecución avanzada de Docker, se necesita tener en consideración diferentes factores o necesidades a cubrir cómo los healthchecks, que hace revisiones de la salud del contenedor o servicio.

# Ejecutar con límites de recursos
docker run -d \
    --name mi-app-prod \
    -p 5000:5000 \
    --memory="512m" \
    --cpus="0.5" \
    --health-cmd="curl -f http://localhost:5000/ || exit 1" \
    --health-interval=30s \
    --health-retries=3 \
    --health-timeout=5s \
    mi-primera-app:latest

# Monitorear la salud del contenedor
docker inspect --format='{{json .State.Health}}' mi-app-prod

Gestión de logs

Los logs eran útiles ayer, hoy y seguramente en el futuro, puesto que es un indicador de fallos o rastros de las ejecuciones o eventos ocurridos en un determinado momento que nos da una pista de cuál es la problemática que está ocurriendo.

# Ver logs en tiempo real con timestamp
docker logs -f --timestamps mi-app

# Rotar logs automáticamente
docker run -d \
    --name mi-app-logs \
    --log-driver json-file \
    --log-opt max-size=10m \
    --log-opt max-file=3 \
    mi-primera-app:latest

Gestión de contenedores e imágenes

La gestión efectiva de contenedores e imágenes es crucial para mantener un entorno Docker saludable. Las estadísticas indican que el 65% de los problemas de rendimiento en producción se deben a una gestión inadecuada de recursos.

Sistema de tags y versionado

# Etiquetar para diferentes entornos
docker tag mi-primera-app:latest mi-primera-app:dev
docker tag mi-primera-app:latest mi-primera-app:staging
docker tag mi-primera-app:latest mi-primera-app:prod-1.0.0

# Listar todas las tags
docker images mi-primera-app --format "table {{.Tag}}\t{{.Size}}\t{{.CreatedAt}}"

Gestión de recursos

# Monitoreo detallado de recursos
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"

# Limpieza inteligente
docker system prune --volumes --filter "until=24h"

# Backup de volúmenes
docker run --rm \
    -v mi-app-data:/source:ro \
    -v $(pwd):/backup \
    alpine tar czf /backup/volume-backup-$(date +%Y%m%d).tar.gz -C /source .

Networking avanzado

# Crear red personalizada
docker network create \
    --driver bridge \
    --subnet=172.20.0.0/16 \
    --gateway=172.20.0.1 \
    mi-app-net

# Conectar contenedor a la red
docker network connect mi-app-net mi-app

# Inspeccionar configuración de red
docker network inspect mi-app-net

Errores comunes y cómo solucionarlos

Problemas de permisos y acceso

Error de socket Docker

docker: Got permission denied while trying to connect to the Docker daemon socket

Causa: El usuario actual no tiene permisos para acceder al socket de Docker.

Solución detallada:

  • Agregar usuario al grupo docker:

    sudo usermod -aG docker $USER
    
  • Verificar permisos del socket:

    ls -l /var/run/docker.sock
    
  • Ajustar permisos si es necesario:

    sudo chmod 666 /var/run/docker.sock
    
  • Reiniciar el servicio:

    sudo systemctl restart docker
    

Problemas de red

Error de puertos en uso

Error response from daemon: driver failed programming external connectivity: Bind for 0.0.0.0:5000 failed: port is already allocated

Causa: El puerto está siendo utilizado por otro proceso o contenedor.

Solución detallada:

  • Identificar el proceso:

    # En Linux/macOS
    sudo lsof -i :5000
    # En Windows
    netstat -ano | findstr :5000
    
  • Liberar el puerto:

    # Terminar proceso (Linux/macOS)
    kill -9 $(lsof -t -i:5000)
    # Terminar proceso (Windows)
    taskkill /PID <PID> /F
    
  • Usar un puerto alternativo:

    docker run -d -p 5001:5000 mi-primera-app
    

Problemas de construcción

Error de caché en construcción

Step 5/10 : RUN pip install -r requirements.txt
ERROR: Could not find a version that satisfies the requirement

Causa: Caché desactualizado o problemas de conectividad.

Solución detallada:

  • Limpiar caché de pip dentro del Dockerfile:

    RUN pip install --no-cache-dir -r requirements.txt
    
  • Forzar reconstrucción sin caché:

    docker build --no-cache -t mi-primera-app .
    
  • Usar buildkit para mejor gestión de caché:

    DOCKER_BUILDKIT=1 docker build -t mi-primera-app .
    

Problemas de memoria

Error OOM (Out of Memory)

ERROR: java.lang.OutOfMemoryError: Java heap space

Causa: El contenedor está intentando usar más memoria de la disponible.

Solución detallada:

  • Verificar uso actual de memoria:

    docker stats --no-stream
    
  • Ajustar límites de memoria:

    docker run -d \
      --name mi-app \
      --memory="1g" \
      --memory-swap="2g" \
      mi-primera-app
    
  • Optimizar la aplicación:

    • Revisar memory leaks
    • Implementar pooling de conexiones
    • Ajustar garbage collection

Problemas de volúmenes

Error de permisos en volúmenes

ERROR: for web  Cannot start service web: error while mounting volume

Causa: Permisos incorrectos en el sistema de archivos host.

Solución detallada:

  • Verificar permisos:

    ls -la /path/to/volume
    
  • Ajustar permisos en el host:

    sudo chown -R 1000:1000 /path/to/volume
    
  • Usar la opción de montaje correcta:

    docker run -v /host/path:/container/path:Z mi-primera-app
    

Problemas de networking

Error de DNS

ERROR: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io

Causa: Problemas de resolución DNS o conectividad.

Solución detallada:

Verificar configuración DNS:

docker run busybox nslookup google.com
  • Configurar DNS alternativos:

    {
      "dns": ["8.8.8.8", "8.8.4.4"]
    }
    
  • Reiniciar el daemon:

    sudo systemctl restart docker
    

Así como estas problemáticas que se mostraron, de seguro en el caminar usando Docker, aparecerán aún más, sin embargo, cada tropiezo solamente es una oportunidad más de aprender a pasar los obstáculos, aprender de los errores y dar ese salto a experto.

Igualmente, esto no va de que, si eres alguien que comienza a aprender o alguien experimentado, va de utilizar las herramientas y proveer soluciones que marquen la diferencia y en cualquier etapa en la que te encuentres, seguro lo podrás hacer siempre y cuando tomes decisiones como éstas, óptimas y seguras.

Construye interfaces de usuarios personalizadas y atractivas
Lleva la formación de tu equipo al siguiente nivel con cursos, talleres y laboratorios prácticos de JavaScript, React, Angular, HTML, CSS y más.
Solicitar más información

Conclusiones

La creación de imágenes y contenedores Docker es una habilidad fundamental en el desarrollo moderno de software. A través de este artículo, hemos aprendido desde los conceptos básicos hasta técnicas avanzadas de gestión y solución de problemas.

Para profundizar en estos conceptos y convertirte en un experto en Docker, te invito a explorar nuestro Curso de introducción a Docker, donde aprenderás técnicas avanzadas y mejores prácticas para el desarrollo profesional con contenedores.

Bombilla

Lo que deberías recordar de crear una imagen y un contenedor Docker

  • Planificación es clave: Un buen Dockerfile y estructura de proyecto son fundamentales.
  • Optimización continua: Monitorea y ajusta según las necesidades.
  • Seguridad primero: Usa imágenes oficiales y mantén todo actualizado.
  • Documentación clara: Mantén un README actualizado y documenta decisiones importantes.
  • Automatización: Implementa CI/CD para construcción y despliegue.
Compartir este post

También te puede interesar

Curso

Docker para desarrolladores

Principiante
4 h. y 4 min.

El objetivo de esta formación es ofrecer una comprensión integral sobre Docker, empezando por sus fundamentos básicos. Aprenderemos...

Ronald Cuzco
4.4