Despliegue de aplicación de Django con Github Actions para un servidor propio
Jose Miguel Sandoval
Posted on June 3, 2024
Para proyectos en donde la actualización del código es algo recurrente, es ideal realizar un proceso de automatización del despliegue del proyecto, además de asegurarse que este se subió correctamente. Esto se conoce como CI/CD (Integración continua/Despliegue continuo).
Hay varias formas de realizar este proceso para una aplicación de Django, por ejemplo se pueden utilizar contenedores de Docker, automatización con SSH, usando herramientas como Jenkins, etc. Sin embargo, para esta publicación se utilizará la herramienta de Github Actions para realizar este proceso.
Para desplegar este proyecto se utilizará también: Nginx como servidor web/Proxy, Supervisor que es un controlador de procesos, Gunicorn para servir la app y Postgresql que será el gestor de la base de datos.
Esta publicación es un ejemplo básico para subir una aplicación de Django usando Github Actions junto con un testeo previo, para verificar que el código este correctamente configurado antes de realizar el deploy.
Paso 1. Creación de un usuario en el servidor
Para utilizar Github Actions en Ubuntu, se debe utilizar un usuario que no sea el usuario root, si ya tienes otro usuario puedes saltar este paso.
Se creará el usuario ubuntu
, para esto ingresamos al servidor que contratamos y como usuario root ejecutamos el siguiente comando:
sudo adduser ubuntu
Paso 1.1: Se agrega al usuario dentro del grupo sudo
sudo usermod -aG sudo ubuntu
Paso 1.2 (opcional): Configurar sudo para que no necesite contraseña
Solo en caso que se requiera que el nuevo usuario no requiera contraseña al ejecutar sudo, se puede editar el archivo de configuración de sudo:
sudo visudo
En el final del archivo se debe agregar la siguiente línea:
ubuntu ALL=(ALL) NOPASSWD:ALL
Paso 1.3: Ingresar con el nuevo usuario
Ahora puedes ingresar al servidor mediante SSH con el nuevo usuario creado.
Paso 2. Hacer las instalaciones necesarias en el servidor
Primero actualizaremos el servidor y todos sus paquetes ejecutando el siguiente comando:
sudo apt-get update
sudo apt-get upgrade
Una vez actualizado el servidor, instalaremos los paquetes necesarios para realizar el despliegue
sudo apt install python3-pip python3-venv nginx git supervisor nano postgresql postgresql-contrib
Paso 3: Creación de la base de datos
Para manejar la base de datos del proyecto, usaremos PostgreSQL.
Paso 3.1: Ingresar a la terminal de Postgres
Para ingresar a la terminal de Postgres sin necesidad de cambiar de usuario, se puede ejecutar el siguiente comando:
sudo -u postgres psql
Este comando nos abrirá la terminal de Postgres y veremos algo así:
postgres=#
Paso 3.2: Creación de la base de datos y usuario configurado en Django
Una vez dentro de la terminal de Postgres, primero crearemos el usuario, se debe reemplazar "username" y "password" por la configuración que tienes en tu proyecto:
CREATE USER username WITH PASSWORD 'password';
Ahora creamos la base de datos:
CREATE DATABASE db_name;
Para asignarles privilegios un usuario para el uso de la bbdd:
GRANT ALL PRIVILEGES ON DATABASE db_name TO username;
Para establecer un usuario como propietario de la bbdd:
ALTER DATABASE db_name OWNER TO username;
Para salir de la terminal de postgres se ejecuta lo siguiente:
\q
Paso 4: Realizar la configuración de Github Actions Runner para Self Host
Paso 4.1: Crear Runner en Github:
Dentro de la sección "Settings"
del repositorio de nuestro proyecto
se debe ir a Actions y luego a Runners.
Una vez en Runners, se debe hacer clic en el botón New self-hosted runner
. Se abrirá una nueva página con las instrucciones necesarias para configurar el servidor linux.
Paso 4.2: Realizar la configuración en el servidor
Copiamos los comandos de la sección Download
uno por uno y lo vamos ejecutando en el servidor siguiendo las instrucciones que aparece en pantalla. Si se quiere manejar los nombres por default, se debe apretar enter cuando al ejecutar un comando se pida algún texto.
Copiamos el primer comando de la sección Configure
para crear el Runner. Si todo sale bien hasta este punto, puedes ejecutar los siguientes comandos para indicarle al runner que mantenga corriendo el servicio:
sudo ./svc.sh install
sudo ./svc.sh start
sudo ./svc.sh status
Finalmente para verificar que todo esta correcto se puede ejecutar:
./run.sh
Se debiese imprimir en la consola que la conexión con Gihtub es un éxito, para salir del run se puede apretar ctrl + c
.
Paso 5: Configuración de Supervisor
Primero crearemos el archivo de configuración de nuestro servicio gunicorn, para esto nos movemos al directorio conf.d dentro de la carpeta de supervisor:
cd /etc/supervisor/conf.d
Una vez dentro, creamos el archivo gunicorn.conf que contendrá las instrucciones que debe servir supervisor:
sudo nano gunicorn.conf
A continuación mostraré un ejemplo de lo que debe estar escrito dentro del archivo. Lo importante es verificar que las rutas estén escritas correctamente, para esto debes cambiar {name_repository}
por el nombre de tu repositorio y myproject
por el nombre de tu proyecto django:
[program:gunicorn]
directory=/home/ubuntu/actions-runner/_work/name_repository/name_repository
command=/home/ubuntu/actions-runner/_work/name_repository/name_repository/venv/bin/gunicorn --workers 3 --bind unix:/home/ubuntu/app.sock myproject.wsgi:application
autostart=true
autorestart=true
stderr_logfile=/var/log/gunicorn/gunicorn.err.log
stdout_logfile=/var/log/gunicorn/gunicorn.out.log
[group:gunicorn]
programs:gunicorn
Para guardar los cambios apretamos ctrl + o
, y para volver a la terminal ctrl + x
.
Ahora creamos el directorio donde se escribirán los logs de gunicorn:
sudo mkdir /var/log/gunicorn
Para que supervisor lea el archivo de configuración recién creado, se lo indicamos con el siguiente comando:
sudo supervisorctl reread
Nos debería aparecer la siguiente respuesta
gunicorn: available
Por último, para que supervisor ejecute los cambios recién leidos, ejecutamos:
sudo supervisorctl update
Al verificar si el servicio gunicorn esta corriendo correctamente al ejecutar el siguiente comando:
sudo supervisorctl status
Debiese aparecer un error FATAL
con la descripción: can't find command '/home/ubuntu/actions-runner/_work/name_repository/name_repository/venv/bin/gunicorn'
, ya que aun no hemos subido el código a nuestro servidor, eso lo haremos a continuación.
Paso 6: Configuración del workflow de Github Actions
Para este caso se mostrará un ejemplo de como realizar el workflow separandolo en 2 pasos:
- Realizar tests para verificar que el código se suba correctamente.
- Si los tests pasaron correctamente, se subirá el código en el servidor.
Paso 6.1: Creación del archivo YAML de Github Actions
En la raíz del repositorio de github, crearemos la carpeta .github
y dentro de esta la carpeta workflows
. Dentro de esta última carpeta crearemos un archivo con la extensión .yml
, por ejemplo ci-cd.yml
. Por lo que, el repositorio debiese tener una estructura básica como se muestra a continuación:
.
├── .github
│ └── workflows
│ └── ci-cd.yml
├── myproject
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
├── requirements.txt
│
...
Dentro del archivo ci-cd.yml
escribimos las instrucciones que necesita Github Actions para automatizar las tareas:
name: CI CD Django
on:
push:
branches:
- main
jobs:
test:
runs-on: ubuntu-latest # Puedes utilizar un runner predeterminado de GitHub Actions para los tests
services:
postgres:
image: postgres:13
env:
POSTGRES_DB: db_name
POSTGRES_USER: username
POSTGRES_PASSWORD: password
ports:
- 5432:5432
strategy:
max-parallel: 4
matrix:
python-version: [3.10.12]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
- name: Run migrations
run: |
source venv/bin/activate
python manage.py migrate
- name: Run tests
run: |
source venv/bin/activate
python manage.py test
deploy:
needs: test # Este trabajo solo se ejecuta si el trabajo 'test' pasa
runs-on: self-hosted
strategy:
max-parallel: 4
matrix:
python-version: [3.10.12]
steps:
- name: Checkout main branch
uses: actions/checkout@v3
with:
clean: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies # Se instala gunicorn pero debiese estar dentro de requiriments.txt
run: |
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install gunicorn
- name: Run migrations
run: |
source venv/bin/activate
python manage.py migrate
- name: Reset supervisor
run: sudo service supervisor restart
Paso 6.2: Subir el archivo YML a Github para iniciar Github Actions
Hacemos un commit y un push de los cambios para subir nuestra configuración.
Al realizar un push, Github inmediatamente reconocerá el workflow y comenzará a realizar las tareas que se indicaron. Esto lo puedes visualizar dentro de la sección Actions
en tu repositorio de Github.
En caso que la operación sea un éxito, se mostrará un check verde al lado del nombre de la tarea, en caso contrario, aparecerá una x con color rojo.
Paso 6.3: Verificamos que el proyecto se subió al servidor
En caso que la operación haya resultado exitosa, podemos ver que dentro de la carpeta actions-runner
se creo una carpeta llamada _work
, esta carpeta contiene nuestro repositorio, para este caso name_repository
, por lo tanto el directorio de la aplicación de Django debiese estar en la siguiente altura:
cd /home/ubuntu/actions-runner/_work/name_repository/name_repository
Dentro de esta carpeta podemos encontrar la carpeta venv
que contendrá el entorno virtual del proyecto, por lo que podemos activarla y generar comandos con managa.py
como por ejemplo, crear un superusario.
Ahora podemos verificar si Supervisor reconoció el proyecto y se encuentra corriedo, para esto ejecutamos:
sudo supervisorctl status
Si aparece que el servicio esta corriendo RUNNING
, es porque el archivo y el código se encuentran configuradas correctamente. En caso de error, verifica las rutas dentro del archivo gunicorn.conf
Paso 7: Configuración de Nginx
Paso 7.1: Editar nginx.conf
Para configurar Nginx, primero debemos modificar el usuario que tiene configurado por defecto, para esto nos movemos dentro de la carpeta de nginx:
cd /etc/nginx
Una vez ahí, editamos el archivo nginx.conf de la siguiente forma:
sudo nano nginx.conf
Al principio del archivo, aparecerá la siguiente instrucción:
user www-data;
# resto de la configuracion
Borramos la parte que dice www-data y la cambiamos por root:
user root;
# resto de la configuracion
Guardamos los cambios con ctrl + o
seguido de ctrl + x
.
Paso 7.2: Configurar Nginx para subir nuestro proyecto
Para configurar Nginx e indicarle que tiene que desplegar nuestro proyecto, nos vamos a la siguiente ruta:
cd /etc/nginx/sites-available
Una vez aquí, creamos un arhivo de configuración, que contendra todas las instrucciones necesarias para que nginx sirva nuestra aplicación, el nombre del archivo puede ser cualquiera pero con extensión .conf
. Ejemplo:
sudo nano django.conf
A continuación, mostraré un ejemplo básico de como configurar el archivo, pero pueden haber muchas más configuraciones para personalizar el funcionamiento de Nginx. Ejemplo:
server{
listen 80;
server_name 198.23.227.182; # Aqui va el dominio. Ejemplo: midominio.com o una dirección IP (no recomendado)
location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/app.sock;
}
location /static {
alias /home/ubuntu/actions-runner/_work/name_repository/name_repository/static;
}
location /media {
alias /home/ubuntu/actions-runner/_work/name_repository/name_repository/media;
}
}
Deberías verificar que las rutas a los archivos estáticos y de media sea correcta cambiando name_repository
, por el nombre de tu repositorio.
El dominio indicado, debe estar configurado dentro del archivo settings.py de Django en ALLOWED_HOSTS. Ejemplo:
ALLOWED_HOSTS = ['*'] # El * permite cualquier HOST (no recomendado). Aquí debiese ir tu dominio
Para verificar que la sintaxis del archivo este escrita correctamente, ejecutamos:
sudo nginx -t
Debiese aparecer un mensaje como el siguiente:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Ahora ejecutamos el siguiente comando para crear un enlace simbólico que referenciara al archivo de configuración recién creado:
sudo ln /etc/nginx/sites-available/django.conf /etc/nginx/sites-enabled
Reiniciamos el servicio de nginx:
sudo service nginx restart
Y si ahora buscamos el dominio ingresado dentro de nuestro navegador, debiésemos ver nuestro proyecto desplegado.
Conclusiones
Siguiendo estos pasos, podrás tener tu proyecto de Django desplegado usando las herramientas mencionadas en este artículo.
Hay varias formas de realizar un despliegue usando Github Actions y Django, lo importante es realizar testeos previos a realizar el deploy de tu proyecto, para que no existan errores en producción.
Espero que te haya sido de utilidad :) Cualquier duda, consulta o sugerencia, házmela llegar a través de los comentarios.
Posted on June 3, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
June 3, 2024