Dockerfile respectivospython3.12 , latest (Dockerfile)python3.11 , (Dockerfile)python3.10 (Dockerfile)python3.9 , (Dockerfile) Estas etiquetas ya no son compatibles o mantenidas, se eliminan del repositorio de GitHub, pero las últimas versiones empujadas aún podrían estar disponibles en Docker Hub si alguien las ha estado tirando:
python3.8python3.8-alpinepython3.7python3.6python2.7Las últimas etiquetas de fecha para estas versiones son:
python3.8-2024-10-28python3.8-alpine-2024-03-11python3.7-2024-10-28python3.6-2022-11-25python2.7-2022-11-25 Nota : Hay etiquetas para cada fecha de compilación. Si necesita "fijar" la versión de imagen de Docker que usa, puede seleccionar una de esas etiquetas. Por ejemplo, tiangolo/uwsgi-nginx-flask:python3.7-2019-10-14 .
Imagen de Docker con UWSGI y NGINX para aplicaciones web frascos en Python que se ejecutan en un solo contenedor.
Esta imagen de Docker le permite crear aplicaciones web frascos en Python que se ejecutan con UWSGI y NGINX en un solo contenedor.
La combinación de UWSGI con NGINX es una forma común de implementar aplicaciones web de Python Flask.
Si está comenzando un nuevo proyecto, es posible que desee probar Fastapi , que creé y donde paso la mayor parte de mi tiempo ahora. Tampoco necesita una imagen base personalizada, hay instrucciones en los documentos para construir su propio Dockerfile .
Repo de Github : https://github.com/tiangolo/uwsgi-nginx-flask-docker
Imagen de Docker Hub : https://hub.docker.com/r/tiangolo/uwsgi-nginx-flask/
Probablemente esté usando Kubernetes o herramientas similares. En ese caso, probablemente no necesite esta imagen (o ninguna otra imagen base similar ). Probablemente sea mejor construyendo una imagen de Docker desde cero .
Si tiene un clúster de máquinas con Kubernetes , Docker Swarm Mode, Nomad u otro sistema complejo similar para administrar contenedores distribuidos en múltiples máquinas, entonces probablemente desee manejar la replicación a nivel de clúster en lugar de usar un administrador de procesos en cada contenedor que inicia múltiples procesos de trabajadores , que es lo que hace esta imagen Docker.
En esos casos (por ejemplo, con Kubernetes), probablemente querrá construir una imagen Docker desde cero , instalar sus dependencias y ejecutar un solo proceso en lugar de esta imagen.
Por ejemplo, con Gunicorn, puede tener una app/gunicorn_conf.py con:
# Gunicorn config variables
loglevel = "info"
errorlog = "-" # stderr
accesslog = "-" # stdout
worker_tmp_dir = "/dev/shm"
graceful_timeout = 120
timeout = 120
keepalive = 5
threads = 3 Y luego podrías tener un Dockerfile con:
FROM python:3.12
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
CMD [ "gunicorn" , "--conf" , "app/gunicorn_conf.py" , "--bind" , "0.0.0.0:80" , "app.main:app" ]Puede leer más sobre estas ideas en la documentación de Fastapi sobre: Fastapi en contenedores: Docker, ya que las mismas ideas se aplicarían a otras aplicaciones web en contenedores.
Puede desear un administrador de procesos que ejecute múltiples procesos de trabajadores en el contenedor si su aplicación es lo suficientemente simple como para no necesitar (al menos aún no) para ajustar demasiado la cantidad de procesos, y puede usar un valor predeterminado automatizado, y la está ejecutando en un solo servidor , no un clúster.
Podría estar implementando en un solo servidor (no un clúster) con Docker Compose , por lo que no tendría una manera fácil de administrar la replicación de contenedores (con Docker Compose) mientras preserva la red compartida y el equilibrio de carga .
Luego, podría tener un solo contenedor con un administrador de procesos que inicie varios procesos de trabajadores en el interior, como lo hace esta imagen Docker.
También podría tener otras razones que facilitarían tener un solo contenedor con múltiples procesos en lugar de tener múltiples contenedores con un solo proceso en cada uno de ellos.
Por ejemplo (dependiendo de su configuración), podría tener alguna herramienta como un exportador de Prometheus en el mismo contenedor que debería tener acceso a cada una de las solicitudes que vienen.
En este caso, si tuviera múltiples contenedores , de forma predeterminada, cuando Prometheus llegó a leer las métricas , obtendría los que se encuentran para un solo contenedor cada vez (para el contenedor que manejaba esa solicitud en particular), en lugar de obtener las métricas acumuladas para todos los contenedores replicados.
Luego, en ese caso, podría ser más simple tener un contenedor con múltiples procesos y una herramienta local (por ejemplo, un exportador de Prometheus) en el mismo contenedor que recolecta métricas Prometheus para todos los procesos internos y expone esas métricas en ese contenedor único.
Lea más sobre todo en la documentación de Fastapi sobre: Fastapi en contenedores - Docker, ya que los mismos conceptos se aplican a otras aplicaciones web en contenedores.
No tienes que clonar este repositorio.
Puede usar esta imagen como imagen base para otras imágenes.
Suponiendo que tenga un archivo requirements.txt , podría tener un Dockerfile como este:
FROM tiangolo/uwsgi-nginx-flask:python3.12
COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
COPY ./app /appHay varias etiquetas de imagen disponibles, pero para nuevos proyectos debe usar la última versión disponible.
Esta imagen de Docker se basa en Tiangolo/UWSGI-NGINX . Esa imagen de Docker tiene UWSGI y NGINX instalados en el mismo contenedor y se hizo que fuera la base de esta imagen.
Dockerfile con: FROM tiangolo/uwsgi-nginx-flask:python3.12
COPY ./app /appapp e ingresarlomain.py (debe nombrarse así y debe estar en su directorio app ) con: from flask import Flask
app = Flask ( __name__ )
@ app . route ( "/" )
def hello ():
return "Hello World from Flask"
if __name__ == "__main__" :
# Only for debugging while developing
app . run ( host = '0.0.0.0' , debug = True , port = 80 ) El objeto de aplicación principal debe nombrarse app (en el código) como en este ejemplo.
Nota : La sección con la función main() es para fines de depuración. Para obtener más información, lea las instrucciones avanzadas a continuación.
.
├── app
│ └── main.py
└── Dockerfile
Dockerfile , que contiene su directorio app )docker build -t myimage .docker run -d --name mycontainer -p 80:80 myimage... y tiene un servidor de frascos optimizado en un contenedor Docker.
Debería poder verificarlo en la URL de su contenedor Docker, por ejemplo: http://192.168.99.100 o http://127.0.0.1
Si está construyendo aplicaciones modernas frontend (por ejemplo, reaccionar, angular), probablemente estaría compilando una versión moderna de JavaScript (ES2015, TypeScript, etc.) a una versión menos moderna y más compatible.
Si desea servir su código frontend (compilado) por el mismo contenedor de acoplador (frasco), tendría que copiar el código al contenedor después de compilarlo.
Eso significa que necesitaría tener todas las herramientas frontend instaladas en la máquina de construcción (podría ser su computadora, un servidor remoto, etc.).
Eso también significa que tendrías que, de alguna manera, recordar siempre compilar el código frontend justo antes de construir la imagen de Docker.
Y también podría significar que entonces podría agregar su código frontend compilado a su repositorio git (con suerte ya está usando GIT o aprender a usar git ).
Agregar su código compilado a Git es una muy mala idea por varias razones, algunas de ellas son:
Por estas razones, no se recomienda que sirva su código frontend del mismo contenedor Docker de backend (frasco).
Hay una alternativa mucho mejor para servir su código frontend del mismo contenedor de acoplador de backend (frasco).
Puede tener otro contenedor Docker con todas las herramientas frontend instaladas (node.js, etc.) que:
Para aprender los detalles de este proceso para la construcción de frontend en Docker, puede leer:
Después de tener un contenedor de backend (matraz) y un contenedor frontend, debe servirlos a ambos.
Y es posible que desee servirlos bajo el mismo dominio, bajo un camino diferente. Por ejemplo, la aplicación Backend (Flask) en la ruta /api y el frontend en la ruta "raíz" / .
Luego puede usar Traefik para manejar eso.
Y también puede generar automáticamente certificados HTTPS para su aplicación utilizando Let's Cifrypt. Todo gratis, en una configuración muy fácil.
Si desea utilizar esta alternativa, consulte los generadores de proyectos anteriores, todos usan esta idea.
En este escenario, tendrías 3 contenedores Docker:
Debería poder seguir las mismas instrucciones que en la sección " Quickstart " anterior, con algunas modificaciones menores:
app/ directorio, colóquelo en un directorio app/app/ .__init__.py dentro de esa app/app/ directorio.uwsgi.ini dentro de su app/ directorio (que se copia a /app/uwsgi.ini dentro del contenedor).uwsgi.ini , agregue: [uwsgi]
module = app.main
callable = app La explicación del uwsgi.ini es la siguiente:
app.main . Entonces, en la app de paquete ( /app/app ), obtenga el módulo main ( main.py ).app ( app = Flask(__name__) ).La estructura de su archivo se vería como:
.
├── app
│ ├── app
│ │ ├── __init__.py
│ │ ├── main.py
│ └── uwsgi.ini
└── Dockerfile
...en lugar de:
.
├── app
│ ├── main.py
└── Dockerfile
Si está utilizando archivos estáticos en el mismo contenedor, asegúrese de que la variable de entorno STATIC_PATH esté establecida en consecuencia, por ejemplo, para cambiar el valor predeterminado de /app/static a /app/app/static puede agregar esta línea a su Dockerfile :
ENV STATIC_PATH /app/app/static... Después de eso, todo debería funcionar como se esperaba. Todas las demás instrucciones se aplicarían normalmente.
.
├── app
│ ├── app
│ │ ├── api
│ │ │ ├── api.py
│ │ │ ├── endpoints
│ │ │ │ ├── __init__.py
│ │ │ │ └── user.py
│ │ │ ├── __init__.py
│ │ │ └── utils.py
│ │ ├── core
│ │ │ ├── app_setup.py
│ │ │ ├── database.py
│ │ │ └── __init__.py
│ │ ├── __init__.py
│ │ ├── main.py
│ │ └── models
│ │ ├── __init__.py
│ │ └── user.py
│ └── uwsgi.ini
└── Dockerfile
Asegúrese de seguir los documentos oficiales mientras importa sus módulos:
Por ejemplo, si está en app/app/main.py y desea importar el módulo en app/app/core/app_setup.py lo escribiría como:
from . core import app_setupo
from app . core import app_setupapp/app/api/endpoints/user.py y desea importar el objeto users desde app/app/core/database.py lo escribiría como: from ... core . database import userso
from app . core . database import users Puede personalizar varias cosas utilizando variables de entorno.
index.html directamenteAviso : esta técnica está en desuso, ya que puede crear varios problemas con los marcos modernos de frontend. Para los detalles y mejores alternativas, lea la sección anterior.
Configuración de la variable de entorno STATIC_INDEX para ser 1 Puede configurar Nginx para servir el archivo en la url /static/index.html cuando se solicite / .
Eso mejoraría la velocidad, ya que no involucraría a Uwsgi ni Python. Nginx serviría el archivo directamente. Para obtener más información, siga la sección anterior " QuickStart for Spas ".
Por ejemplo, para habilitarlo, puede agregar esto a su Dockerfile :
ENV STATIC_INDEX 1Por defecto, la imagen comienza con 2 procesos UWSGI en ejecución. Cuando el servidor está experimentando una carga alta, crea hasta 16 procesos UWSGI para manejarla a pedido.
Si necesita configurar estos números, puede usar variables de entorno.
El número inicial de procesos UWSGI está controlado por la variable UWSGI_CHEAPER , de forma predeterminada establecida en 2 .
El número máximo de procesos UWSGI está controlado por la variable UWSGI_PROCESSES , de forma predeterminada establecida en 16 .
Tenga en cuenta que UWSGI_CHEAPER debe ser más bajo que UWSGI_PROCESSES .
Entonces, si, por ejemplo, debe comenzar con 4 procesos y crecer hasta un máximo de 64, su Dockerfile podría parecer:
FROM tiangolo/uwsgi-nginx-flask:python3.12
ENV UWSGI_CHEAPER 4
ENV UWSGI_PROCESSES 64
COPY ./app /app Puede establecer un tamaño de archivo de carga máximo personalizado utilizando una variable de entorno NGINX_MAX_UPLOAD , por defecto, tiene un valor de 0 , que permite tamaños de archivo de carga ilimitados. Esto difiere del valor predeterminado de Nginx de 1 MB. Está configurado de esta manera porque esa es la experiencia más simple que esperaría un desarrollador inexperto en NGINX.
Por ejemplo, para tener un tamaño de archivo de carga máximo de 1 MB (predeterminado de NGINX) agregue una línea en su Dockerfile con:
ENV NGINX_MAX_UPLOAD 1mPor defecto, el contenedor hecho de esta imagen escuchará en el puerto 80.
Para cambiar este comportamiento, establezca la variable de entorno LISTEN_PORT . También es posible que deba crear la instrucción de Docker EXPOSE respectivo.
Puedes hacer eso en tu Dockerfile , se vería algo así como:
FROM tiangolo/uwsgi-nginx-flask:python3.12
ENV LISTEN_PORT 8080
EXPOSE 8080
COPY ./app /appuwsgi.ini Hay un archivo predeterminado en /app/uwsgi.ini con configuraciones específicas de la aplicación (además de las configuraciones globales uwsgi ).
Solo contiene:
[uwsgi]
module = main
callable = appmodule = main se refiere al archivo main.pycallable = app se refiere a la "aplicación" Flask , en la app variable. Puede personalizar uwsgi reemplazando ese archivo con el suyo, incluidas todas sus configuraciones.
Por ejemplo, para extender el predeterminado anterior y habilitar hilos, puede tener un archivo:
[uwsgi]
module = main
callable = app
enable-threads = trueuwsgi.ini Puede anular dónde la imagen debe buscar el archivo de la aplicación uwsgi.ini utilizando la variable de entorno UWSGI_INI .
Con eso, puede cambiar el directorio predeterminado de su aplicación desde /app a otra cosa, como /application .
Por ejemplo, para hacer que la imagen use el archivo en /application/uwsgi.ini , puede agregar esto a su Dockerfile :
ENV UWSGI_INI /application/uwsgi.ini
COPY ./application /application
WORKDIR /application Nota : El WORKDIR es importante, de lo contrario, UWSGI intentará ejecutar la aplicación en /app .
Nota : También tendría que configurar la ruta de archivos static , lea a continuación.
./static/ ruta Puede hacer que NGINX use una ruta de directorio personalizada con los archivos para servir directamente (sin tener UWSGI involucrado) con la variable de entorno STATIC_PATH .
Por ejemplo, para hacer que Nginx sirva el contenido estático usando los archivos en /app/custom_static/ puede agregar esto a su Dockerfile :
ENV STATIC_PATH /app/custom_static Luego, cuando el navegador solicitó un archivo, por ejemplo, http://example.com/static/index.html, Nginx respondería directamente usando un archivo en la ruta /app/custom_static/index.html .
Nota : También tendría que configurar Flask para usarlo como su directorio static .
Como otro ejemplo, si necesitara colocar su código de aplicación en un directorio diferente, podría configurar NGINX para servir esos archivos estáticos de ese directorio diferente.
Si necesitara tener sus archivos estáticos en /application/static/ podría agregar esto a su Dockerfile :
ENV STATIC_PATH /application/static/static También puede hacer que NGINX sirva los archivos estáticos en una URL diferente, para eso, puede usar la variable de entorno STATIC_URL .
Por ejemplo, si desea cambiar la URL /static a /content podría agregar esto a su Dockerfile :
ENV STATIC_URL /content Luego, cuando el navegador solicitó un archivo, por ejemplo, http://example.com/content/index.html, Nginx respondería directamente usando un archivo en la ruta /app/static/index.html .
/app/prestart.sh Si necesita ejecutar algo antes de comenzar la aplicación, puede agregar un archivo prestart.sh al directorio /app . La imagen detectará y ejecutará automáticamente antes de comenzar todo.
Por ejemplo, si desea agregar migraciones SQL alembic (con sqlalchemy), puede crear un archivo ./app/prestart.sh en su directorio de código (que será copiado por su Dockerfile ) con:
#! /usr/bin/env bash
# Let the DB start
sleep 10 ;
# Run migrations
alembic upgrade head Y esperaría 10 segundos para darle a la base de datos algo de tiempo para comenzar y luego ejecutar ese comando alembic .
Si necesita ejecutar un script de Python antes de comenzar la aplicación, puede hacer que el archivo /app/prestart.sh ejecute su script Python, con algo así como:
#! /usr/bin/env bash
# Run custom Python script before starting
python /app/my_custom_prestart_script.py Nota : La imagen usa source para ejecutar el script, por lo que, por ejemplo, persistirían las variables de entorno. Si no comprende la oración anterior, probablemente no la necesite.
Por defecto, NGINX iniciará un "proceso de trabajadores".
Si desea establecer un número diferente de procesos de trabajadores NGINX, puede usar la variable de entorno NGINX_WORKER_PROCESSES .
Puede usar un número único específico, por ejemplo:
ENV NGINX_WORKER_PROCESSES 2 O puede configurarlo en la palabra clave auto e intentará detectar automáticamente la cantidad de CPU disponibles y usarla para la cantidad de trabajadores.
Por ejemplo, usando auto , su Dockerfile podría verse como:
FROM tiangolo/uwsgi-nginx-flask:python3.12
ENV NGINX_WORKER_PROCESSES auto
COPY ./app /appPor defecto, NGINX comenzará con un límite máximo de 1024 conexiones por trabajador.
Si desea establecer un número diferente, puede usar la variable de entorno NGINX_WORKER_CONNECTIONS , por ejemplo:
ENV NGINX_WORKER_CONNECTIONS 2048No puede exceder el límite actual en el número máximo de archivos abiertos. Vea cómo configurarlo en la siguiente sección.
Las conexiones numéricas por trabajador NGINX no pueden exceder el límite en el número máximo de archivos abiertos.
Puede cambiar el límite de los archivos abiertos con la variable de entorno NGINX_WORKER_OPEN_FILES , por ejemplo:
ENV NGINX_WORKER_OPEN_FILES 2048 Si necesita configurar más a Nginx, puede agregar *.conf archivos a /etc/nginx/conf.d/ en su Dockerfile .
Solo tenga en cuenta que las configuraciones predeterminadas se crean durante el inicio en un archivo en /etc/nginx/conf.d/nginx.conf y /etc/nginx/conf.d/upload.conf . Entonces no debes sobrescribirlos. Debe nombrar su archivo *.conf con algo diferente a nginx.conf o upload.conf , por ejemplo: custom.conf .
Nota : Si está personalizando NGINX, tal vez copiando configuraciones de un blog o una respuesta de StackOverflow, tenga en cuenta que probablemente necesite usar las configuraciones específicas de UWSGI, en lugar de las de otros módulos, como por ejemplo, ngx_http_fastcgi_module .
Si necesita configurar NGINX aún más, anulando por completo los valores predeterminados, puede agregar una configuración NGINX personalizada a /app/nginx.conf .
Se copiará a /etc/nginx/nginx.conf y se usará en lugar del generado.
Tenga en cuenta que, en ese caso, esta imagen no generará ninguna de las configuraciones de Nginx, solo copiará y usará su archivo de configuración.
Eso significa que todas las variables de entorno descritas anteriormente que son específicas de Nginx no se utilizarán.
También significa que no usará configuraciones adicionales de archivos en /etc/nginx/conf.d/*.conf , a menos que tenga una sección explícitamente en su archivo personalizado /app/nginx.conf con:
include /etc/nginx/conf.d/*.conf;
Si desea agregar un archivo personalizado /app/nginx.conf pero no sabe dónde comenzar, puede usar el nginx.conf utilizado para las pruebas y personalizarlo o modificarlo más.
La combinación de UWSGI con NGINX es una forma común de implementar aplicaciones web de Python Flask.
Apenas:
Nginx es un servidor web, se encarga de las conexiones HTTP y también puede servir archivos estáticos directa y de manera más eficiente.
UWSGI es un servidor de aplicaciones, eso es lo que ejecuta su código Python y habla con Nginx.
Su código de Python tiene la aplicación web de frasco real y está ejecutado por UWSGI.
La imagen Tiangolo/UWSGI-NGINX aprovecha las imágenes de Docker delgadas y optimizadas ya existentes (basadas en Debian según lo recomendado por Docker) e implementa varias de las mejores prácticas de Docker.
Utiliza la imagen oficial de Python Docker, instala UWSGI y además de eso (con la menor cantidad de modificaciones) agrega la imagen oficial de Nginx.
Y controla todos estos procesos con Supervisord.
La imagen (y las etiquetas) creada por este repositorio se basa en la imagen Tiangolo/UWSGI-NGINX . Esta imagen agrega frascos y valores predeterminados sensatos encima.
Si sigue las instrucciones y mantiene el directorio /app raíz en su contenedor, con un archivo llamado main.py y un objeto frasco llamado app en él, debería "solo funcionar".
Ya hay un archivo uwsgi.ini en el directorio /app con las configuraciones UWSGI para que "solo funcione". Y todos los demás parámetros requeridos están en otro archivo uwsgi.ini en la imagen, dentro /etc/uwsgi/ .
Si necesita cambiar el nombre del archivo principal o el objeto principal de frasco, tendría que proporcionar su propio archivo uwsgi.ini . Puede usar el de este repositorio como plantilla para comenzar (y solo tendría que cambiar las 2 líneas correspondientes).
Puede tener un directorio A /app/static y Nginx atenderán de manera eficiente (sin pasar por su código frasco o incluso UWSGI), ya está configurado para usted. Pero puede configurarlo más utilizando variables de entorno (lea arriba).
Supervisord se encarga de ejecutar UWSGI con el archivo uwsgi.ini en /app (incluido también el archivo en /etc/uwsgi/uwsgi.ini ) e iniciar Nginx.
Existe la regla general de que debe tener "un proceso por contenedor".
Eso ayuda, por ejemplo, aislar una aplicación y su base de datos en diferentes contenedores.
Pero si desea tener un enfoque de "microervicios", es posible que desee tener más de un proceso en un contenedor si todos están relacionados con el mismo "servicio", y es posible que desee incluir su código frascos, UWSGI y NGINX en el mismo contenedor (y tal vez ejecute otro contenedor con su base de datos).
Ese es el enfoque adoptado en esta imagen.
Esta imagen (y etiquetas) tienen algunos archivos predeterminados, por lo que si la ejecuta solo (no como la imagen base de su propio proyecto) verá una aplicación web "Hello World" predeterminada.
Cuando crea un Dockerfile con una COPY ./app /app reemplaza esos archivos predeterminados con el código de su aplicación.
El archivo predeterminado principal está solo en /app/main.py . Y en el caso de las etiquetas con -index , también en /app/static/index.html .
Pero esos archivos renderizan un texto "(predeterminado)" en la página web servida, para que pueda verificar si está viendo el código predeterminado o su propio código anulando el valor predeterminado.
El código de su aplicación debe estar en el directorio de contenedores /app , debe tener un archivo main.py y ese archivo main.py debe tener una app de objeto frasco.
Si sigue las instrucciones anteriores o usa una de las plantillas de ejemplo descargables, debe estar bien.
También hay un archivo A /app/uwsgi.ini dentro de las imágenes con los parámetros predeterminados para UWSGI.
Los ejemplos descargables incluyen una copia del mismo archivo uwsgi.ini para fines de depuración. Para obtener más información, lea las " instrucciones de desarrollo avanzadas " a continuación.
Mientras se desarrolla, es posible que desee hacer de su directorio de código un volumen en su contenedor Docker.
Con eso, se actualizaría sus archivos (temporalmente) cada vez que los modifique, sin necesidad de construir su contenedor nuevamente.
Para hacer esto, puede usar el comando pwd (directorio de trabajo imprimido) dentro de su docker run y el flag -v para volúmenes.
Con eso, podría asignar su directorio ./app en el directorio de su contenedor /app .
Pero primero, ya que reemplazará por completo el directorio /app en su contenedor (y todo su contenido) deberá tener un archivo uwsgi.ini en su directorio ./app con:
[uwsgi]
module = main
callable = appY luego puede hacer la asignación de volumen de Docker.
Nota : Un archivo uwsgi.ini se incluye en los ejemplos descargables.
Dockerfile y su directorio ./app )uwsgi.ini en su directorio ./appdocker build -t myimage ../app ) en el directorio de su contenedor /app : docker run -d --name mycontainer -p 80:80 -v $( pwd ) /app:/app myimage Si va a la URL de su contenedor Docker, debería ver su aplicación, y debería poder modificar archivos en ./app/static/ y ver esos cambios reflejados en su navegador simplemente recargando.
... Pero, a medida que UWSGI carga toda su aplicación web Python Flask una vez que se inicia, no podrá editar su código de frascos de Python y ver los cambios reflejados.
Para poder (temporalmente) depurar su código Python Flask en vivo, puede ejecutar su contenedor anulando el comando predeterminado (que inicia Supervisord que a su vez inicia UWSGI y NGINX) y ejecutar su aplicación directamente con python , en modo de depuración, utilizando el comando flask con sus variables de entorno.
Entonces, con todas las modificaciones anteriores y haciendo que su aplicación se ejecute directamente con flask , el comando final Docker sería:
docker run -d --name mycontainer -p 80:80 -v $( pwd ) /app:/app -e FLASK_APP=main.py -e FLASK_DEBUG=1 myimage flask run --host=0.0.0.0 --port=80 O en el caso de un proyecto de paquete, configuraría FLASK_APP=main/main.py :
docker run -d --name mycontainer -p 80:80 -v $( pwd ) /app:/app -e FLASK_APP=main/main.py -e FLASK_DEBUG=1 myimage flask run --host=0.0.0.0 --port=80Ahora puede editar su código de frasco en su máquina local y una vez que actualice su navegador, verá los cambios en vivo.
Recuerde que debe usar esto solo para la depuración y el desarrollo, para la implementación en la producción, no debe montar volúmenes y debe dejar que Supervisord comience y dejar que comience UWSGI y NGINX (que es lo que sucede por defecto).
Una alternativa para estos últimos pasos para funcionar cuando no tiene un paquete, pero solo una estructura plana con archivos (módulos), su código de frasco de Python podría tener esa sección con:
if __name__ == "__main__" :
# Only for debugging while developing
app . run ( host = '0.0.0.0' , debug = True , port = 80 ) ... y podrías ejecutarlo con python main.py Pero eso solo funcionará cuando no esté utilizando una estructura de paquete y no planee hacerlo más tarde. En ese caso específico, si no agregó el bloque de código anterior, su aplicación solo escucharía localhost (dentro del contenedor), en otro puerto (5000) y no en modo de depuración.
Además, si desea hacer la misma depuración en vivo utilizando la variable de entorno STATIC_INDEX=1 (para servir /app/static/index.html directamente cuando se solicite / ) su NGINX no lo servirá directamente, ya que no se ejecutará (solo su aplicación Python Flask en modo de depuración se ejecutará).
from flask import Flask , send_filey
@ app . route ( '/' )
def route_root ():
index_path = os . path . join ( app . static_folder , 'index.html' )
return send_file ( index_path ) ... Eso asegura que su aplicación también sirva el archivo /app/static/index.html cuando se solicite / . O si está utilizando una estructura de paquete, el archivo /app/main/static/index.html .
Y si está utilizando un marco SPA, para permitir que maneje las URL en el navegador, su código de frasco de Python debe tener la sección con:
# Everything not declared before (not a Flask route / API endpoint)...
@ app . route ( '/<path:path>' )
def route_frontend ( path ):
# ...could be a static file needed by the front end that
# doesn't use the `static` path (like in `<script src="bundle.js">`)
file_path = os . path . join ( app . static_folder , path )
if os . path . isfile ( file_path ):
return send_file ( file_path )
# ...or should be handled by the SPA's "router" in front end
else :
index_path = os . path . join ( app . static_folder , 'index.html' )
return send_file ( index_path ) ... Eso hace que el frasco envíe todos los archivos de CSS, JavaScript e Image cuando se solicite en la URL root ( / ), pero también se asegura de que su SPA frontend maneje todas las otras URL que no están definidas en su aplicación Flask.
Así es como se escribe en el tutorial anterior y se incluye en los ejemplos descargables.
Si sigue las instrucciones anteriores, es probable que en algún momento escriba un código que rompa su servidor de depuración de frascos y se bloqueará.
Y dado que el único proceso en ejecución fue su servidor de depuración, que ahora se detiene, su contenedor se detendrá.
Luego tendrá que comenzar su contenedor nuevamente después de arreglar su código y no verá muy fácilmente cuál es el error que está bloqueando su servidor.
Entonces, mientras se desarrolla, podría hacer lo siguiente (eso es lo que normalmente hago, aunque lo hago con Docker Compose, como en los proyectos de ejemplo):
docker run -d --name mycontainer -p 80:80 -v $( pwd ) /app:/app -e FLASK_APP=main.py -e FLASK_DEBUG=1 myimage bash -c " while true ; do sleep 10 ; done "FLASK_APP=main/main.py : docker run -d --name mycontainer -p 80:80 -v $( pwd ) /app:/app -e FLASK_APP=main/main.py -e FLASK_DEBUG=1 myimage bash -c " while true ; do sleep 10 ; done "docker exec -it mycontainer bash Ahora estará dentro de su contenedor en el directorio /app .
flask run --host=0.0.0.0 --port=80Verá el inicio de su servidor de depuración de frascos, verá cómo envía respuestas a cada solicitud, verá los errores lanzados cuando rompa su código y cómo detiene su servidor, y podrá reiniciarlo muy rápido, simplemente ejecutando el comando anterior nuevamente.
Se prueban todas las etiquetas de imagen, configuraciones, variables de entorno y opciones de aplicación.
issue-manager.yml . PR #385 por @Tiangolo.latest-changes . PR #360 por @Tiangolo.latest-changes.yml . PR #348 por @alejsdev.README.md . PR #346 por @alejsdev. Lo más destacado de este lanzamiento:
python3.6-2022-11-25 y python2.7-2022-11-25 .1.17.10 .3.11 .-index sufix tags.-index (use ENV STATIC_INDEX 1 instead).2020-05-04 .tiangolo/uwsgi-nginx-flask:python3.8-2019-10-14 . PR #154./start.sh and /app/prestart.sh functionality to parent image. PR #134.2019-02-02:
uwsgi-nginx and PR #121./app/nginx.conf file that overrides the generated one. PR #51 in the parent image uwsgi-nginx and PR #122.2019-01-01:
2018-12-29:
2018-11-23:
2018-09-22:
2018-06-22:
NGINX_WORKER_CONNECTIONS to set the maximum number of Nginx worker connections and NGINX_WORKER_OPEN_FILES to set the maximum number of open files. Thanks to ronlut in this PR.2018-06-22:
Improvements from parent image:
Make uWSGI require an app to run, instead of going in "full dynamic mode" while there was an error. Supervisord doesn't terminate itself but tries to restart uWSGI and shows the errors. Uses need-app as suggested by luckydonald in this comment.
Correctly handled graceful shutdown of uWSGI and Nginx. Thanks to desaintmartin in this PR.
2018-02-04:
It's now possible to set the number of Nginx worker processes with the environment variable NGINX_WORKER_PROCESSES . Thanks to naktinis in this PR.
2018-01-14:
python2.7-alpine3.7 and python3.6-alpine3.7 .2017-12-10:
/app/prestart.sh script to run arbitrary code before starting the app (for example, Alembic - SQLAlchemy migrations). The documentation for the /app/prestart.sh is in the main README./app is part of the PYTHONPATH environment variable. That allows global imports from several places, easier Alembic integration, etc. 2017-12-08: Now you can configure which port the container should listen on, using the environment variable LISTEN_PORT thanks to tmshn in this PR.
2017-09-10: Updated examples and sample project to work with SPAs even when structuring the app as a package (with subdirectories).
2017-09-02:
flask run commands, that allows running a package application while developing more easily.2017-08-10: Many changes:
python3.6 , python3.6-index , python.3.5 , python3.5-index , python2.7 and python2.7-index . All the other images are deprecated in favor is this ones.latest will point to Python 3.6 and the other tags will be removed.tiangolo/uwsgi-nginx that improved this image too.index.html directly: STATIC_INDEXNGINX_MAX_UPLOADuwsgi.ini file (that allows using a custom directory different than /app ): UWSGI_INI (using the ideas by @bercikr in #5 )../static/ path: STATIC_PATH/static/ URL: STATIC_URLDockerfile with: FROM tiangolo/uwsgi-nginx-flask:python3.6
COPY ./app /appand then customize with environment variables.
This project is licensed under the terms of the Apache license.