Al desplegar aplicaciones de Python en un entorno de Docker, a menudo se experimenta que el tiempo de construcción de la imagen es excesivamente largo o que la construcción falla debido a problemas de dependencia del compilador, como gcc. Una de las soluciones más efectivas en este caso es utilizar Python Wheel.

En este artículo, exploraremos el concepto y las ventajas de Python Wheel, y cómo optimizar el proceso de construcción utilizando esto en un Dockerfile.


1. ¿Qué es Python Wheel?



Wheel (.whl) es el formato de distribución binaria (Built Distribution) de Python.

Generalmente, los paquetes de Python se distribuyen en dos formas.

  1. Distribución de Fuente (sdist, .tar.gz): en forma de código fuente. El proceso de compilación (Build) es necesario en la computadora del usuario durante la instalación.

  2. Distribución Constructiva (bdist_wheel, .whl): en forma de binario precompilado. La instalación se completa simplemente copiando archivos sin necesidad de compilación adicional.

Para entenderlo fácilmente, la distribución de fuente es como 'muebles que necesitan ser ensamblados' y Wheel es como 'muebles ya listos'. Usar Wheel significa que no necesitará tiempo para el ensamblaje ni herramientas (compilador).


2. Diferencias con pip install regular

Cuando ejecutamos el comando pip install <package>, internamente funciona en el siguiente orden de prioridad.

  1. Si existe un archivo Wheel: descarga ese binario e instala de inmediato. (muy rápido)

  2. Si no existe un archivo Wheel: descarga el archivo fuente (tar.gz) y realiza la compilación (Build) en el entorno local antes de instalarlo. (lento, se requiere herramienta de compilación)

Resumen de diferencias

Clasificación Distribución de Fuente (sdist) Wheel (whl)
Extensión .tar.gz, .zip .whl
Proceso de instalación Descarga -> Compilación -> Instalación Descarga -> Instalación
Velocidad de instalación Lento (requiere tiempo de compilación) Muy rápido
Herramientas necesarias Compilador (gcc, g++, archivos de encabezado, etc.) Ninguna (solo se necesita pip)
Dependencia del SO Depende del entorno en el momento de la compilación Dependiente del OS/arquitextura construida

3. Razones para usar Wheel en Dockerfile (ventajas)



Utilizar Wheel en un entorno Docker, especialmente en Multi-stage Build, ofrece las siguientes ventajas claras.

  1. Mejora drástica de la velocidad de construcción: no es necesario compilar constantemente bibliotecas pesadas escritas en C/C++, como pandas o numpy.

  2. Reducir tamaño de la imagen: La imagen de ejecución final (Runtime Image) no necesita incluir herramientas pesadas de compilación como gcc o build-essential.

  3. Seguridad: Previene la ruptura de la construcción debido a problemas de red o fallas temporales en repositorios externos y permite el uso de archivos previamente construidos localmente.


4. Cómo escribir y usar Dockerfile

La construcción de Docker utilizando Wheel se lleva a cabo principalmente creando archivos Wheel en la etapa Builder y luego instalándolos en la etapa Final.

Ejemplo: Dockerfile utilizando Multi-stage Build

A continuación, se presenta un patrón para instalar eficientemente un paquete con dependencias de bibliotecas C.

# [Stage 1] Builder: Creación del archivo Wheel
FROM python:3.9-slim as builder

# Instalación de paquetes necesarios para la compilación (no incluidos en la imagen final)
RUN apt-get update && apt-get install -y \
    build-essential \
    gcc \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Copiar requirements.txt
COPY requirements.txt .

# Generar archivos .whl en el directorio /wheels usando el comando pip wheel
# -w: especifica la ruta para guardar el archivo wheel
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt


# [Stage 2] Final: Imagen de ejecución
FROM python:3.9-slim

WORKDIR /app

# Copiar solo los archivos Wheel generados en la etapa Builder
COPY --from=builder /app/wheels /wheels
COPY --from=builder /app/requirements.txt .

# Instalar paquetes utilizando el archivo Wheel
# --no-index: ignora el índice de PyPI y busca solo archivos locales
# --find-links: especifica la ruta donde buscar paquetes para instalar
RUN pip install --no-cache --no-index --find-links=/wheels -r requirements.txt \
    && rm -rf /wheels

# Copiar el código de la aplicación
COPY . .

CMD ["python", "main.py"]

Explicación de comandos clave

  • pip wheel: genera un archivo .whl correspondiente al entorno actual y lo guarda en el directorio especificado sin instalar paquetes.

  • --wheel-dir: ubicación donde se guardará el archivo Wheel generado.

  • --find-links=/wheels: instruye que se busquen los paquetes en la ruta local especificada en lugar de descargarlos desde el servidor PyPI (internet).


Conclusión

Utilizar Python Wheel durante la construcción de Docker es más una técnica de optimización necesaria que una opción. Especialmente en entornos donde se producen construcciones repetitivas en una pipeline CI/CD, simplemente reducir el tiempo de construcción y el tamaño de la imagen puede resultar en un considerable ahorro de costos.

Si en tu Dockerfile actual está el proceso de instalación de gcc, considera cambiar a una construcción multi-estadio utilizando Wheel.

imagen-concepto-python-wheel