Hopp til innhold

Docker - Construir una imagen con un archivo Dockerfile

Skip to content

Este es un texto traducido por máquina que puede contener errores.

Crear una imagen con un Dockerfile

Aquí se crea una imagen a partir de una aplicación Flask y se prueba con docker run. Estará completo cuando la application responda y haya verificado que el archivo local .env se mantenga fuera de la nueva imagen. La aplicación de pruebas no requiere ni GitHub ni una API externa.

Antes de construir

Deberás construir una imagen y demostrar que un contenedor a partir de dicha imagen responde. Necesitas Docker instalado y debes saber cómo iniciar e inspeccionar un contenedor, como se muestra en Ejecutar e inspeccionar un contenedor. Si no tienes ninguna aplicación Flask, utiliza la aplicación de prueba siguiente. Trabaja en el directorio del proyecto en la máquina virtual Linux, donde se encuentran tanto app.py como cualquier plantilla u otro archivo del proyecto.

Si el proyecto está en un repositorio de código, Git en la terminal te mostrará cómo clonarlo en la VM. También puedes crear los archivos en el editor de texto de la VM. Usa pwd y ls para comprobar si estás en el directorio correcto. No construyas desde una carpeta vacía ni desde la Shell del host Proxmox.

Primero prueba con una pequeña aplicación de prueba

Si aún no has llevado tu aplicación a la máquina virtual, puedes practicar el Dockerfile con una aplicación mínima. Crea un directorio con mkdir min-app y cd min-app, y crea app.py con nano:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def index():
    return "¡Hola desde el contenedor!"

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

Luego, crea requirements.txt y Dockerfile como se muestra a continuación. Cuando la compilación funcione, haz lo mismo con tu propia aplicación.

Cree el archivo requirements.txt en la misma carpeta. Este lista los paquetes de Python que deben instalarse en la imagen. Para la aplicación sencilla basada en Flask 1, que solo utiliza Flask, el contenido es:

Flask

Si la aplicación utiliza otras bibliotecas de terceros, también deben estar enumeradas allí con sus nombres de paquete correctos, por ejemplo, requests. Los archivos como .venv no se copian para instalar los paquetes; Docker los instala nuevamente a partir de esta lista. Las versiones pueden fijarse, por ejemplo con nombre_del_paquete==version, una vez que hayas verificado qué versiones utiliza la aplicación.

Crea también un archivo .dockerignore antes del primer build. Esto evita que las credenciales locales, el historial de Git y el entorno local de Python se copien en la imagen:

The provided input contains no comments (lines starting with #), so there is nothing to translate. The content remains unchanged as per your instructions.

.env
.git
__pycache__/
.venv/
app-data/

Agrega también .env en .gitignore si usas Git. Si los archivos de ignoración ya contienen contenido previo, agrega las reglas faltantes en lugar de reemplazarlos. Usa [[Git in the terminal Level 5 - gitignore y secretos|.gitignore y secretos]] para verificar el seguimiento antes de compartir código.

Crea una imagen con un archivo Dockerfile

Un archivo Dockerfile y el código fuente se utilizan para construir una imagen. A continuación, se crea e inicia un contenedor a partir de la imagen.

docker build genera el paquete. docker run crea e inicia un contenedor a partir del paquete. La construcción por sí sola no inicia la aplicación. Consulta [[Nivel 0 de Docker - ¿Qué es Docker?|Nivel 0]] si necesitas distinguir nuevamente entre imagen y contenedor.

Un Dockerfile describe los pasos que Docker debe utilizar para construir una imagen. Cada línea realiza algo específico:

# FROM python:3.12-slim
#
# WORKDIR /app
# COPY requirements.txt .
# RUN pip install --no-cache-dir -r requirements.txt
#
# COPY . .
# EXPOSE 5000
# CMD ["python", "app.py"]

Docker ejecuta la compilación por pasos. COPY y RUN pueden agregar capas del sistema de archivos, mientras que, entre otros, CMD describe cómo debe iniciarse el contenedor. Docker puede reutilizar resultados de compilaciones anteriores desde una caché de construcción. Cuando un paso debe recompilarse, los pasos posteriores también deben ejecutarse nuevamente.

Por lo tanto, copiamos requirements.txt por separado antes de COPY . .: la instalación que requiere más tiempo se realiza antes del código fuente, que cambia con frecuencia:

flowchart TB
    L1["Imagen base: python:3.12-slim"] --> L2["Directorio de trabajo: /app"]
    L2 --> L3["Copiar requirements.txt"]
    L3 --> L4["Instalar los paquetes con pip"]
    L4 --> L5["Copiar el código fuente"]
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

Si se modifica requirements.txt, Docker debe reinstalar los paquetes. Esto es deseable: el nuevo paquete debe incluirse realmente en la imagen. Si solo cambia el código fuente, Docker puede usar la capa de instalación ya completada y continuar construyendo desde COPY . ..

Cuando Docker publica un puerto, reenvía el tráfico al programa dentro del contenedor. Por lo tanto, el programa debe escuchar en la red del contenedor, no solo en 127.0.0.1, que significa “este contenedor”. Si el programa solo escucha en 127.0.0.1, otras máquinas no podrán acceder a él a través del puerto de Docker.

Ejemplo de Flask

Flask debe escuchar en todas las interfaces de red (0.0.0.0) cuando se ejecuta en un contenedor. 0.0.0.0 significa que Flask acepta solicitudes en todas las tarjetas de red dentro del contenedor. Reemplace el bloque de inicio existente en app.py con lo siguiente:

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=False)

Esto es una configuración de práctica con el servidor de desarrollo de Flask. Antes de que la solución se use en producción, debe ejecutarse con un servidor WSGI adecuado; consulte Flask: configuración para producción.

EXPOSE 5000 describe qué puerto utiliza la aplicación; no publica el puerto por sí solo. Eso lo hace -p 127.0.0.1:5000:5000 en el comando siguiente. Construye e inicia:

docker build -t min-app:latest .
docker run -d --name min-app -p 127.0.0.1:5000:5000 min-app:latest
docker logs -f min-app

Pulse Ctrl+C para detener la visualización del registro. El contenedor continúa ejecutándose.

Prueba desde el propio equipo virtual:

curl http://127.0.0.1:5000

Deberás obtener el contenido de la ruta principal de la aplicación. En -p 127.0.0.1:5000:5000, 127.0.0.1:5000 significa el puerto 5000 del servidor, pero solo para los programas dentro del propio servidor. El último número es el puerto dentro del contenedor. Si no funciona, primero comprueba docker ps, los registros y que el puerto esté publicado correctamente.

Con 127.0.0.1 al principio, el puerto está cerrado hacia la red, por lo que ninguna otra máquina puede acceder a la aplicación mientras la desarrollas y pruebas. Es un estándar seguro para una aplicación en desarrollo. Sin 127.0.0.1 (-p 5000:5000), el puerto escucha en todas las interfaces de red del servidor. Solo necesitarás esto cuando otra máquina o un proxy deba acceder a la aplicación, en [[Docker Nivel 3 - Publicar aplicaciones|Nivel 3]].

Punto de control: La imagen propia funciona

curl http://127.0.0.1:5000 debe mostrar la página principal de la aplicación. Para la aplicación de prueba, la respuesta es ¡Hola desde el contenedor!. Explica lo que creó docker build y qué inició docker run. En caso de error, lee los registros antes de continuar.

Verifica que .env se mantenga fuera de la versión

No necesitas una clave real para verificar esto. Si el proyecto aún no tiene un archivo .env, puedes crearlo con PIGGY_TEST=valor_prueba_seguro. Conserva cualquier archivo existente; no sobrescribas tus valores.

  1. Asegúrate de que .env esté presente tanto en .dockerignore como en .gitignore.
  2. Si usas Git, ejecuta las verificaciones en [[Git in the terminal Level 5 - gitignore and secrets|el ejercicio de .gitignore]]. Un archivo ignorado tampoco debe estar siendo rastreado previamente.
  3. Vuelve a construir la imagen y verifica esta ruta de archivo sin imprimir su contenido:
# docker bygger bildet med tagget "min-app:latest" fra det gjeldende katalogen
docker build -t min-app:latest .
# docker kjører containeren fjerne deretter, og kontrollerer at filen "/app/.env" ikke eksisterer; hvis den ikke gjør det, vises meldingen om at den mangler
docker run --rm --entrypoint sh min-app:latest -c 'test ! -e /app/.env && echo ".env finnes ikke i /app"'

El resultado esperado es que el archivo .env no existe en /app. Si el mensaje no aparece, revise el archivo de exclusión antes de compartir la imagen. Esto verifica la ruta del archivo dentro del sistema de archivos terminado de la nueva imagen. No actualiza imágenes antiguas, otros archivos secretos ni valores escritos directamente en el código o en el Dockerfile. Reemplace primero una clave real si la anterior se ha compartido.

Si la construcción o la aplicación falla

En caso de ModuleNotFoundError, comprueba requirements.txt y vuelve a compilar. Si hay errores al descargar la imagen base o los paquetes de Python, prueba la red con [[Método de depuración Nivel 1 - Depuración sistemática|Método de depuración]]. En caso de falta de respuesta HTTP, lee docker logs min-aplicacion y verifica la dirección de Flask y el mapeo de puertos.

Siguiente paso

Muestra la respuesta de la aplicación y el control del archivo .env. Explica lo que describe el Dockerfile, lo que genera la compilación y qué inicia docker run. Continúa con [[Docker Level 3 - Publisar aplicacion|Docker - Publicar aplicación]]. Si deseas describir el inicio y la actualización en un archivo Compose, [[App con Compose Nivel 1 - Ejecutar y actualizar la app|Ejecuta y actualiza la app con Compose]] es una profundización opcional.



Compose y la actualización están ahora en [[App con Compose Nivel 1 - Ejecutar y actualizar la app|Ejecuta y actualiza la app con Compose]].


El almacenamiento se explica en [[UsoDeContenedores Nivel 2 - Conservar datos fuera del contenedor|Conserva los datos fuera del contenedor]]; la aplicación de Compose está en [[App con Compose Nivel 1 - Ejecutar y actualizar la app|Ejecuta y actualiza la app con Compose]].


La especificación de API está ahora en [[App con Compose Nivel 2 - Variable de medio y clave de API|Variable de entorno y clave de API]] y es opcional.