Juan Diego Andrés PRADA··RAMÍREZ Entrar
Lección 5 de 7

Docker básico

Tu proyecto ya es reproducible con venv y requirements.txt, y vive en GitHub. Pero "reproducible en mi Python" no es lo mismo que "reproducible en cualquier máquina, con todo incluido". Esa garantía total la da Docker. En este módulo escribimos el Dockerfile del PROYECTO FINAL: la receta que empaqueta tu aplicación —Python, dependencias y código— en una imagen que corre igual en tu portátil, en el de tu compañero y en un servidor.

¿Qué es?

Docker es una herramienta para empaquetar una aplicación junto con todo lo que necesita para ejecutarse —el sistema base, Python, las librerías y tu código— en una unidad portátil y aislada llamada contenedor (container).

La diferencia con un entorno virtual es de alcance. El venv aísla solo las librerías de Python, pero depende del Python y del sistema operativo que ya tengas instalados. Docker aísla todo el entorno: empaqueta hasta la versión exacta de Python y las dependencias del sistema. Por eso elimina de raíz el "en mi máquina funciona".

¿Cómo funciona?

Hay dos conceptos que no debes confundir:

  • Una imagen (image) es la plantilla: un paquete inmutable que contiene el sistema, Python, tus dependencias y tu código. Es como la receta o el molde.
  • Un contenedor (container) es una instancia en ejecución de una imagen. Es como el plato cocinado a partir de la receta. De una misma imagen puedes lanzar muchos contenedores idénticos.

La imagen se construye a partir de un Dockerfile: un archivo de texto con instrucciones paso a paso (qué base usar, qué copiar, qué instalar, qué comando ejecutar). Docker lee ese archivo de arriba abajo y construye la imagen capa por capa.

¿Para qué sirve?

  • Portabilidad total: corre igual en cualquier máquina con Docker, sin instalar nada más.
  • Aislamiento completo: incluye el SO base y las dependencias del sistema, no solo las de Python.
  • Despliegue: es el estándar para llevar aplicaciones a producción y a la nube.
  • Onboarding instantáneo: un nuevo integrante levanta el proyecto con un comando, sin pelear con versiones.

Construyamos esta pieza del proyecto

Paso 1: ten lista la aplicación

Partimos del app.py del proyecto. Para que el contenedor tenga algo claro que ejecutar, usemos un script sencillo. Crea o ajusta app.py:

import requests

def main():
 print("Entorno pro empaquetado con Docker")
 print("requests está disponible:", requests.__version__)

if __name__ == "__main__":
 main()

Asegúrate de que requests esté en tu requirements.txt (lo congelamos en el primer módulo).

Paso 2: escribe el Dockerfile

Crea un archivo llamado exactamente Dockerfile (sin extensión) en la raíz del proyecto:

# Imagen base: Python 3.12 en su variante ligera "slim"
FROM python:3.12-slim

# Carpeta de trabajo dentro del contenedor
WORKDIR /app

# Copiamos primero solo requirements para aprovechar la caché de capas
COPY requirements.txt .

# Instalamos dependencias (--no-cache-dir mantiene la imagen pequeña)
RUN pip install --no-cache-dir -r requirements.txt

# Ahora copiamos el resto del código
COPY . .

# Comando que se ejecuta al arrancar el contenedor
CMD ["python", "app.py"]

Repasemos cada instrucción:

  • FROM: la imagen base sobre la que construyes. python:3.12-slim ya trae Python instalado y es ligera.
  • WORKDIR: fija la carpeta de trabajo dentro del contenedor; los comandos siguientes corren ahí.
  • COPY: copia archivos de tu máquina al contenedor.
  • RUN: ejecuta un comando durante la construcción de la imagen (aquí, instalar dependencias).
  • CMD: el comando que se ejecuta cuando arrancas el contenedor.

Copiamos requirements.txt antes que el resto del código a propósito. Docker cachea cada capa; si solo cambias tu código pero no las dependencias, reaprovecha la capa de instalación y reconstruye en segundos.

Paso 3: añade un .dockerignore

Igual que .gitignore, evita meter basura en la imagen. Crea .dockerignore:

.venv/
__pycache__/
*.pyc
.git/
.env

Si copias .venv dentro de la imagen, no solo la inflas: puedes romperla, porque ese entorno se creó para tu sistema, no para el del contenedor. Por eso lo ignoramos.

Paso 4: construye la imagen

El comando docker build lee el Dockerfile y construye la imagen. El -t le pone una etiqueta (nombre) y el punto indica "el Dockerfile está en esta carpeta":

docker build -t mi-entorno-pro .

Verás cómo Docker ejecuta cada instrucción. Confirma que la imagen quedó creada:

docker images

Paso 5: ejecuta el contenedor

Lanza un contenedor a partir de la imagen:

docker run --rm mi-entorno-pro

Deberías ver la salida de tu app.py. El flag --rm borra el contenedor al terminar, para no acumular contenedores muertos.

Tech English: to build an image es "construir una imagen"; to run a container es "ejecutar un contenedor". Slim describe una variante reducida de la imagen base.

Paso 6: comandos de mantenimiento

docker ps -a # lista contenedores (también los detenidos)
docker images # lista imágenes
docker rmi mi-entorno-pro # borra una imagen

Error frecuente: olvidar el punto final en docker build -t nombre .. Ese punto es el contexto de construcción (la carpeta que Docker enviará). Sin él, el comando falla.

Con esto, el PROYECTO FINAL ya es totalmente portátil: cualquiera con Docker lo construye y lo ejecuta sin instalar Python ni dependencias a mano.

Ejercicios

  1. Añade a app.py una segunda línea que imprima la fecha y hora actuales (usa datetime). Reconstruye la imagen con docker build y ejecuta el contenedor. Observa en la salida del build cuáles capas se reaprovecharon de la caché y cuáles se reconstruyeron.
  2. Cambia la imagen base de python:3.12-slim a python:3.11-slim, reconstruye y ejecuta. Comprueba que el proyecto corre igual con otra versión de Python. Explica en una frase por qué Docker te permite hacer esto sin tocar el Python de tu máquina.
Tu progreso se guarda en este navegador. Inicia sesión para guardarlo en tu cuenta y verlo desde cualquier dispositivo.