Cómo correr un proyecto de Django con Docker
Una de las cosas que he estado haciendo esta cuarentena es aprovechar para aprender a utilizar Docker y desde que terminé el curso me apetece aplicarlo en todos mis proyectos 🚀. Si no sabes nada de Docker te recomiendo que investigues en su web o realices algún curso sobre ello, sino vas a estar muy perdido y no queremos eso 😅.
Este tutorial está basado en la documentación oficial de docker pero con algunas mejoras como crear variables de entorno y persistir los datos guardados en PostgreSQL al parar el contenedor.
Lo primero que haremos será crear una carpeta donde guardaremos todo el proyecto, yo para este ejemplo he creado una carpeta llamada django_docker_proyect.
Lo siguiente es crear el archivo requirements.txt para posteriormente decirle que librerías queremos instalar, en nuestro caso Django y psycopg2.
Django>=2.0,<3.0
psycopg2>=2.7,<3.0
Ahora vamos a crear un archivo Dockerfile sobre un contenedor basado en Python 3. En él crearemos un directorio llamado code y le diremos que es el directorio de trabajo, después copiaremos el archivo requirements.txt en el contenedor y utilizaremos pip para instalar las librerías que usaremos.
FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
Si queréis saber más sobre el contenedor de Python podéis verlo en su repositorio en github.
Ahora que ya tenemos esta parte, vamos a crear una carpeta llamada .envs y dentro de ella un archivo llamado .postgres donde guardaremos nuestras variables de entorno que se utilizarán más adelante en el contenedor de postgres:
# PostgreSQL
POSTGRES_HOST=db
POSTGRES_PORT=5432
POSTGRES_DB=mydb
POSTGRES_USER=Ds5DTAxP
POSTGRES_PASSWORD=5nFyHgRtx8z3Mf5kcar8d2D4yQrVgFE2
El host es el nombre del servicio, en db, user y password podemos poner lo que queramos, el contenedor de PostgreSQL creará la configuración de la bbdd y el usuario y contraseña basándose en los datos encontrados en las variables de entorno.
Ya tenemos lista toda la configuración, ahora crearemos el archivo docker-compose.yml.
version: '3'
services:
db:
image: postgres
env_file:
- ./.envs/.postgres
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
env_file:
- ./.envs/.postgres
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
En este archivo le decimos los servicios que queremos correr que serán la base de datos y el proyecto web.
En db le pasamos la imagen de PostgreSQL que es la que queremos usar y le pasamos nuestro archivo con las variables de entorno para usarlas al crear la base de datos.
- En el servicio web le decimos que se construya en base el archivo Dockerfile.
- En command el comando para ejecutar el proyecto.
- En env_file el archivo con las variables de entorno (para poder comunicarnos con la base de datos).
- Con volumes le decimos que copie todo lo que hay en el directorio raíz a la carpeta, con eso mientras el contenedor este corriendo se sincronizará automáticamente todos los cambios que realicemos de nuestra máquina al contenedor.
- En ports le decimos tanto el puerto de nuestra máquina como el del contenedor que usará para poder comunicarnos con el proyecto.
- Por último con depends_on le diremos que este servicio depende del servicio db.
Una vez hecho esto crearemos el proyecto con la siguiente orden, sustituir <nombre-proyecto> por el nombre que le queráis poner.
docker-compose run web django-admin startproject <nombre-proyecto> .
Para finalizar la construcción del contenedor lanzaremos la ordern build
docker-compose -f docker-compose.yml build
Ahora que ya tenemos el proyecto creado, modificaremos el archivo settings.py del proyecto de Django, para ello en nuestra carpeta raíz, buscamos en <nombre-proyecto/settings.py y realizamos las siguientes modificaciones para poder comunicarnos con nuestra base de datos.
ALLOWED_HOSTS = ['*']
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ['POSTGRES_DB'],
'USER': os.environ['POSTGRES_USER'],
'PASSWORD': os.environ['POSTGRES_PASSWORD'],
'HOST': os.environ['POSTGRES_HOST'],
'PORT': os.environ['POSTGRES_PORT'],
}
}
Con esto ya estaría todo listo, lanzamos up para levantar el servicio y ya tendríamos nuestro proyecto completamente listo.
docker-compose up
Ahora accedemos a http://localhost:8000 y ya podremos ver nuestro proyecto en funcionamiento.
Bueno bueno, esto está muy bien pero cada vez que paremos el contenedor perderemos los datos almacenados en la base de datos por lo que sería un rollazo tener que estar creando los datos de nuevo cada vez que corramos nuestro contenedor. Para solucionar esto abrimos el archivo docker-compose.yml y añadiremos unas modificaciones en el servicio db.
version: '3'
services:
db:
image: postgres
env_file:
- ./.envs/.postgres
volumes:
- /opt/postgres-data:/var/lib/postgresql/data
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
env_file:
- ./.envs/.postgres
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
En el servicio db en volumes le hemos dicho que queremos montar nuestra carpeta /opt/postgres-data (deberéis crearla previamente) con la carpeta del contenedor de postgres que es /var/lib/postgresql/data y es donde se almacenan todos los datos generados en postgres, de esta manera aunque paremos el contenedor seguiremos manteniendo los cambios.
Lanzamos de nuevo el build y el up y ya estaría listo.
docker-compose -f docker-compose.yml build
docker-compose up
Para comprobar que podemos acceder al admin de Django haremos el makemigrations y migrate para crear las tablas en la base de datos, para ello ahora lo tendremos que lanzar de esta forma:
docker-compose -f .\docker-compose.yml run --rm web python manage.py makemigrations
docker-compose -f .\docker-compose.yml run --rm web python manage.py migrate
Y ahora crearemos el super usuario para poder entrar al panel con la siguiente orden:
docker-compose -f .\docker-compose.yml run --rm web python manage.py createsuperuser
Por último, con nuestro contenedor corriendo accedemos a http://localhost:8000/admin y comprobamos que podemos realizar el login sin problema.
Conclusiones de usar Docker con Django
- Me he ahorrado la instalación de Postgresql en mi máquina.
- Al compartir el proyecto, trabajaría con mis compañeros con la misma configuración lo que evitaría errores de configuración.
- Es rápido, una vez aprendes a hacerlo te sirve para crear cualquier proyecto con Django.
Como siempre he creado un repositorio en github llamado docker_x_django y cualquier duda o problema podéis ponerlo en los comentarios :)
Espero que este post te ayude y como siempre, te recomiendo seguirme en Twitter para estar al tanto de los nuevo contenido. Ahora también puedes seguirme en Instagram donde estoy subiendo tips, tutoriales en vídeo e información sobre herramientas para developers.
Por último os dejo mi guía para aprender a trabajar con APIs donde explico todo el funcionamiento de una API, el protocolo HTTP y veremos como construir una API con arquitectura REST.
Nos leemos 👋.