Como configurar Django con Gunicorn, Nginx y Mysql
11/2/2024
Como dejar desplegado una aplicación de Django con Gunicorn, NGINX y MySQL.
Teniendo en cuenta que el projecto es un directorio llamado /app y dentro el proyecto esta configurado para llamarese server. Existe una carpeta /app/server que es el punto de entrada de la aplicación.
Dockerfile para Django
Este archivo es el encargado de montar la aplicación de Django.
# pull official base image
FROM python:3.11.4
# set work directory
WORKDIR /usr/src/app
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# install dependencies
RUN pip install --upgrade pip
COPY ./requirements.txt .
RUN pip install -r requirements.txt
# copy project
COPY . .
NGINX
Para servir la aplicación no voy a usar el runserver por defecto sino que vot a usar gunicorn para enlazar el servidor WSGI de Python con un servidor Nginx.
Dockerfile
FROM nginx:1.25
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d
nginx.conf
Dejo a Nginx manejar los archivos estáticos de que existen en el proyecto de Django en /app/static (esto lo configuro con los settings.py)
upstream web_api {
server web:8000;
}
server {
listen 80;
location /static/ {
alias /usr/src/app/static/;
}
location / {
proxy_pass http://web_api;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
}
Settings .py
Es importante setear donde van a estar los archivos estaticos. Si es necesario hay que usar el comando python manage collectstatic
para posibles estáticos de librerías externas.
Por otro lado uso variables de entorno que se declaran en el archivo docker-compose.yml.
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / "static"
DATABASES = {
"default": {
"ENGINE": os.environ.get("SQL_ENGINE", "django.db.backends.sqlite3"),
"NAME": os.environ.get("SQL_DATABASE", BASE_DIR / "db.sqlite3"),
"USER": os.environ.get("SQL_USER", "user"),
"PASSWORD": os.environ.get("SQL_PASSWORD", "password"),
"HOST": os.environ.get("SQL_HOST", "localhost"),
"PORT": os.environ.get("SQL_PORT", "5432"),
}
}
# Importante cambiarla siempre
SECRET_KEY = os.environ.get("SECRET_KEY","ESTO_ES_UNA_CLAVE_POR_DEFECTO_CAMBIALA!!!")
# Por defecto en 0 por si acaso
DEBUG = bool(os.environ.get("DEBUG", default=0))
# Aquí configurar posibles hosts. "*" da acceso a todos
ALLOWED_HOSTS = ['*']
docker-compose.yml
Para acabar de juntarlo todo. La base de datos puede tener acceso al exterior o dejar que solo se comunique con Django en una red interna. Esto es cuestión de configurarlo.
version: '3.8'
services:
web:
build: ./app
command: bash -c "gunicorn server.wsgi:application --bind 0.0.0.0:8000"
volumes:
- ./app/:/usr/src/app/
- static_volume:/usr/src/app/static/
expose:
- 8000
env_file:
- ./.env.dev
depends_on:
- mysql
mysql:
image: mysql:8.3.0
restart: always
environment:
MYSQL_DATABASE: 'khudos-dev'
# Password for root access
MYSQL_ROOT_PASSWORD: 'root'
ports:
# <Port exposed> : <MySQL Port running inside container>
- '3306:3306'
expose:
# Opens port 3306 on the container
- '3306'
# Where our data will be persisted
volumes:
- ./mysql:/var/lib/mysql
nginx:
build: ./nginx
ports:
- 1337:80
volumes:
- static_volume:/usr/src/app/static/
depends_on:
- web
# Names our volume
volumes:
mysql:
static_volume:
Con esto debería funcionar. Pero hay cositas que configurar :)