Cátedra de Sistemas Operativos

Trabajo Práctico N°2: Contenerización con Docker y API REST

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.

1. Presentación del Trabajo Práctico

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:

ArchivoResponsabilidad
app.pyAPI REST en Python/Flask. Procesa los parámetros y calcula el SHA-256.
DockerfileReceta de construcción de la imagen: Ubuntu + Python + Flask + la app.
index_tp2.htmlEsta página: documentación y cliente interactivo de la API.

2. Prueba tu 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.

// La respuesta aparecerá aquí...

3. ¿Qué es un contenedor Docker?

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.

Conceptos clave

¿Por qué usamos una imagen base de Ubuntu?

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.

4. El Dockerfile, línea por línea

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ónQué 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.

5. ¿Cómo funciona app.py?

Flujo de una petición

  1. Recepción: el cliente (esta página, curl, Postman) envía una petición GET /api/hash?nombre=Juan&apellido=Perez o un POST con JSON.
  2. Ruteo: el decorador @app.route('/api/hash', methods=['GET','POST']) indica a Flask qué función debe atender esa URL.
  3. Extracción de parámetros: en GET se leen con request.args.get(...) (query string); en POST se leen del cuerpo JSON con request.get_json().
  4. Validación: si falta algún parámetro se responde con 400 Bad Request y un mensaje de error.
  5. Concatenación: texto = f"{nombre}{apellido}".
  6. Hash: 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.
  7. Respuesta: jsonify(...) serializa el diccionario a JSON con código 200 OK:
{
  "nombre": "Juan",
  "apellido": "Perez",
  "texto_concatenado": "JuanPerez",
  "algoritmo": "SHA-256",
  "hash": "..."
}

Detalle importante: 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.

6. Instrucciones de compilación y ejecución

Paso 1 — Construir la imagen

Desde la carpeta del proyecto (donde están Dockerfile y app.py):

docker build -t tp2-so .

Paso 2 — Ejecutar el contenedor

docker run -p 5000:5000 --name tp2-contenedor tp2-so

Paso 3 — Probar la API

# 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\"}"

Comandos útiles de administración

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

7. Conclusión

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.

8. Entregables

Qué tenés que entregar

Informe en PDF que incluya:

Publicación y cierre

Además del informe

Se debe entregar el código fuente completo (carpeta del proyecto comprimida en .zip o enlace a un repositorio Git).

Entrega por mail

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.

9. Evaluación

Rúbrica orientativa

CriterioPuntos
Parte A completa y respondida correctamente10
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, conclusiones10
Total100

10. Descargar los archivos del proyecto

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.