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'),
    }
}

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
  • Creamos el usuario Administrador:
python django_tutorial/manage.py createsuperuser
---
password: admin
  • 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

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:
  • Creamos dos preguntas con varias respuestas.

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:

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:

  1. Vamos a clonar el repositorio de la aplicación en el VPS.
git clone git@github.com:Legnakra/Tutorial-Django.git
  1. 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
  1. 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
  1. 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;
  1. 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': '',
    }
}
  1. 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
  1. 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
  1. 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/;
        }
    }
  1. 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.
  1. 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:

  1. 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:

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.

  1. 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>
  1. 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;
}
  1. 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:
  • 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.