Python Flask Docker en ISPConfig3 con Nginx - Parte 1: Mínima aplicación
ISPConfig es un gran panel de control de hosting, pero no soporta Python aplicaciones fuera de la caja. Este post muestra cómo se puede hacer utilizando Docker...
Este es un post que muestra cómo ejecutar una Flask aplicación en ISPConfig3. Por qué? Tengo un VPS en internet funcionando Debian y ISPConfig3. Está ejecutando sitios y PHP sitios estáticos. Pero ahora también quiero ejecutar mis aplicaciones Flask python aquí. De esta manera puedo utilizar la gestión de dominios a la que estoy acostumbrado y no necesito un servidor extra para las Python aplicaciones.
Esta solución utiliza Docker para ejecutar la Flask aplicación, imprimiendo'Hello world', y es una primera prueba de concepto que muestra que es posible desplegar una aplicación Flasp en ISPConfig3.
Mi máquina local:
- Ubuntu desktop 18.04.1
- Python3.6.7
- nginx 1.14.0
- Docker 18.09.0
- Docker-Composición 1.23.2
Mi VPS:
- Debian 9 (Estiramiento)
- ISPConfig3 3.1.13
- Nginx 1.10.3
- docker 18.09.0
- Docker-Composición 1.23.2
Trate de mantener las versiones Docker y Docker-componer en ambas máquinas idénticas. los Docker desarrolladores a veces no logran mantener la compatibilidad hacia atrás.
Contenido:
- Paso 1: Crear y ejecutar una Flask aplicación helloworld en la máquina local, utilizando el servidor de desarrollo
- Paso 2: Ejecutar helloworld en la máquina local, utilizando el servidor de producción Gunicorn
- Paso 3: Ejecute helloworld en la máquina local, usando Docker
- Paso 4: En la máquina local servir el dockarized helloworld con un servidor proxy nginx inverso
- Paso 5: En el equipo ISPConfig3, despliegue el dockarized helisupervisor
- Resumen
- Notas
Paso 1: Crear y ejecutar una Flask aplicación helloworld en la máquina local, utilizando el servidor de desarrollo
1.1. Cree un entorno virtual y active
Consulte las instrucciones en Internet. Haz algo como:
> mkdir flask_docker
> cd flask_docker
> mkdir python3
> cd python3
> mkdir venvs
> python3 -m venv venvs/helloworld
> source venvs/helloworld/bin/activate
> cd venvs/helloworld
> pwd
.../flask_docker/python3/venvs/helloworld
1.2. Consulta el directorio helloworld
Deberías ver algo como:
.
|-- bin
|-- include
|-- lib
|-- lib64 -> lib
|-- __pycache__
|-- share
`-- pyvenv.cfg
All commands below are from this directory.
1.3. Instalar Flask
Tipo:
> instalación de un matraz pip
1.4. Crear una Flask aplicación sencilla hello.py
Con tu editor crea una Flask aplicación helloworld.py:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "<h1>Hello world!</h1>"
if __name__ == '__main__':
app.run()
1.5. Ejecútalo usando el servidor de desarrollo
> python3 helloworld.py En
su tipo de navegador: localhost:5000
Debería ver: Hola Mundo
Detenga el servidor de desarrollo usando Ctrl-C.
Paso 2: Ejecutar helloworld en la máquina local, utilizando el servidor de producción Gunicorn
2.1. Instalar servidor de producción gunicornio
pip install gunicornio
2.2. Crear el archivo de objeto de aplicación wsgi.py para gunicornio:
Cree el archivo wsgi.py como se indica a continuación:
from helloworld import app
if __name__ == "__main__":
app.run()
Simplemente estamos importando la aplicación desde helloworld.py.
2.3. Ejecútalo usando el servidor de gunicornio
> gunicorn --bind 0.0.0.0.0:8000 wsgi:app En
su tipo de navegador: localhost:80000
Debería ver: Hola Mundo
Detén el servidor gunicornio usando Ctrl-C.
Paso 3: Ejecute helloworld en la máquina local, usando Docker
3.1. Instalar Docker y Dockercomponer
Ver instrucciones en docker.com, digitalocean.com, etc.
Si no puede emitir Docker comandos sin sudo, añádase al Docker grupo:
Pasos posteriores a la instalación para Linux
https://docs.docker.com/install/linux/linux-postinstall/
3.2. Almacene el software necesario en requirements.txt
> pip freeze > requirements.txt Si
hay una línea 'pkg-resources==0.0.0.0' presente en requirements.txt, elimínela.
Esto es un error en algunos sistemas.
Mi archivo requirements.txt tiene este aspecto:
Click==7.0
Flask==1.0.2
gunicorn==19.9.0
itsdangerous==1.1.0
Jinja2==2.10
MarkupSafe==1.1.0
Werkzeug==0.14.1
3.3. Crear un Dockerfichero
El Dockerarchivo tiene el siguiente aspecto:
FROM python:3.6-alpine
RUN adduser -D helloworlduser
RUN mkdir -p /home/flask_app/helloworld
WORKDIR /home/flask_app/helloworld
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY helloworld.py wsgi.py boot.sh ./
RUN chmod +x boot.sh
ENV FLASK_APP helloworld.py
RUN chown -R helloworlduser:helloworlduser ./
USER helloworlduser
EXPOSE 5000
ENTRYPOINT ["./boot.sh"]
El script de inicio boot.sh:
#!/bin/sh
# called by Dockerfile
# go to directory where wsgi.py is
cd /home/flask_app/helloworld
# start gunicorn
exec gunicorn -b :5000 --access-logfile - --error-logfile - wsgi:app
El directorio ahora se ve así:
.
|-- bin
|-- include
|-- lib
|-- lib64 -> lib
|-- __pycache__
|-- share
|-- boot.sh
|-- docker-compose.yml
|-- Dockerfile
|-- Dockerfile_web
|-- helloworld.py
|-- image_helloworld.tar
|-- pyvenv.cfg
|-- requirements.txt
`-- wsgi.py
3.4. Construir la imagen del contenedor
> docker build -t helloworld:más reciente
La salida termina con algo como:
...
Successfully built d3e8bc220161
Successfully tagged helloworld:latest
Puede verificar si se ha creado el contenedor:
> imágenes de docker
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworld latest d3e8bc220161 2 minutes ago 84.8MB
python 3.6-alpine 1837080c5e87 5 weeks ago 74.4MB
3.5. Ejecutar la imagen del contenedor
Primero ejecute el contenedor como una aplicación en primer plano, es decir, sin la opción -d:
> docker run --nombre helloworld -p 8001:5000 --rm helloworld:latest
Si algo está mal, por ejemplo, en boot.sh, puede corregirlo y reconstruir el contenedor de nuevo:
> docker build -t helloworld:más reciente
También puede entrar en el contenedor para ver lo que está sucediendo, por ejemplo, si los archivos están realmente allí:
> docker run -it --entrypoint /bin/sh --rm helloworld:latest
Si todo está bien, puede ejecutar el contenedor en el fondo utilizando la opción -d:
> docker run --nombre helloworld -d -p 8001:5000 --rm helloworld:latest
En su tipo de navegador: localhost:80001
Deberías verlo: Hola Mundo
Compruebe que el contenedor está en funcionamiento:
> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
37f06d44cd30 helloworld:latest "./boot.sh" 4 seconds ago Up 4 seconds 0.0.0.0:8001->5000/tcp helloworld
Revisa los registros:
> docker logs helloworld
[2019-02-02 14:52:57 +0000] [1] [INFO] Starting gunicorn 19.9.0
[2019-02-02 14:52:57 +0000] [1] [INFO] Listening at: http://0.0.0.0:5000 (1)
[2019-02-02 14:52:57 +0000] [1] [INFO] Using worker: sync
[2019-02-02 14:52:57 +0000] [9] [INFO] Booting worker with pid: 9
Para detener el contenedor:
> docker kill helloworld
Compruebe que el contenedor ha dejado de funcionar:
> docker ps
Paso 4: En la máquina local servir el dockarized helloworld con un servidor inverso proxy Nginx
4.1. Instalar Nginx en la máquina local
Si aún no está instalado:
> sudo apt install nginx
4.2. Configurar Nginx
Vamos a servir el sitio web helloworld.net en el puerto 8080. Configúralo como un Nginx reverso, es decir proxy, dirige las peticiones de los clientes a nuestro Gunicorn servidor que se ejecuta en...
Cree un archivo /etc/nginx/sites-available/helloworld.conf:
server {
listen 8080;
server_name helloworld.net;
location / {
proxy_pass http://127.0.0.1:8001;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 1M;
}
}
Crear un enlace simbólico en /etc/nginx/sites-enabled:
> sudo ln -s /etc/nginx/sites-available/helloworld.conf /etc/nginx/sites-enabled/helloworld.conf
Reiniciar Nginx:
> sudo systemctl reiniciar nginx
Si algo sale mal, mira el estado:
> sudo systemctl status nginx.service
4.3. Añadir helloworld.net al archivo de hosts
> sudo nano /etc/hosts
Añade una línea:
127.0.0.0.1 helloworld.net
Comprueba que funciona, debería responder 127.0.0.0.1 en el ping:
> ping helloworld.net
PING helloworld.net (127.0.0.1) 56(84) bytes of data.
64 bytes from helloworld.net (127.0.0.1): icmp_seq=1 ttl=64 time=0.023 ms
64 bytes from helloworld.net (127.0.0.1): icmp_seq=2 ttl=64 time=0.042 ms
En cromo (cromo) puede comprobar y borrar los dns escribiendo en la barra de direcciones:
cromado://net-internals/#dns
4.4. Inicie el contenedor y acceda a su sitio web
En su tipo de navegador: helloworld.net:8080
Si aún no ha iniciado la imagen del contenedor de la base Docker de helloworld, aparecerá el navegador:
502 Puerta de enlace defectuosa
Empieza tu contenedor:
> docker run --nombre helloworld -d -p 8001:5000 --rm helloworld:latest
En tu navegador deberías ver: Hola Mundo
Paso 5: En los ISPConfig3 VPS, desplegar el dockarized helloworld
Ahora tenemos una imagen del Docker contenedor que está trabajando en nuestra máquina local. Para ejecutar esto en nuestra máquina ISPConfig3 tenemos varias opciones. Aquí usamos: copiar la Docker imagen a otro host.
5.1. Instalar Docker y Docker-componer en el VPS
Siga los procedimientos de instalación.
5.2. Copia Dockerde archivos e imágenes docker a ISPConfig3 máquinas
Localice nuestra imagen:
> imágenes de docker
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworld latest bee00f1c8607 21 hours ago 84.8MB
Guarda la imagen de la ventana acoplable como un archivo tar:
> docker save -o./image_helloworld.tar helloworld
Utilice un programa de transferencia de archivos para copiar Dockerel archivo y la imagen en el ISPConfigequipo.
En la máquina ISPConfig3 vaya al directorio donde se encuentran los archivos y añada nuestra imagen a Docker:
> docker load -i image_helloworld.tar
Esto puede tomar algún tiempo. Compruebe que la imagen está disponible:
> imágenes de docker
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworld latest bee00f1c8607 21 hours ago 84.8MB
5.3. Configure su sitio en ISPConfig3
Asumiendo que ya tiene un nombre de dominio que apunta a su ISPConfigmáquina, usted agregó el dominio y agregó el sitio. En este caso, al escribir en su navegador:
<dominio>dominio
deberías ver algo como:
Welcome to your website!
Inicie sesión en ISPConfig3.
Ir a: Sitios->Su sitio
En la pestaña Dominio:
- Desmarcar CGI
- Desactivado PHP
Haga clic en Guardar.
En la ficha Opciones
Añada lo siguiente a las Directivas nginx:
location / {
proxy_pass http://127.0.0.1:8001;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 1M;
}
Haga clic en Guardar.
Si su sitio estaba funcionando antes, ahora debería aparecer:
ERROR 502 - ¡Mala puerta de enlace!
5.4. Arrancar el contenedor
> docker run --nombre helloworld -p 8001:5000 --rm helloworld:latest
Ahora, después de escribir en su navegador:
<dominio>dominio
deberías ver: Hola Mundo
¡Genial!
Detenga la Docker Flask aplicación:
> docker kill helloworld
Comprueba que se ha ido:
> docker ps
Resumen
Creamos una Flask aplicación simple y la implementamos en nuestra máquina ISPConfig3.
En un próximo post usaremos un ejemplo más avanzado:
- Servir varias páginas
- Servir archivos estáticos
- Conectarse a la base de datos ISPConfig3
Notas
1. Es posible que desee utilizar Gunicorn siempre para el desarrollo
Habilitar el depurador Flask interactivo en el desarrollo con Gunicorn
https://nickjanetakis.com/blog/enabling-the-flask-interactive-debugger-in-development-with-gunicorn
Enlaces / créditos
Deploy flask app with nginx using gunicorn and supervisor
https://medium.com/ymedialabs-innovation/deploy-flask-app-with-nginx-using-gunicorn-and-supervisor-d7a93aa07c18
Embedding Python In Apache2 With mod_python (Debian/Ubuntu, Fedora/CentOS, Mandriva, OpenSUSE)
https://www.howtoforge.com/embedding-python-in-apache2-with-mod_python-debian-ubuntu-fedora-centos-mandriva-opensuse
How to Configure NGINX for a Flask Web Application
https://www.patricksoftwareblog.com/how-to-configure-nginx-for-a-flask-web-application/" target="_blank">How to Configure NGINX for a Flask
How to copy Docker images from one host to another without using a repository
https://stackoverflow.com/questions/23935141/how-to-copy-docker-images-from-one-host-to-another-without-using-a-repository
How to deploy a django application on a linux (Debian/Ubuntu) production server running ISPConfig 3
http://blog.yawd.eu/2011/how-to-deploy-django-app-linux-server-ispconfig/
How To Serve Flask Applications with Gunicorn and Nginx on Ubuntu 18.04
https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-gunicorn-and-nginx-on-ubuntu-18-04
The Flask Mega-Tutorial Part XIX: Deployment on Docker Containers
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xix-deployment-on-docker-containers
Recientes
- Cómo ocultar las claves primarias de la base de datos UUID de su aplicación web
- Don't Repeat Yourself (DRY) con Jinja2
- SQLAlchemy, PostgreSQL, número máximo de filas por user
- Mostrar los valores en filtros dinámicos SQLAlchemy
- Transferencia de datos segura con cifrado de Public Key y pyNaCl
- rqlite: una alternativa de alta disponibilidad y dist distribuida SQLite
Más vistos
- Usando Python's pyOpenSSL para verificar los certificados SSL descargados de un host
- Usando UUIDs en lugar de Integer Autoincrement Primary Keys con SQLAlchemy y MariaDb
- Conectarse a un servicio en un host Docker desde un contenedor Docker
- Usando PyInstaller y Cython para crear un ejecutable de Python
- SQLAlchemy: Uso de Cascade Deletes para eliminar objetos relacionados
- Flask RESTful API validación de parámetros de solicitud con esquemas Marshmallow