Empaquetamos una API REST en Python dentro de un contenedor Docker basado en Ubuntu, aprendiendo en el camino qué son los contenedores, las imágenes y cómo se construyen.
En este TP construimos una API REST en Python (Flask) que recibe un nombre y un apellido, los concatena y devuelve su hash criptográfico SHA-256 en formato JSON. Luego la contenerizamos con Docker usando una imagen base de Ubuntu, de modo que pueda ejecutarse de forma idéntica en cualquier máquina que tenga Docker instalado.
Archivos del proyecto:
| Archivo | Responsabilidad |
|---|---|
app.py | API REST en Python/Flask. Procesa los parámetros y calcula el SHA-256. |
Dockerfile | Receta de construcción de la imagen: Ubuntu + Python + Flask + la app. |
index_tp2.html | Esta página: documentación y cliente interactivo de la API. |
Asegurate primero de tener el contenedor corriendo
(docker run -p 5000:5000 tp2-so). Ingresá los datos y presioná
Generar Hash: la página enviará una petición HTTP a la API del contenedor.
Un contenedor es un proceso aislado que corre sobre el kernel del sistema operativo anfitrión, pero con su propio sistema de archivos, variables de entorno, red y espacio de procesos. A diferencia de una máquina virtual, no incluye un sistema operativo completo ni un hipervisor: comparte el núcleo (kernel) del host, lo que los hace livianos y de arranque casi instantáneo.
Porque necesitamos un entorno con sistema operativo completo para instalar
python3 y pip manualmente con
apt-get, lo que fuerza a practicar la administración de paquetes
dentro del contenedor (en lugar de usar una imagen python:*
prearmada que "esconde" ese paso didáctico). Ubuntu 22.04 LTS es estable, ampliamente
documentado y familiar para la cátedra.
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive PYTHONUNBUFFERED=1
RUN apt-get update && \
apt-get install -y --no-install-recommends python3 python3-pip && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY app.py /app/
RUN pip3 install --no-cache-dir flask
EXPOSE 5000
CMD ["python3", "app.py"]
| Instrucción | Qué hace |
|---|---|
FROM ubuntu:22.04 |
Define la imagen base: Ubuntu 22.04 LTS descargada de Docker Hub. |
ENV ... |
Variables de entorno: noninteractive evita que apt haga
preguntas durante el build; PYTHONUNBUFFERED muestra los
logs de Python en tiempo real. |
RUN apt-get update && ... |
Actualiza los repositorios de paquetes e instala Python 3 y pip. Luego borra la caché de apt para achicar la imagen final. |
WORKDIR /app |
Establece el directorio de trabajo dentro del contenedor. |
COPY app.py /app/ |
Copia el código de la app desde el host hacia el contenedor. |
RUN pip3 install ... flask |
Instala Flask, la dependencia Python de la aplicación. |
EXPOSE 5000 |
Documenta que la app escucha en el puerto 5000 (la publicación real se hace con
-p al correr). |
CMD ["python3", "app.py"] |
Proceso que se ejecuta al iniciar el contenedor: arranca el servidor Flask. |
app.py?GET /api/hash?nombre=Juan&apellido=Perez
o un POST con JSON.@app.route('/api/hash', methods=['GET','POST']) indica a Flask
qué función debe atender esa URL.request.args.get(...) (query string); en POST se leen del cuerpo
JSON con request.get_json().400 Bad Request y un mensaje de error.texto = f"{nombre}{apellido}".hashlib.sha256(texto.encode('utf-8')).hexdigest().
SHA-256 recibe bytes y devuelve 64 caracteres hexadecimales (256 bits). Es
determinista (mismo input → mismo hash) e irreversible.jsonify(...) serializa el
diccionario a JSON con código 200 OK:{
"nombre": "Juan",
"apellido": "Perez",
"texto_concatenado": "JuanPerez",
"algoritmo": "SHA-256",
"hash": "..."
}
host='0.0.0.0'Flask escucha con app.run(host='0.0.0.0', port=5000).
Esto hace que acepte conexiones desde todas las interfaces de red del contenedor.
Si escuchara solo en 127.0.0.1, el servidor sería inalcanzable
desde el host, porque en Docker el "localhost" del contenedor no es el localhost de tu PC.
Desde la carpeta del proyecto (donde están Dockerfile y
app.py):
docker build -t tp2-so .
-t tp2-so: etiqueta (nombre) que le damos a la imagen..: contexto de build (el directorio actual).docker run -p 5000:5000 --name tp2-contenedor tp2-so
-p 5000:5000: mapea el puerto 5000 del host al 5000 del contenedor.--name tp2-contenedor: nombre asignado al contenedor.# Desde el navegador o curl (GET):
curl "http://localhost:5000/api/hash?nombre=Juan&apellido=Perez"
# POST con JSON:
curl -X POST http://localhost:5000/api/hash \
-H "Content-Type: application/json" \
-d "{\"nombre\":\"Juan\",\"apellido\":\"Perez\"}"
docker ps # ver contenedores en ejecución docker logs tp2-contenedor # ver los logs de la app docker stop tp2-contenedor # detener el contenedor docker rm tp2-contenedor # eliminar el contenedor docker images # listar imágenes locales
Con este TP comprobamos cómo Docker resuelve el clásico problema de "en mi máquina funciona": la imagen empaqueta sistema operativo, intérprete, dependencias y código en una unidad portable y reproducible. Además, comprendimos su relación directa con conceptos de Sistemas Operativos: procesos aislados mediante namespaces, control de recursos con cgroups, sistemas de archivos en capas y administración de paquetes en Linux.
Informe en PDF que incluya:
Dockerfile,
docker-compose.yml, index.html y
style.css.docker ps y docker images.docker pull + docker run),
el puerto y la URL donde se visualizará el sitio.Se debe entregar el código fuente completo (carpeta del proyecto comprimida en
.zip o enlace a un repositorio Git).
Enviar el informe en PDF y el código fuente (comprimido en .zip o
enlace al repositorio Git) por correo electrónico a:
coordi.tecnicatura@uccuyo.edu.ar
Colocar en el asunto del correo: [SO] TP Contenedores — Apellido, Nombre.
| Criterio | Puntos |
|---|---|
| Parte A completa y respondida correctamente | 10 |
| Dockerfile funcional y bien construido (Parte B) | 20 |
| Sitio web desplegado correctamente con volumen (Parte B.7) | 15 |
| Docker Compose funcional con dos servicios (Parte C) | 15 |
| Buenas prácticas: .dockerignore, imagen liviana, limpieza final (Parte D) | 10 |
| Publicación en Docker Hub y verificación de pull + run por parte del profesor (Parte E) | 20 |
| Informe: claridad, capturas, conclusiones | 10 |
| Total | 100 |
Descargá el código fuente del TP directamente desde esta página con un clic:
Guardá los tres archivos en una misma carpeta, luego ejecutá
docker build -t tp2-so . y
docker run -p 5000:5000 tp2-so.
El botón Descargar index_tp2.html descarga una copia exacta de esta misma página,
incluyendo la demo interactiva y los botones de descarga.