Despliegue de una aplicación Python

Descripción

En esta entrada vamos a desplegar una aplicación Python realizada en Django.

Entorno de desarrollo

  1. Utilizamos la máquina bravo de nuestro escenario que usa Rocky Linux 9.

  2. Vamos a configurar nuestro escenario de la siguiente manera:

    • Realizamos un fork del repositorio con la app.

    • Creamos un entorno virtual de Python3 e instalamos las dependencias necesarias.

Realización Entorno de desarrollo

Para realizar el entorno de desarrollo vamos a utilizar la máquina bravo de nuestro escenario, que usa Rocky Linux 9.

  • Primero instalamos git para poder clonar el repositorio de la aplicación:
    sudo dnf install git
    
  • Realizamos un fork del repositorio con la app y clonamos el repositorio en la máquina bravo, concretamente en eldirectorio /var/www/html:
    git clone https://github.com/Legnakra/Tutorial-Django.git
    

E instalamos el entorno virtual de python:

    python3 -m venv venv
    
    source venv/bin/activate
    
  • Instalamos las dependencias de la aplicación:
    pip install -r requirements.txt
    
  • ¿Qué fichero tienes que consultar? ¿Cómo se llama la base de datos que vamos a crear?

    Para consultar el fichero que tenemos que consultar, vamos a ver el fichero settings.py de la aplicación, en el apartado de DATABASES:

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }
    

1

Como podemos ver, la base de datos que vamos a crear es db.sqlite3.

  • Creamos la base de datos:
    python django_tutorial/manage.py migrate
    
![2](/images/django/2.png)
  • Creamos el usuario Administrador:
    python django_tutorial/manage.py createsuperuser
    ---
    password: admin
    

3

  • Modificamos el fichero settings.py para que el servidor web de desarrollo escuche en todas las interfaces:
    ALLOWED_HOSTS = ['*']
    
  • Ejecutamos el servidor web de desarrollo y entramos en la zona de administración para comprobar que los datos se han almacenado correctamente:
    python django_tutorial/manage.py runserver 0.0.0.0:8000
    
![4](/images/django/4.png)

NOTA: Para acceder a la página web desde el ordenador, tendremos que añadir una nueva regla DNAT en alfa para que redirija el tráfico de la máquina bravo al puerto 8000.

    nano /etc/network/interfaces.d/50-cloud-init
    ---
    post-up iptables -t nat -A PREROUTING -p tcp --dport 8000 -i ens3 -j DNAT --to 172.16.0.200
    

Seguidamente reiniciamos la máquina alfa:

    sudo reboot
    
  • Comprobamos que podemos acceder a la aplicación desde el navegador, sobre todo en la zona de administración:

5

6

7

  • Creamos dos preguntas con varias respuestas.

8

9

10

11

12

Configurar el servidor web

Vamos a configurar el servidor web apache2 con el módulo wsgi para servir la página web. Al utilizar como entorno de desarrollo la máquina bravo, se accederá con el nombre python.mariajesus.gonzalonazareno.org.

  • Para reunir los ficheros estáticos, ejecutamos el siguiente comando:
    python django_tutorial/manage.py collectstatic
    
  • Pero antes de ello, tenemos que modificar el fichero settings.py para que el servidor web de desarrollo escuche en todas las interfaces:
        STATIC_ROOT = '/var/www/html/Django_Tutorial/static'
        
  • Instalamos el módulo wsgi para apache2:
    sudo dnf install mod_wsgi httpd
    
  • Creamos el VirtualHost que servirá la web:
    nano /etc/httpd/sites-available/django_tutorial.conf

    ---

    <VirtualHost *:80>
        ServerName python.mariajesus.gonzalonazareno.org
        DocumentRoot /var/www/html/django_tutorial
        Alias /static/ /var/www/html/django_tutorial/static/
        WSGIDaemonProcess django_tutorial python-path=/var/www/html/django_tutorial:/var/www/html/django/lib/python3.9/site-packages
        WSGIProcessGroup django_tutorial
        WSGIScriptAlias / /var/www/html/django_tutorial/django_tutorial/wsgi.py
        ErrorLog /var/log/httpd/django_tutorial_error.log
        CustomLog /var/log/httpd/django_tutorial_access.log combined
    </VirtualHost>
    

Lo activamos:

        ln -s /etc/httpd/sites-available/django_tutorial.conf /etc/httpd/sites-enabled/django_tutorial.conf
        
  • Reiniciamos el servicio apache2:
    sudo systemctl restart httpd
    
  • Nos dirigimos a la máquina charlie, que es el servidor DNS, y añadimos la nueva zona DNS:
    nano /var/cache/bind/db.interna.mariajesus.gonzalonazareno.org
    nano /var/cache/bind/db.dmz.mariajesus.gonzalonazareno.org
    ---
    python  IN  A   bravo
    

Refrescamos la zona DNS:

        rndc flush
        systemctl restart bind9
        
  • Comprobamos que podemos acceder a la aplicación desde el navegador:

    12

Entorno de producción

Eneste apartado vamos a realizar el despliegue de nuestra aplicación en un entorno de producción, para ello vamos a utilizar nuestro VPS.

Para ello:

  • Vamos a clonar el repositorio de la aplicación en el VPS.
    git clone git@github.com:Legnakra/Tutorial-Django.git
    
  • Creamos un entorno virtual e instalamos las dependencias de nuestra aplicación.
    cd /var/www/html/
    python3 -m venv django
    source django/bin/activate
    pip install -r requirements.txt
    
  • Instalamos el módulo que nos permitirá que python trabaje con mysql:
    apt install python3-dev default-libmysqlclient-dev build-essential -y
    pip install mysqlclient
    
  • Creamos la base de datos y un usuario en mysql.
    mysql -u root -p
    
    CREATE DATABASE django;
    CREATE USER 'django'@'%' IDENTIFIED BY 'admin';
    GRANT ALL PRIVILEGES ON django.* TO 'maria'@'%';
    FLUSH PRIVILEGES;
    EXIT;
    
  • Configuramos la aplicación para trabajar con mysql, por ello, modificamos el fichero settings.py de la siguiente manera:
    DATABASES = {
        'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django',
        'USER': 'django',
        'PASSWORD': 'admin',
        'HOST': 'localhost',
        'PORT': '',
        }
    }
    
  • Creamos una copia de seguridad de la base de datos, teniendo en cuenta que en el entorno de desarrollo hemos utilizado SQLite y en el de producción MySQL. Por ello, lo recomendable es realizar la copia de seguridad y recuperarla con los comandos adecuados.
    python3 manage.py dumpdata > db.json 
    

Y la subimos al repositorio:

    git add db.json
    git commit -m "Copia de seguridad de la base de datos"
    git push
    

Nos conectamos a nuestro VPS y realizamos la migración de la base de datos:

    cd /var/www/html/django_tutorial
    git pull
    pip install pymysql
    python3 manage.py migrate
    python3 manage.py loaddata db.json
    
  • Configuramos el servidor de aplicaciones uwsgi, creando una unidad de systemd (como hemos realizado en el paso 2 de talleres wsgi )y configuramos nginx como proxy inverso para servir la aplicación.

  • Instalamos el módulo uwsgi y lo configuramos

        pip install uwsgi
        ---
        sudo nano /var/www/html/Tutorial-Django/django/uwsgi.ini
        

Añadimos al fichero las siguientes líneas:

        [uwsgi]
        http = :8080
        chdir = /var/www/html/Tutorial-Django
        wsgi-file = /var/www/html/Tutorial-Django/django_tutorial/wsgi.py
        processes = 4
        threads = 2
        
  • Creamos la unidad de systemd para el servicio uwsgi:
        sudo nano /etc/systemd/system/uwsgi.service
        

Añadimos las siguientes líneas:

        [Unit]
        Description=uWSGI Emperor service
        After=network.target

        [Install]
        User=www-data
        Group=www-data
        Restart=always

        ExecStart=/var/www/html/django_tutorial/django/bin/uwsgi --ini /var/www/html/Tutorial-Django/django/uwsgi.ini

        ExecReload=/bin/kill -s HUP $MAINPID
        ExecStop=/bin/kill -s TERM $MAINPID
        WorkingDirectory=/var/www/html/django_tutorial
        Environment=PYTHONPATH='/var/www/html/Tutorial-Django/django_tutorial:/var/www/html/Tutorial-Django/django/lib/python3.9/site-packages'
        PrivateTmp=true
        
  • Y lo activamos:
        sudo systemctl daemon-reload
        sudo systemctl enable uwsgi
        sudo systemctl start uwsgi
        
  • Debemos asegurarnos que el contenido estático se está sirviendo: ¿Se muestra la imagen de fondo de la aplicación? ¿Se ve de forma adecuada la hoja de estilo de la zona de administración?

  • Creamos el VirtualHost de nginx:

        sudo nano /etc/nginx/sites-available/django
        

Añadimos las siguientes líneas:

        server {
            listen 80;
            listen [::]:80;

            root /var/www/html/Tutorial-Django/

            index index.php

            server_name python.mariatec.es;

            location / {
                proxy_pass http://localhost:8080;
                include proxy_params;
            }

            location /static/ {
                alias /var/www/html/Tutorial-Django/static/;
            }
        }
        
  • Desactivamos la configuración el modo debug a False, para que los errores de ejecución no den información sensible de la aplicación.

  • Modificamos el fichero settings.py:

        DEBUG = False
        
  • Creamos el enlace simbólico:
        sudo ln -s /etc/nginx/sites-available/django /etc/nginx/sites-enabled/django
        

Y reiniciamos el servicio:

        sudo systemctl restart nginx
        
  • Realizamos los cambios necesarios en el DNS del VPS para que la URL python.mariatec.es apunte a la IP del VPS.

13

  • La página web deberá ser accesible en la URL: python.mariatec.es. ¿Se muestra la imagen de fondo de la aplicación? ¿Se ve de forma adecuada la hoja de estilo de la zona de administración?

Como podemos ver en las siguientes imagenes, la página, su fondo y su hoja de estilo funcionan correctamente:

Como podemos ver en la siguiente imagen, la página funciona correctamente:

14

15

16

17

Instalamos el certificado SSL.

  • Desactivamos la configuración el modo debug a False, para que los errores de ejecución no den información sensible de la aplicación.

  • Modificamos el fichero settings.py:

    DEBUG = False
    
  • Cambiamos el VirtualHost:
    server {
            listen 80;
            listen [::]:80;
            server_name python.mariatec.es;
            return 301 https://$server_name$request_uri;
    }
    server {
            listen 443 ssl;
            listen [::]:443 ssl;
            server_name python.mariatec.es;
            ssl_certificate /etc/letsencrypt/live/mariatec.es/fullchain.pem;
            ssl_certificate_key /etc/letsencrypt/live/mariatec.es/privkey.pem;
            include /etc/letsencrypt/options-ssl-nginx.conf;
            ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
            root /var/www/html/Tutorial-Django;
            index index.php;
            location / {
                    proxy_pass http://localhost:8080;
                    include proxy_params;
            }
            location /static/ {
                    alias /var/www/html/Tutorial-Django/static/;
            }
    }
    
  • Y reiniciamos el servicio:
    sudo systemctl restart nginx
    
  • Comprobamos que el certificado funciona correctamente:

18

Modificación de la aplicación y migración de los cambios a producción

En este apartado vamos a realizar cambios en el entorno de desarrollo y posteriormente vamos a subirlas a producción. Vamos a realizar tres modificaciones.

Primero vamosa realizar los cambios en el entorno de desarrollo, es decir, en bravo.

  • Modifica la página inicial donde se ven las encuestas para que aparezca tu nombre, para ello modifica el archivo django_tutorial/polls/templates/polls/index.html.
    cd /var/www/html/Tutorial-Django
    nano polls/templates/polls/index.html
    
  • Vamos a realizar los cambios necesarios para que aparezca mi nombre en la página principal:
            <h2>Maria Jesus</h2>
        
  • Modificamos la imagen que aparece como fondo de la aplicación. Para ello, vamos a buscar una imagen nueva, la descargamos y la antigua imagen por la nueva.
    wget https://i.imgur.com/rqzs4jU.jpeg -O fondo.jpg
    
  • Modificamos el propietario del fichero para que el servidor web pueda acceder a él.
    chown -R apache:apache static/polls/images/fondo.jpg
    
  • Modificamos también el fichero de estilo para que apunte a la nueva imagen y para que la renderice.
    nano static/polls/style.css
    ---
    li a {
        color: green;
        background-color: blanchedalmond;
    }

    body {
        background: white url("images/fondo.jpg");
        background-size: cover;
    }
    
  • Centrar la imagen de fondo y que sea responsive.
    body {
        background: white url("images/fondo.jpg");
        background-size: cover;
        background-position: center;
        background-repeat: no-repeat;
        background-attachment: fixed;
    }
    

19

Vamos a crear una nueva tabla en la base de datos, para ello sigue los siguientes pasos:

  • Añadimos un nuevo modelo al fichero polls/models.py:
		class Categoria(models.Model):	
        	Abr = models.CharField(max_length=4)
        	Nombre = models.CharField(max_length=50)

        	def __str__(self):
        		return self.Abr+" - "+self.Nombre 		
        
  • Creamos una nueva migración:
        python manage.py makemigrations
        
  • Aplicamos la migración:
        python manage.py migrate
        

Añadimos el nuevomodelo al sitio de administración de django:

  • Cambiamos la siguiente línea del fichero polls/admin.py:
            from .models import Choice, Question, Categoria
            
  • Añadimos la siguiente línea al fichero polls/admin.py:
            admin.site.register(Categoria)
            
  • Comprobamos que el cambio se ha realizado correctamente:

20

Deplegamos los cambios en el entorno de producción.

  • Realizamos un backup de la base de datos:
        python3 manage.py dumpdata > db2.json
        
  • Añadimos los ficheros que hemos cambiado al repositorio:
        git status
        git add .
        git commit -m "Tarea 3"
        git push
        
  • Nos dirigimos al entorno de producción y actualizamos el repositorio:
        cd /var/www/html/Tutorial-Django
        git pull
        
  • Cargamos los datos y los cambios:
        python3 manage.py loaddata db2.json
        python3 manage.py migrate
        
  • Realizamos de nuevo la recolección de los ficheros estáticos:
        python3 manage.py collectstatic
        
  • Reiniciamos el servicio:
        sudo systemctl restart uwsgi-django
        

Como podemos ver en las siguientes imágenes, los cambios se han realizado correctamente.

21

22

23