Aplicaciones de una sola página con Vue.js y Flask: implementación

    Implementación en un servidor privado virtual

    Bienvenido a la séptima y última entrega de esta serie de tutoriales de varias partes sobre desarrollo web full-stack usando Vue.js y Flask. En esta publicación, demostraré cómo implementar la aplicación construida a lo largo de esta serie.

    El código para esta publicación se puede encontrar en mi cuenta de GitHub en la rama Séptima Publicación.

    Contenido de la serie

    • Seup y familiarización con VueJS
    • Navegando por el enrutador Vue
    • Gestión de estado con Vuex
    • API RESTful con Flask
    • Integración AJAX con API REST
    • Autenticación JWT
    • Implementación en un servidor privado virtual (usted está aquí)

    Resumen de las tecnologías

    Este tutorial cubrirá varias tecnologías necesarias para implementar una API REST de Flask de varios niveles distribuida y una aplicación Vue.js SPA. A continuación, he enumerado las tecnologías y sus usos:

    • Ubuntu LTS 16.04: servidor host para ejecutar varias aplicaciones y servidores
    • uWSGI: servidor contenedor Webserver Gateway Interface (WSGI) para ejecutar aplicaciones Python (Flask en este caso)
    • Nginx: servidor web HTTP sin bloqueo de alto rendimiento capaz de realizar proxy inverso a uWSGI
    • Node.js / NPM: entorno Javascript para compilar la aplicación Vue.js SPA

    Preparar el código para la implementación

    Hay un par de cambios que deben realizarse en el código para que sea más fácil de mantener una vez que la aplicación se haya implementado en mi entorno de producción.

    Por ejemplo, en api / index.js del survey-spa Aplicación Vue.js He codificado una variable llamada API_URL para apuntar al servidor de desarrollo http://127.0.0.1:5000/api. Al hacer esto, tendré que recordar cambiar esto a la dirección IP del servidor de producción cada vez que necesite implementar.

    La experiencia me ha enseñado que siempre habrá cambios en la aplicación que requieran futuras implementaciones donde es probable que me olvide de actualizar esta dirección IP. Un mejor enfoque es eliminar el riesgo de que me olvide de actualizar esto y, en su lugar, utilice configuraciones en el proceso de compilación para manejar esto por mí, lo que resulta en menos de lo que tengo que recordar (es decir, se necesitan menos pasos) durante la implementación. Esto reduce significativamente el riesgo de una implementación fallida en futuras actualizaciones.

    Lo logro moviéndome al directorio survey-spa / config y modificando los archivos dev.env.js y prod.env.js definiendo una variable llamada API_URL a los que se les asigna un valor de http://localhost:5000/api para dev y http://${process.env.BASE_URL}/api para prod como se muestra a continuación:

    // dev.env.js
    
    'use strict'
    const merge = require('webpack-merge')
    const prodEnv = require('./prod.env')
    
    module.exports = merge(prodEnv, {
      NODE_ENV: '"development"',
      API_URL: JSON.stringify(`http://localhost:5000/api`)
    })
    
    // prod.env.js
    'use strict'
    module.exports = {
      NODE_ENV: '"production"',
      API_URL: JSON.stringify(`http://${process.env.BASE_URL}/api`)
    }
    

    Nota: el valor de process.env.BASE_URL es una variable de entorno que agregaré al usuario del servidor de Ubuntu .bash_profile y la estableceré igual a la dirección IP del servidor.

    Luego, en api / index.js modifico la línea const API_URL = 'http://127.0.0.1:5000/api' y ponerlo igual a process.env.API_URL.

    A continuación, en la aplicación Flask, necesito agregar un nuevo módulo llamado wsgi.py para que sirva como punto de entrada a la API REST de Flask. El módulo wsgi.py se parece bastante al módulo appserver.py, excepto que no tiene ninguna llamada al run(...) método del objeto de la aplicación. Esto se debe a que el objeto de la aplicación servirá como un invocable para que el servidor de contenedores uwsgi se ejecute utilizando su protocolo binario rápido en lugar del servidor de desarrollo normal que se crea cuando app.run(...) se llama.

    # backend/wsgi.py
    
    from surveyapi.application import create_app
    app = create_app()
    

    Con esto terminado, puedo enviar mis cambios al control de versiones y saltar a mi servidor de producción para desplegar el proyecto y configurar los programas que usaré para ejecutar la aplicación en el servidor de producción.

    Preparando el servidor Ubuntu

    A continuación, entraré en mi servidor privado virtual Ubuntu de producción, que podría estar alojado en uno de los muchos servicios en la nube, como AWS, DigitalOcean, Linode, etc., y comenzaré a instalar todas las ventajas que enumeré en la Descripción general de las tecnologías. sección.

    $ apt-get update
    $ apt-get install python3-pip python3-dev python3-venv nginx nodejs npm
    

    Con esas instalaciones fuera del camino, ahora puedo crear un usuario llamado “encuesta” para ejecutar la aplicación y albergar el código.

    $ adduser survey
    $ usermod -aG sudo survey
    $ su survey
    $ cd
    

    Ahora debería estar en el directorio de inicio del usuario de “encuesta” en / home / survey.

    Con la encuesta creada por el usuario, puedo actualizar el archivo .bash_profile para que contenga la dirección IP de mi servidor de producción agregando esta línea al final del archivo. Tenga en cuenta que 123.45.67.89 representa una dirección IP falsa de mi servidor. Reemplácelo con su verdadera dirección IP si lo está siguiendo.

    export BASE_URL=123.45.67.89
    

    A continuación, quiero decirle al firewall (ufw) que OpenSSH es aceptable y habilítelo.

    $ sudo ufw allow OpenSSH
    $ sudo ufw enable
    

    Una vez hecho esto, ahora clonaré el repositorio en el servidor para poder construirlo e implementarlo.

    $ git clone https://github.com/amcquistan/flask-vuejs-survey.git
    

    Ahora ingresaré en flask-vuejs-survey / frontend / survey-spa e instalaré las dependencias de frontend y construiré la aplicación de producción.

    $ cd flask-vuejs-survey/frontend/survey-spa
    $ npm install
    $ npm run build
    

    Esto crea un nuevo directorio llamado “dist”, que contendrá una página index.html y un directorio llamado “estático” que contiene todos los archivos CSS y JavaScript compilados. Estos son los que tendré en el servidor Nginx para constituir la aplicación de front-end del SPA.

    A continuación, crearé un entorno virtual en el directorio / home / survey para que un intérprete de Python3 aislado ejecute la aplicación Python. Una vez instalado, lo activo y me muevo al directorio del proyecto backend para instalar sus paquetes de dependencia especificados en el archivo requirements.txt.

    $ python3 -m venv venv
    $ source venv/bin/activate
    (venv) $ cd flask-vuejs-survey/backend
    (venv) $ pip install -r requirements.txt
    

    Ahora puedo inicializar la base de datos sqlite y ejecutar las migraciones para crear las diversas tablas de base de datos requeridas por la API REST.

    (venv) $ python manage.py db upgrade
    

    En este punto, me gustaría encender el servidor de desarrollo Flask para asegurarme de que todo funciona como se esperaba. Antes de hacerlo, necesito decirle al ufw servicio para permitir el tráfico en el puerto 5000.

    (venv) $ sudo ufw allow 5000
    (venv) $ python appserver.py
    

    En un navegador ahora puedo ir a http://123.45.67.89:5000/api/surveys/ y debería ver una simple respuesta JSON de [] porque aún no hay encuestas en esta base de datos, pero esto indica que se realizó una solicitud con éxito. Además, en el terminal conectado al servidor debería haber un mensaje registrado para la solicitud GET emitida desde mi navegador.

    Tecleo Ctrl + C en la terminal para matar el servidor de desarrollo de Flask y paso a configurar uwsgi para controlar la ejecución de mi API REST de Flask. Si se está preguntando de dónde vino uwsgi, se especifica como un requisito en el archivo requirements.txt que instalé anteriormente.

    Configuración del servidor de contenedores uWSGI

    De manera similar a lo que acabo de hacer con el servidor de desarrollo Flask, ahora probaré que el servidor uWSGI puede servir la aplicación de la siguiente manera.

    (venv) $ uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app
    

    Nuevamente, ir a mi navegador y actualizar la misma solicitud que hice anteriormente debería devolver una respuesta de matriz JSON vacía. Una vez satisfecho con mi progreso, puedo volver a presionar Ctrl + C en la terminal y seguir adelante.

    Hay dos pasos más que me gustaría seguir para completar la configuración del servidor de contenedores uWSGI. Un paso es crear un archivo de configuración que leerá uWSGI en el que reemplazará muchos de los indicadores y argumentos de la línea de comando que utilicé anteriormente. El segundo paso es crear un archivo de servicio systemd para administrar el servidor contenedor uWSGI como un servicio como muchos de los otros que ya se ejecutan en el servidor Ubuntu.

    En el directorio de backend, hago un archivo llamado surveyyapi.ini y lo lleno con lo siguiente:

    [uwsgi]
    module = wsgi:app
    
    master = true
    processes = 4
    
    socket = myproject.sock
    chmod-socket = 660
    vacuum = true
    
    die-on-term = true
    

    Este archivo de configuración le permite a uWSGI saber que el invocable es el objeto de la aplicación dentro del módulo wsgi.py. También le dice que genere y use cuatro procesos para manejar solicitudes de aplicaciones comunicadas a través de un archivo de socket llamado surveyyapi.sock que tiene un permiso lo suficientemente flexible como para permitir que el servidor web Nginx lea y escriba desde él. los vacuum y die-on-term Los ajustes son para asegurar una limpieza adecuada.

    Para el archivo de servicio systemd, necesito crear un archivo llamado surveyapi.service en el directorio / etc / systemd / system y agregue algunos descriptores más los comandos de acceso, escritura y ejecución de la siguiente manera:

    (venv) $ sudo nano /etc/systemd/system/surveyapi.service
    

    Luego, complételo con lo siguiente:

    [Unit]
    Description=uWSGI Python container server
    After=network.target
    
    [Service]
    User=survey
    Group=www-data
    WorkingDirectory=/home/survey/flask-vuejs-survey/backend
    Environment="PATH=/home/survey/venv/bin"
    ExecStart=/home/survey/venv/bin/uwsgi --ini surveyapi.ini
    
    [Install]
    WantedBy=multi-user.target
    

    Ahora puedo iniciar el servicio y verificar su estado y asegurarme de que el directorio de backend ahora contenga surveyyapi.sock.

    (venv) $ sudo systemctl start surveyapi
    (venv) $ sudo systemctl status surveyapi
       Loaded: loaded (/etc/systemd/system/surveyapi.service; disabled; vendor preset: enabled)
       Active: active (running) since Mon 2018-04-23 19:23:01 UTC; 2min 28s ago
     Main PID: 11221 (uwsgi)
        Tasks: 6
       Memory: 28.1M
          CPU: 384ms
       CGroup: /system.slice/surveyapi.service
               ├─11221 /home/survey/venv/bin/uwsgi --ini surveyapi.ini
               ├─11226 /home/survey/venv/bin/uwsgi --ini surveyapi.ini
               ├─11227 /home/survey/venv/bin/uwsgi --ini surveyapi.ini
               ├─11228 /home/survey/venv/bin/uwsgi --ini surveyapi.ini
               ├─11229 /home/survey/venv/bin/uwsgi --ini surveyapi.ini
               └─11230 /home/survey/venv/bin/uwsgi --ini surveyapi.ini
    
    Apr 23 19:23:01 ubuntu-s-1vcpu-2gb-sfo2-01 uwsgi[11221]: mapped 437520 bytes (427 KB) for 5 cores
    Apr 23 19:23:01 ubuntu-s-1vcpu-2gb-sfo2-01 uwsgi[11221]: *** Operational MODE: preforking ***
    Apr 23 19:23:01 ubuntu-s-1vcpu-2gb-sfo2-01 uwsgi[11221]: WSGI app 0 (mountpoint="") ready in 0 seconds on interpreter 0x8b4c30 pid: 112
    Apr 23 19:23:01 ubuntu-s-1vcpu-2gb-sfo2-01 uwsgi[11221]: *** uWSGI is running in multiple interpreter mode ***
    Apr 23 19:23:01 ubuntu-s-1vcpu-2gb-sfo2-01 uwsgi[11221]: spawned uWSGI master process (pid: 11221)
    Apr 23 19:23:01 ubuntu-s-1vcpu-2gb-sfo2-01 uwsgi[11221]: spawned uWSGI worker 1 (pid: 11226, cores: 1)
    Apr 23 19:23:01 ubuntu-s-1vcpu-2gb-sfo2-01 uwsgi[11221]: spawned uWSGI worker 2 (pid: 11227, cores: 1)
    Apr 23 19:23:01 ubuntu-s-1vcpu-2gb-sfo2-01 uwsgi[11221]: spawned uWSGI worker 3 (pid: 11228, cores: 1)
    lines 1-23
    (venv) $ ls -l /home/survey/flask-vuejs-survey/backend
    -rw-rw-r-- 1 survey survey     201 Apr 23 18:18 appserver.py
    -rw-rw-r-- 1 survey survey     745 Apr 23 17:55 manage.py
    drwxrwxr-x 4 survey survey    4096 Apr 23 18:06 migrations
    drwxrwxr-x 2 survey survey    4096 Apr 23 18:52 __pycache__
    -rw-rw-r-- 1 survey survey     397 Apr 23 18:46 requirements.txt
    drwxrwxr-x 3 survey survey    4096 Apr 23 18:06 surveyapi
    -rw-rw-r-- 1 survey survey     133 Apr 23 19:04 surveyapi.ini
    srw-rw---- 1 survey www-data     0 Apr 23 19:23 surveyapi.sock
    -rw-r--r-- 1 survey survey   10240 Apr 23 18:19 survey.db
    -rw-rw-r-- 1 survey survey      84 Apr 23 18:42 wsgi.py
    

    ¡Excelente! Lo último que debo hacer es habilitar el inicio automático cada vez que se inicia el sistema, asegurándome de que la aplicación esté siempre activa.

    (venv) $ sudo systemctl enable surveyapi
    

    Configuración de Nginx

    Utilizaré Nginx para servir contenido estático como HTML, CSS y JavaScript, así como para revertir las llamadas API REST del proxy a la aplicación Flask / uWSGI. Para configurar nginx para lograr estas cosas, necesitaré crear un archivo de configuración que defina cómo administrar estas diversas solicitudes.

    En / etc / nginx / sites-available, crearé un archivo llamado encuesta que contendrá lo siguiente:

    server {
        listen 80;
        server_name 123.45.67.89;
    
        location /api {
            include uwsgi_params;
            uwsgi_pass unix:/home/survey/flask-vuejs-survey/backend/surveyapi.sock;
        }
    
      location / {
        root /home/survey/flask-vuejs-survey/frontend/survey-spa/dist;
        try_files $uri $uri/ /index.html;
      }
    }
    

    Este archivo crea una nueva configuración de bloque de servidor que dice que escuche la dirección IP 123.45.67.89 en el puerto HTTP estándar de 80. Luego dice que busque cualquier ruta URI que comience con / api y un proxy inverso al servidor Flask / uWSGI REST API utilizando el archivo de socket definido previamente. Por último, la configuración dice que capture todo lo demás en / y sirva el archivo index.html en el directorio dist creado cuando construí la aplicación SPA de front-end Vue.js antes.

    Con este archivo de configuración creado, necesito informarle a Nginx que es un sitio disponible creando un enlace simbólico al directorio / etc / nginx / sites-enabled como sigue:

    $ sudo ln -s /etc/nginx/sites-available/survey /etc/nginx/sites-enabled 
    

    Para permitir el tráfico a través del puerto HTTP y enlazar con Nginx, emitiré la siguiente actualización para ufw así como cerrar el puerto 5000 previamente abierto.

    $ sudo ufw delete allow 5000
    $ sudo ufw allow 'Nginx Full'
    

    Siguiendo este comando, tendré que reiniciar el servicio Nginx para que las actualizaciones surtan efecto.

    $ sudo systemctl restart nginx
    

    Ahora puedo volver a mi navegador y visitar http://123.454.67.89 y se me presenta la aplicación de encuesta que he mostrado en artículos anteriores.

    Conclusión

    Bueno, esta es la publicación final de esta serie de tutoriales de varias partes sobre cómo utilizar Flask y Vue.js para construir una aplicación SPA habilitada para REST API. He intentado cubrir la mayoría de los temas importantes que son comunes a muchos casos de uso de aplicaciones web, asumiendo muy poco conocimiento previo de las tecnologías Flask y Vue.js utilizadas.

    Les agradezco por seguir esta serie y, por favor, no tengan vergüenza de comentar o criticar a continuación.

     

    Etiquetas:

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *