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.
Lo siguiente es una imagen para montar nuestra base de datos, para este ejercicio decidí usar mysql en su versión 5.7
Creamos una carpeta la cual va a contener nuestro proyecto
~/ $ mkdir dockerproject
~/ $ cd dockerproject
~/dockerproject $
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
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
Creamos nuestro directorio de trabajo.
WORKDIR /code
Ahora necesitaremos instalar Django y el cliente de mysql para Python, en este paso usaremos el archivo de requirements.
COPY requirements.txt /code/
En este punto podemos instalar las dependencias con la siguiente instrucción.
RUN pip install -r requirements.txt
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/
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/
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
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
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 .
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 .
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
}
}
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'
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
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
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
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
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
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 ###
Para comprobar que todo funciona correctamente iniciando los servicios con el comando:
~/dockerproject $ docker-compose up -d
Si todo esta correcto al ir a nuestro navegador e introducir localhost:8085 podremos ver una pantalla como la siguiente:
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
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
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:
Top comments (1)
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.