ksergio.com

I love coding

← Volver

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 :)