DEV Community

Adrian Garay
Adrian Garay

Posted on • Updated on

Dockerizar un proyecto Django

Introduccion

Docker es una herramienta que como desarrolladores debemos estar dispuestos a aprender nos permite hacer el despliegue de nuestras aplicaciones de una manera rápida y sencilla ademas de hacer que nuestros proyectos sean fáciles de distribuir. A continuación vamos a descubrir como dockerizar nuestra app en Django.

Elegir nuestras imágenes y el espacio de trabajo

Lo primero es saber que imágenes necesitamos y para ello lo primero es una imagen de con la que podremos usar el lenguaje.

python - Docker Hub

Lo siguiente es una imagen para montar nuestra base de datos, para este ejercicio decidí usar mysql en su versión 5.7

mysql

Creamos una carpeta la cual va a contener nuestro proyecto

~/ $ mkdir dockerproject
~/ $ cd dockerproject
~/dockerproject $
Enter fullscreen mode Exit fullscreen mode

Definir dependencias

Para nuestro proyecto en Django necesitamos las librerías correspondientes ademas del interpretador de lenguaje Python, asi que necesitamos definir las dependencias de nuestro proyecto.

Creamos un archivo de nombre requirements.txt en nuestro espacio de trabajo el cual tiene que contener la versión de Django que vamos a usar y el cliente para mysql.

Django>=3.0,<4.0
mysqlclient>=2.0
Enter fullscreen mode Exit fullscreen mode

El cliente de mysql es necesario ya que no se encuentra en las librerías por defecto para la versión 3 de Python, asi que lo agregaremos manualmente.

Nuestro servidor de Python

Dentro de la carpeta vamos a crear un archivo de nombre Dockerfile, esta sera nuestra imagen local de Python en la cual podremos definir una serie de instrucciones necesarias para el inicio de nuestro proyecto.

Definimos la imagen base.

FROM python:3
Enter fullscreen mode Exit fullscreen mode

Creamos nuestro directorio de trabajo.

WORKDIR /code
Enter fullscreen mode Exit fullscreen mode

Ahora necesitaremos instalar Django y el cliente de mysql para Python, en este paso usaremos el archivo de requirements.

COPY requirements.txt /code/
Enter fullscreen mode Exit fullscreen mode

En este punto podemos instalar las dependencias con la siguiente instrucción.

RUN pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

Y poner una copia de nuestro código en la carpeta en la que nos encontramos dentro de nuestro directorio de trabajo en el contenedor de Docker

COPY . /code/
Enter fullscreen mode Exit fullscreen mode

Al final deberíamos de tener un archivo como el siguiente Dockerfile

FROM python:3

WORKDIR /code

COPY requirements.txt /code/

RUN pip install -r requirements.txt

COPY . /code/
Enter fullscreen mode Exit fullscreen mode

Con el siguiente comando en la terminal podemos comprobar que nuestra imagen se puede procesar correctamente.

~/dockerproject $ docker build .
[+] Building 0.4s (10/10) FINISHED
 => [internal] load build definition from Dockerfile                                                       0.0s
 => => transferring dockerfile: 31B                                                                        0.0s
 => [internal] load .dockerignore                                                                          0.0s
 => => transferring context: 2B                                                                            0.0s
 => [internal] load metadata for docker.io/library/python:3                                                0.0s
 => [1/5] FROM docker.io/library/python:3                                                                  0.0s
 => [internal] load build context                                                                          0.1s
 => => transferring context: 2.43kB                                                                        0.0s
 => CACHED [2/5] WORKDIR /code                                                                             0.0s
 => CACHED [3/5] COPY requirements.txt /code/                                                              0.0s
 => CACHED [4/5] RUN pip install -r requirements.txt                                                       0.0s
 => CACHED [5/5] COPY . /code/                                                                             0.0s
 => exporting to image                                                                                     0.1s
 => => exporting layers                                                                                    0.0s
 => => writing image sha256:13e36e422c69799feb5105373d4b04d78c683c7527294be29c80a7940a6374b4               0.0s
Enter fullscreen mode Exit fullscreen mode

Ahora podemos comprobar que las dependencias se instalaron correctamente con el hash de la imagen que nos devuelve el comando anterior y con la siguiente instrucción. Si todo esta correcto Python debería de regresar la versión de Django instalada

~/dockerproject $ docker run 13e36e422c69799feb5105373d4b04d78c683c7527294be29c80a7940a6374b4 python -m django --version
3.2
Enter fullscreen mode Exit fullscreen mode

Crear el proyecto

Para el siguiente paso podemos crear el proyecto desde nuestro contenedor asi que ejecutaremos el siguiente comando. El comando puede variar en el parámetro directorio-actual y el cual te dejo ejemplos para Linux y Windows.

~/dockerproject $ docker run -it --volume <directorio-actual>:/code <hash-de-la-imagen> python -m django startproject dockerproject .
Enter fullscreen mode Exit fullscreen mode
Windows $ docker run -it --volume %cd%:/code <hash-de-la-imagen> python -m django startproject dockerproject .
Linux $ docker run -it --volume $(pwd):/code <hash-de-la-imagen> python -m django startproject dockerproject .
Enter fullscreen mode Exit fullscreen mode

Al finalizar obtendremos un nuevo directorio con el nombre del proyecto que contiene los archivos de configuración del proyecto y un archivo de nombre manage.py que nos permitirá ejecutar comando de Django de nuestro proyecto.

Ahora tenemos que decirle a Django que conexión de base de datos va a usar y esto lo podremos hacer con el archivo de configuración /dockerproject/setting.py en la linea 76 con la constante DATABASES.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'project',
        'USER': 'root',
        'PASSWORD': 'password',
        'HOST': 'docker_python_db',
        'PORT': 3306
    }
}
Enter fullscreen mode Exit fullscreen mode

Docker compose

Para una gestión mas limpia de los contenedores de nuestro proyecto usaremos docker compose.

Creamos el archivo docker-compose.yml en el cual definiremos los servicios para nuestro proyecto.

Primero definimos que versión de compose vamos a usar.

version: '3.8'
Enter fullscreen mode Exit fullscreen mode

Después definimos los servicios que vamos a usar, en primer lugar nuestro servidor web.

# version
web:
    container_name: ${PROJECT_NAME}_web
    build: .
    working_dir: /code
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - '8085:8000'
    expose:
      - '8000'
    links:
      - mysql
    networks:
      backend:
        ipv4_address: 192.20.0.5
Enter fullscreen mode Exit fullscreen mode

Explicando un poco la definición de este servicio vamos a poner como nombre del contenedor el nombre del proyecto mas la terminación _web. El contenedor se va a genera desde el contexto del mismo directorio en el cual se encuentra nuestra imagen en Dockerfile. El directorio de trabajo sera /code y el comando que se estará ejecutando el cual va a ser:

command: python manage.py runserver 0.0.0.0:8000
Enter fullscreen mode Exit fullscreen mode

Este comando iniciara el servidor de test que provee Django, este sera el comando que se estará ejecutando en el ciclo de vida del contenedor. Después con volumes vamos a pedir a Docker compose que cree una copia de nuestro directorio dentro del directorio de trabajo del contenedor y esto nos servirá para la ejecución del código en el contenedor.

Con ports le indicaremos el mapa de puertos de nuestro host y el contenedor, en este caso mapeamos el puerto 8085 de nuestro host al puerto 8000 del contenedor y el cual es usado para el servidor.

La instrucción expose nos permite agregar metadata que para saber en que puerto se estará publicando la aplicación.

La instrucción links nos permite ligar a otro servicio el que se esta definiendo, en otras palabras nos permite definir que el servicio web va a interactuar con mysql.

Finalmente networks define la red por la cual se comunicaran los diferentes servicios. En esta parte especificamos una dirección ip fija.

Ahora podemos añadir el servicio de mysql para nuestra base de datos.

# web
mysql:
    container_name: ${PROJECT_NAME}_db
    image: 'mysql:5.7'
    volumes:
      - './database/data:/var/lib/mysql'
    ports:
      - '3308:3306'
    networks:
      backend:
        ipv4_address: 192.20.0.6
    environment:
      MYSQL_DATABASE: project
      MYSQL_ROOT_PASSWORD: password
Enter fullscreen mode Exit fullscreen mode

Aquí definimos el nombre del contenedor, que usa la imagen mysql:5.7 y que estará montando un volume de la carpeta ./database/data en /var/lib/mysql este paso nos permitirá mantener la base de datos que se cree en el contenedor de mysql y asi no tendremos que definir la base de datos cada que iniciamos los servicios. Mapeamos el puerto 3308 al 3306 que usa mysql en el contenedor y definimos la red a la que estará conectada con su respectiva ip. Finalmente para el contenedor de mysql podemos definir dos variables de entorno MYSQL_DATABASE nos permite definir la base de datos que se creara cuando el servicio inicie y ademas MYSQL_ROOT_PASSWORD que define la contraseña del usuario root.

Como ultimo con docker-compose definimos la red backend que se uso en los servicios anteriores. La red backend usara el driver bridge y una configuración donde las direcciones ip tendrán una mascara de 24 y empezaran con 192.20.0.

# version
# services
networks:
  backend:
    driver: bridge
    ipam:
      config:
        - subnet: 192.20.0.0/24
Enter fullscreen mode Exit fullscreen mode

Al final tendrías un archivo docker-compose.yml como el siguiente:

version: '3.8'

services:

  web:
    container_name: ${PROJECT_NAME}_web
    build: .
    working_dir: /code
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - '8085:8000'
    expose:
      - '8000'
    links:
      - mysql
    networks:
      backend:
        ipv4_address: 192.20.0.5

  mysql:
    container_name: ${PROJECT_NAME}_db
    image: 'mysql:5.7'
    volumes:
      - './database/data:/var/lib/mysql'
    ports:
      - '3308:3306'
    networks:
      backend:
        ipv4_address: 192.20.0.6
    environment:
      MYSQL_DATABASE: project
      MYSQL_ROOT_PASSWORD: password

networks:
  backend:
    driver: bridge
    ipam:
      config:
        - subnet: 192.20.0.0/24
Enter fullscreen mode Exit fullscreen mode

Necesitamos definir nuestra variable de entorno para el nombre del proyecto. Para esto creamos un archivo .env en nuestro directorio de trabajo el cual tiene que contener lo siguiente:

###< docker ###
PROJECT_NAME=docker_python
###> docker ###
Enter fullscreen mode Exit fullscreen mode

Para comprobar que todo funciona correctamente iniciando los servicios con el comando:

~/dockerproject $ docker-compose up -d
Enter fullscreen mode Exit fullscreen mode

Si todo esta correcto al ir a nuestro navegador e introducir localhost:8085 podremos ver una pantalla como la siguiente:

Alt Text

Migraciones

Como ultimo podemos correr las migraciones en la base de datos, estas migraciones serán las migraciones del modulo admin de Django, para este paso podremos usar el siguiente comando:

~/dockerproject $ docker exec -it docker_python_web bash
Enter fullscreen mode Exit fullscreen mode

El cual ejecuta el comando bash en el contenedor web, desde el que podremos ejecutar las migraciones con:

root@<hash>: /code# python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

Conclusion

Docker es siempre una excelente opción para la distribución de nuestras aplicaciones, podemos personalizar una imagen local y adecuarla a nuestras necesidades, ademas con solo instalar Docker tendremos una serie de herramientas poderosas para un desarrollo mas rápido y en este caso sin tener que instalar Python directamente en nuestra computadora podremos iniciar un proyecto en Django.

Puedes consultar el código en:

GitHub logo AdGARAY / docker-python

This is a skeleton for dockerized python project

Top comments (1)

Collapse
 
cristianec profile image
Cristian

Hola soy nuevo en esto, es muy bueno tu post segui los pasos y me funciono correctamente solo que me surgio una duda, espero y tengas el tiempo para responder.

Cuando creo la imagen con el comando docker build . se crea una imagen, ejecuto docker run -it --volume $(pwd):/code python -m django startproject dockerproject . .

Al ejecutar el docker-compose up se crea otra imagen, esto es normal?
por que se crea una segunda imagen de forma automatica? esto es normal?

Espero y me haya explicado bien.