Diferencia entre revisiones de «Tutorial configurando vagrant para una aplicación»

De Wiki de EGC
Saltar a: navegación, buscar
(Paso 3: Añadir python-dotenv a requirements.txt)
Línea 93: Línea 93:
 
zope.event==5.0
 
zope.event==5.0
 
zope.interface==7.1.1
 
zope.interface==7.1.1
python-dotenv
+
python-dotenv #Añadir esta línea al requirements.txt que ya teníamos
 
  </pre>
 
  </pre>
  

Revisión del 19:37 12 nov 2024

Despliegue de una Aplicación Python en Vagrant

Introducción

Este tutorial te guiará en el despliegue de una aplicación Flask utilizando Vagrant, Ansible y Shell scripts. La finalidad es entender cómo automatizar la configuración y despliegue de aplicaciones en entornos virtuales reproducibles, como los que proporciona Vagrant.

¿Por qué utilizamos Vagrant?

Vagrant es una herramienta de administración de entornos virtuales que permite definir en un archivo (llamado `Vagrantfile`) las especificaciones necesarias para crear, configurar y aprovisionar una máquina virtual de manera rápida y consistente. Vagrant es especialmente útil en desarrollo y pruebas, ya que nos permite configurar un entorno de desarrollo idéntico al entorno de producción en cuestión de minutos y garantiza que cada miembro del equipo de desarrollo trabaje en un entorno coherente.

Con Vagrant, evitamos el clásico problema de "en mi máquina funciona" al tener un entorno idéntico en cada ejecución, independientemente de la máquina en la que se esté corriendo el proyecto. En este tutorial, usaremos Vagrant para crear una máquina virtual de Linux donde desplegaremos nuestra aplicación de Flask.

¿Qué es el Aprovisionamiento?

Aprovisionar, en el contexto de máquinas virtuales y Vagrant, se refiere al proceso de instalar y configurar el software necesario en una máquina virtual para que pueda ejecutar una aplicación. Cuando aprovisionamos una máquina, estamos automatizando la instalación de dependencias, configuraciones de sistema, servicios necesarios (como bases de datos), y otras tareas de configuración que preparan el entorno para ejecutar la aplicación.

Métodos de Aprovisionamiento

En este tutorial veremos dos métodos de aprovisionamiento:

1. Mediante un script de shell: Usando un archivo `.sh` (como `provision.sh`), que contiene comandos de terminal para instalar y configurar los componentes necesarios.

2. Mediante Ansible: Usando un archivo de configuración llamado `playbook.yml`, que describe de manera declarativa lo que queremos instalar y configurar en la máquina virtual.

¿Por qué utilizar Ansible para el Aprovisionamiento?

Ansible es una herramienta de automatización de TI que permite gestionar la configuración, el despliegue y la orquestación de sistemas. Comparado con los scripts de shell, Ansible ofrece varias ventajas:

  • Declarativo y legible: Un playbook de Ansible describe el estado deseado del sistema (qué queremos conseguir), en lugar de los pasos para llegar a ese estado (cómo hacerlo), lo cual hace que sea más legible y fácil de mantener.
  • Idempotencia: Ansible ejecuta las tareas de manera idempotente, lo que significa que si ejecutamos el playbook varias veces, el sistema solo aplicará los cambios necesarios, evitando que se realicen operaciones innecesarias.
  • Escalabilidad y organización: Ansible permite crear playbooks para gestionar múltiples servidores de manera centralizada, lo cual es esencial en ambientes de producción donde hay decenas o cientos de servidores.
  • Ecosistema y comunidad: Ansible es una herramienta popular con una gran comunidad de usuarios y módulos preexistentes para una amplia variedad de tareas, lo que facilita extender la funcionalidad y resolver problemas comunes rápidamente.

¿Cuándo es mejor utilizar un script de shell y cuándo Ansible?

Para proyectos pequeños o configuraciones rápidas, un script de shell puede ser suficiente. Sin embargo, para entornos más complejos, donde la repetición, escalabilidad y legibilidad son factores importantes, Ansible es preferible debido a su idempotencia, claridad y modularidad.

En este tutorial, vamos a provisionar un entorno para nuestra aplicación Flask de ambas maneras, para que puedas comparar los métodos y comprender en qué casos uno puede ser más ventajoso que el otro.

Nuestra Aplicación: Gestión de Tareas

La aplicación que desplegaremos es una sencilla aplicación de gestión de tareas, creada previamente en otras prácticas. Esta aplicación está basada en Flask, un framework de desarrollo web en Python, y utiliza una base de datos MariaDB para almacenar información. El propósito de este tutorial es aprender a desplegar la aplicación en un entorno controlado y reproducible usando Vagrant y los métodos de aprovisionamiento mencionados anteriormente.

Estructura del Proyecto

Tras la última práctica, el proyecto debería presentar la siguiente estructura de archivos:

 flask_testing_project/
 ├── app.py                # Archivo principal de la aplicación Flask
 ├── templates/            # Directorio con la plantilla HTML
 │   └── tasks.html        # Plantilla para mostrar y agregar tareas
 ├── tests/
 │   ├── test_app.py       # Pruebas para la lógica de la aplicación
 │   └── test_interfaz.py   # Pruebas para la interfaz de usuario
 ├── locustfile.py         # Archivo para pruebas de carga con Locust
 ├── Dockerfile            # Archivo para construir la imagen Docker de la aplicación
 ├── requirements.txt      # Dependencias de Python necesarias para la aplicación
 └── docker-compose.yml    # Archivo de configuración de Docker Compose
 

Parte 1: Aprovisionamiento mediante un Script de Shell

En la primera parte del tutorial, aprovisionaremos el entorno de desarrollo con un script de shell (`provision.sh`).

Paso 1: Generar el archivo .env

Comienza creando un archivo .env en el directorio flask_testing_project. Este archivo contendrá las variables de entorno que tu aplicación Flask necesita para conectarse a la base de datos y otras configuraciones.

En el archivo .env, añade lo siguiente:

DATABASE_USER=flask_user
DATABASE_PASSWORD=flask_password
DATABASE_HOST=localhost
DATABASE_DB=tasks_db
 

Este archivo será leído por la aplicación Flask para cargar estas configuraciones automáticamente al inicio.

Paso 2: Modificar app.py para usar dotenv

Dotenv es una biblioteca que permite gestionar variables de entorno en una aplicación de manera sencilla y segura. Las variables de entorno son valores de configuración (como credenciales de bases de datos, claves API, configuraciones específicas del entorno, etc.) que suelen variar entre diferentes entornos (desarrollo, pruebas, producción) y que, por seguridad, no queremos incluir directamente en el código fuente. Dotenv permite almacenar estas variables de entorno en un archivo llamado .env, donde cada línea contiene un par clave=valor. Luego, al utilizar la biblioteca python-dotenv en nuestro código, podemos cargar automáticamente estas variables al entorno de la aplicación al inicio. Esto nos permite acceder a ellas a través de os.environ, como si estuvieran configuradas en el sistema, pero sin exponerlas en el código.

¿Sabrías enumerar al menos tres motivos por lo que el uso de dotenv es una buena práctica?

Para que la aplicación Flask cargue automáticamente las variables desde el archivo `.env`, edita `app.py` para que incluya dotenv:

  1. Abre `app.py` y añade al principio las siguientes líneas:
 from dotenv import load_dotenv
 import os

 # Cargar variables de entorno desde el archivo .env
 load_dotenv()

Paso 3: Añadir python-dotenv a requirements.txt

Abre el archivo `requirements.txt` y añade la biblioteca `python-dotenv` al final:

attrs==24.2.0
blinker==1.8.2
Brotli==1.1.0
.....
wsproto==1.2.0
zope.event==5.0
zope.interface==7.1.1
python-dotenv #Añadir esta línea al requirements.txt que ya teníamos
 

Paso 4: Crear el Vagrantfile

Recuerda que el Vagrantfile es el archivo de configuración que Vagrant utiliza para definir y gestionar una máquina virtual. Este archivo es el núcleo de cualquier proyecto que utilice Vagrant, ya que contiene instrucciones específicas para la configuración de la máquina virtual, incluyendo el sistema operativo, red, sincronización de carpetas, y scripts de aprovisionamiento.

Al colocar el Vagrantfile en el directorio raíz del proyecto (flask_testing_project/), mantenemos todos los recursos y configuraciones necesarias para el despliegue de la aplicación en un solo lugar. Esto hace que el proyecto sea fácil de portar y reproducir, ya que cualquier persona con este directorio y Vagrant puede ejecutar el proyecto en una máquina virtual idéntica.

A continuación, crea un archivo llamado Vagrantfile en el directorio flask_testing_project/ y añade el siguiente contenido:

 Vagrant.configure("2") do |config|
    config.vm.box = "ubuntu/jammy64"
    
    config.vm.network "forwarded_port", guest: 5000, host: 8080
    
    # Sincronización de la carpeta de tu proyecto para que sea accesible desde la VM
    config.vm.synced_folder ".", "/home/vagrant/app", type: "virtualbox"
    
    # Copiar el archivo .env desde el directorio del proyecto en tu máquina local
    config.vm.provision "file", source: ".env", destination: "/home/vagrant/app/.env"
    
    config.vm.provision "shell", path: "provision.sh"
end

Explicación línea por línea del Vagrantfile

Vagrant.configure("2") do |config|

Este bloque define la configuración para la máquina virtual. El "2" especifica la versión de la sintaxis de configuración de Vagrant, y config es el objeto que contiene todas las configuraciones de esta máquina virtual.

config.vm.box = "ubuntu/jammy64"

Esta línea indica a Vagrant qué sistema operativo (o "box") debe utilizar. Aquí, especificamos "ubuntu/jammy64", una versión de Ubuntu 22.04 (Jammy Jellyfish). Vagrant descargará esta box la primera vez que se ejecute, creando una base común para cualquier máquina que utilice este archivo de configuración.

config.vm.network "forwarded_port", guest: 5000, host: 8080

Esta línea configura el reenvío de puertos para que puedas acceder a la aplicación Flask que se ejecuta en el puerto 5000 de la VM desde el puerto 8080 de tu máquina local. Esto significa que, aunque Flask escuche en localhost:5000 dentro de la VM, podrás acceder a la aplicación en http://localhost:8080 en tu navegador fuera de la VM.

config.vm.synced_folder ".", "/home/vagrant/app", type: "virtualbox"

Aquí estamos sincronizando la carpeta raíz del proyecto (representada por ".") con el directorio /home/vagrant/app dentro de la máquina virtual. Esto permite que los archivos en tu máquina local se mantengan sincronizados con los de la VM, de modo que cualquier cambio que hagas en tu proyecto se refleje inmediatamente dentro de la máquina virtual. La opción type: "virtualbox" es una opción específica de VirtualBox que puede optimizar el rendimiento de esta carpeta sincronizada.

config.vm.provision "file", source: ".env", destination: "/home/vagrant/app/.env"

Este paso copia el archivo .env de configuración desde tu máquina local al directorio correspondiente en la máquina virtual (/home/vagrant/app/.env). Este archivo .env contiene variables de entorno necesarias para que la aplicación Flask funcione correctamente. Asegurar que se copie garantiza que la aplicación tenga las configuraciones necesarias para ejecutarse.

config.vm.provision "shell", path: "provision.sh"

Esta línea define un paso de aprovisionamiento que ejecutará un script de shell llamado provision.sh en la máquina virtual. Este script contendrá instrucciones para instalar dependencias, configurar la aplicación y preparar la máquina virtual para ejecutar el proyecto Flask. Añadir este paso en el Vagrantfile asegura que todo el entorno de la aplicación se instale automáticamente al iniciar la VM con vagrant up.

Paso 5: Escribir el Script de Aprovisionamiento provision.sh

Dentro del directorio raíz, flask_testing_project,, crea un archivo llamado provision.sh que contendrá los comandos necesarios para instalar Python, MariaDB, y todas las dependencias de la aplicación.

El contenido de `provision.sh` debe ser el siguiente:

 #!/bin/bash

 # Actualizar el sistema
 sudo apt-get update

 # Instalar Python, pip y MariaDB
 sudo apt-get install -y python3 python3-venv python3-pip mariadb-server

 # Configurar MariaDB
 sudo mysql -e "CREATE DATABASE IF NOT EXISTS flask_db;"
 sudo mysql -e "CREATE USER 'flask_user'@'localhost' IDENTIFIED BY 'flask_password';"
 sudo mysql -e "GRANT ALL PRIVILEGES ON flask_db.* TO 'flask_user'@'localhost';"
 sudo mysql -e "FLUSH PRIVILEGES;"

 # Crear y activar entorno virtual
 cd /home/vagrant/app
 python3 -m venv venv
 source venv/bin/activate

 # Instalar dependencias de Python
 pip install -r requirements.txt

 # Lanzar aplicación en segundo plano
 nohup python3 app.py &

Paso 6: Iniciar el Entorno Virtual con Vagrant

Desde la terminal, navega al directorio `flask_testing_project/` y ejecuta el siguiente comando:

 vagrant up

Cuando el proceso finalice, podrás acceder a la aplicación en `http://localhost:8080`.

Parte 2: Aprovisionamiento mediante Ansible

Paso 1: Actualizar el archivo .env

Asegúrate de que el archivo `.env` en `flask_testing_project/` contiene las variables necesarias para la base de datos y la aplicación:

 DATABASE_USER=flask_user
 DATABASE_PASSWORD=flask_password
 DATABASE_HOST=localhost
 DATABASE_DB=flask_db
 MYSQL_ROOT_PASSWORD=root_password
 

Paso 2: Modificar el Vagrantfile para usar Ansible

Modifica el `Vagrantfile` para ejecutar un playbook de Ansible en lugar del script `provision.sh`:

 Vagrant.configure("2") do |config|
   config.vm.box = "ubuntu/bionic64"
   config.vm.network "forwarded_port", guest: 5000, host: 8080
   config.vm.provision "ansible" do |ansible|
     ansible.playbook = "playbook.yml"
     ansible.extra_vars = { ansible_python_interpreter: "/usr/bin/python3" }
   end
   config.vm.synced_folder ".", "/home/vagrant/app"
 end

Paso 3: Escribir el Playbook de Ansible

En la raíz de `flask_testing_project/`, crea un archivo llamado `playbook.yml` con el siguiente contenido:

 ---
 - name: Aprovisionamiento de aplicación Flask con Ansible
   hosts: all
   become: true
   vars:
     app_directory: "/home/vagrant/app"
     env_file_path: "/home/vagrant/app/.env"

   tasks:
     # Configurar el repositorio y actualizar paquetes
     - name: Habilitar repositorio "universe" y actualizar paquetes
       ansible.builtin.apt_repository:
         repo: "ppa:deadsnakes/ppa"
         state: present
         update_cache: yes
       when: ansible_distribution == "Ubuntu"
     - name: Actualizar caché de paquetes
       ansible.builtin.apt:
         update_cache: yes

     # Instalar dependencias de sistema
     - name: Instalar dependencias de sistema
       package:
         name:
           - python3
           - python3-venv
           - python3-pip
           - mariadb-server
           - python3-pymysql
           - libmariadb-dev
           - screen
         state: present

     # Configurar MariaDB
     - name: Crear base de datos y usuario de MariaDB
       mysql_user:
         login_unix_socket: /var/run/mysqld/mysqld.sock
         name: 'root'
         password: "{{ MYSQL_ROOT_PASSWORD }}"
         plugin: mysql_native_password
     - name: Crear base de datos
       mysql_db:
         name: "{{ DATABASE_DB }}"
         state: present
         login_unix_socket: /var/run/mysqld/mysqld.sock

     # Crear entorno virtual y activar
     - name: Crear y activar entorno virtual
       command: python3 -m venv {{ app_directory }}/venv
       args:
         creates: "{{ app_directory }}/venv/bin/activate"

     # Instalar dependencias de Python
     - name: Instalar dependencias de Python desde requirements.txt
       pip:
         requirements: "{{ app_directory }}/requirements.txt"
         virtualenv: "{{ app_directory }}/venv"
         virtualenv_python: python3

     # Copiar archivo .env
     - name: Copiar archivo .env al directorio de la aplicación
       copy:
         src: "{{ playbook_dir }}/.env"
         dest: "{{ app_directory }}/.env"
         owner: vagrant
         group: vagrant
         mode: '0640'

     # Lanzar aplicación Flask en segundo plano
     - name: Lanzar aplicación Flask en segundo plano con screen
       shell: |
         screen -m -d -S flask_app bash -c "source {{ app_directory }}/venv/bin/activate && {{ app_directory }}/venv/bin/python3 {{ app_directory }}/app.py"
       args:
         executable: /bin/bash

     # Mensaje de finalización
     - name: Mensaje final
       debug:
         msg: "¡Aprovisionamiento completado y aplicación lanzada en http://localhost:8080!"

Paso 4: Iniciar el Entorno Virtual con Vagrant y Ansible

Para iniciar el entorno, ejecuta nuevamente:

 vagrant up

La aplicación Flask estará disponible en `http://localhost:8080` cuando finalice el aprovisionamiento.

Conclusión

Este tutorial te ha guiado a través de dos métodos de aprovisionamiento de una aplicación Flask en Vagrant, utilizando un script de shell y un playbook de Ansible. ¡Ahora deberías tener una mejor comprensión del aprovisionamiento automático y de cómo desplegar aplicaciones en entornos virtuales reproducibles!