13

Cómo crear tu contenedor de Docker para tu aplicación en Django

43474Puntos

hace 9 meses

Curso de Django
Curso de Django

Curso de Django

Crea sitios web fácilmente. Aprende sobre la conectividad y la extensibilidad que ofrecen los nuevos componentes de Django: el framework de desarrollo Web para Python más usado en la actualidad.

Docker resulta útil a la hora de crear un entorno de desarrollo ya que empaqueta la aplicación en contenedores con lo necesario para que pueda funcionar sin importar el sistema operativo que corre. Incluso si no tienes dependencias o servicios, como Postgres instalados en tu máquina.

Este tutorial quiero enseñarte cómo puedes tener tu primer contenedor con una aplicación de Django. Ojo, estoy suponiendo que tienes Pipenv, Docker y Docker Compose.

Dockerfile

7Ha8pRa.png

Lo primero que debemos hacer es crear un proyecto con Django con su entorno virtual.

mkdir PlatziDocker
pipenv install --three django
pipenv run django-admin startproject config .

Listo. Si Pipenv no te resulta familiar, escribí un tutorial acerca de esta herramienta hace un par de semanas, te puede ahorra tiempo a la hora de usar entornos virtuales.

Sigamos, ahora es necesario crear un Dockerfile. Así, sin extensión ni nada parecido.

Nuestro Dockerfile se debe ver así.

FROM python:3.6ENV PYTHONUNBUFFERED 1COPY. /code/
WORKDIR/code/
RUNpip install pipenv
RUNpipenv install --system
EXPOSE8000

La primera línea FROM python:3.6 le dice a Docker que vamos a usar esa imagen como base para construir la nuestra. Es un contenedor de Ubuntu que tiene instalado la versión 3.6 de Python.

La segunda línea ENV PYTHONUNBUFFERED 1 es una variable de entorno diciéndole a Docker que nos muestre el Standart Output(salida) y Standart Error(errores) en la terminal como estamos acostumbrados. De esta misma manera podemos declarar un ENV SECRET_KEY='__KEY__' para tener nuestra llave secreta alejada de nuestro archivo settings.

La tercera línea COPY . /code/ es un comando para copiar todos los archivos y carpetas que se encuentran al mismo nivel (.) del Dockerfile a una carpeta llamada code. Luego en WORKDIR /code/ le decimos que nuestra área de trabajo va a ser esa carpeta, todos los comandos que corramos, se ejecutarán dentro de la misma.

Las siguientes dos líneas RUN pip install pipenv y RUN pipenv install --system le dirán a docker que ejecute esos comandos, primero instalará Pipenv con pip para luego ejecutar la siguiente e instalar las dependencias de nuestro archivo Pipfile.lock y como le estamos pasando como argumento --system no se va a crear un entorno virtual, no lo necesitamos.

Y la última línea EXPOSE 8000, para correr bien runserver nuestro contenedor necesita acceder al puerto 8000.

Listo, con eso ya tenemos nuestro Dockerfile. Ahora solo necesitamos hacer docker build . y vamos a ver una larga lista de cosas en la terminal, diferentes pasos. Todo debería ir bien.

Docker Compose

Ahora, Docker Compose nos ayuda a correr más de un contenedor en nuestra aplicación de Docker, por ejemplo si queremos tener una base de datos como Postgres o un servicio de caché como Redis o un servidor como Nginx. Para esto necesitamos un archivo en el mismo nivel que nuestro archivo Dockerfile y lo llamamos docker-compose.yml, este si tiene una extensión. Es un archivo YAML.

Tendría esto:

versiónversion: '3'

services:	db:    	image: postgres:10.1    	volumes:
        	- postgres_data:/var/lib/postgresql/data
	web:    	build: .
    	command: python /code/manage.py migrate --noinput
    	command: python /code/manage.py runserver 0.0.0.0:8000    	volumes:
        	- .:/code
    	ports:
        	- "8000:8000"    	depends_on:
        	- db
    	environment:
        	- DJANGO_SETTINGS_MODULE=config.settings
        	- SECRET_KEY=${SECRET_KEY}
volumes:postgres_data:

Ahora vamos a explicarlo línea por línea.

La primera version: '3' define la versión de Compose que queremos usar.

Ahora en services vamos a definir, de manera identada, los servicios que queremos corran en diferentes contenedores.

Con el primer servicio le decimos a docker que queremos la imagen de PostgreSQL. Ni siquiera necesitamos tenerlo instalado en nuestra sistema, Docker la descargará desde el Docker Hub con la versión que le especificamos. Y con volumes le decimos en que parte de nuestro contenedor queremos que se guarden los datos, en este caso /var/lib/postgresql/data. Si recuerdan, les dije que nuestra imagen de Python tiene como base una imagen de Ubuntu, eso hace que tenga varios subdirectorios. Un volumen permite que nuestros datos persistan sin importar el ciclo de vida del contenedor

Por supuesto, para esto tenemos que decirle a Django que vamos a usar Postgres como base de datos, así que tenemos que deshacernos de ese sqlite3. Colocaremos esto:

DATABASES = {
	'default': {
    	'ENGINE': 'django.db.backends.postgresql_psycopg2',
    	'NAME': 'postgres',
    	'USER': 'postgres',
    	'PASSWORD': 'postgres',
    	'HOST': 'db',
    	'PORT': '5432',
	}
}

El siguiente servicio es el web y le decimos que construya build . nuestra imagen desde el directorio actual. Los siguientes dos commandos command, uno ejecutará las migraciones sin mostrar la salida en nuestra consola --no-input y el segundo levantará el servidor cuando corramos el contenedor.

volumes al igual que con la base de datos, le dira a nuestro contenedor donde estará nuestro código ./code. Justo después con ports mapeamos nuestro puerto 8000 al puerto 8000 del contenedor de Docker, haciendo que nuestro servidor sea accesible vía localhost:8000 o 0.0.0.0:8000. Ahora depends_on le dice que nuestro servicio web necesita esperar por la base de datos, Compose primero levantará ese servicio antes de pasar a web.

Con environment, puedes adivinar que son variables de entorno. Si es el caso de que estamos trabajando con diferentes archivos settings. Puedes colocar ahí, la variable DJANGO_SETTINGS_MODULE para especificar con cuál archivo quieres trabajar, puede ser local, production o test. La siguiente SECRET_KEY es una manera de llamar a una variable de entorno colocada en un archivo .env

Ya que Pipenv carga automáticamente las variables de un archivo .env podemos usar ese mismo archivo para mandarle la variable de entorno a nuestro contenedor con la línea SECRET_KEY=${SECRET_KEY}

Y nuestras últimas dos líneas, Compose tiene una regla donde tenemos que listar nuestros volúmenes en una llave volumes al mismo nivel de identación que services o version

Con el archivo guardado. Podemos ejecutar ahora docker-compose up también nos mostrará cierta cantidad de información en la terminal pero al final deberías tener un servidor corriendo en localhost:8000 o 0.0.0.0:8000 con la acostumbrada salida de Django.

KLB7fnp.png

Conclusión

De esta manera, puedes olvidarte de los entornos virtuales y de tener algunos programas instalados en tu máquina local, puedes tener tu aplicación empaquetada de esta manera y usarla en cualquier SO mientras tengas Docker instalado. Para saber más acerca de Docker te invito a ver los dos grandes cursos que tiene Platzi, aprenderás esto y más.

Curso de Django
Curso de Django

Curso de Django

Crea sitios web fácilmente. Aprende sobre la conectividad y la extensibilidad que ofrecen los nuevos componentes de Django: el framework de desarrollo Web para Python más usado en la actualidad.
Kevin
Kevin
@iKenshu

43474Puntos

hace 9 meses

Todas sus entradas
Escribe tu comentario
+ 2
Ordenar por:
3
1342Puntos

Buenas algunos detallitos "La segunda línea ENV PYTHONUNBUFFERED 1 es una variable de entorno diciéndole a Docker que nos muestre el Standart Output(salida) y Standart Error(errores) en la terminal"
No se le dice a docker se le dice es al interprete de python.

"De esta misma manera podemos declarar un ENV SECRET_KEY=’__KEY__’ para tener nuestra llave secreta alejada de nuestro archivo settings."
Este tampoco es un buen sitio donde colocar la secret key, no hay diferencia con el settings. swarm tiene los secrets o se puede usar vars de entorno.

"La tercera línea COPY . /code/ es un comando para copiar todos los archivos y carpetas que se encuentran al mismo nivel (.) del Dockerfile ", aqui no es al nivel del dockerfile sino el “context build” que puede ser distinto.

Esta parte “Y la última línea EXPOSE 8000, para correr bien runserver nuestro contenedor necesita acceder al puerto 8000.” no seria para correr bien porque expose es solo una clase de documentacion
De la documentacion de docker
The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.

Lo mismo aqui “Para esto necesitamos un archivo en el mismo nivel que nuestro archivo Dockerfile y lo llamamos docker-compose.yml, este si tiene una extensión. Es un archivo YAML.” no es necesario que este al mismo nivel se puede especificar con “build: dockerfile”

Esto “Ya que Pipenv carga automáticamente las variables de un archivo .env podemos usar ese mismo archivo para mandarle la variable de entorno a nuestro contenedor con la línea SECRET_KEY=${SECRET_KEY}” esa interpolacion no es por pipenv sino porque docker carga automaticamente el archivo .env al mismo nivel si quieres meter variables puedes usar env_file

1
1342Puntos
8 meses

por cierto el .env que carga docker compose no se envia al contenedor solo se usa para la interpolacion de string en el archivo docker-compose

1
1342Puntos
8 meses

tambien haria falta el network para conectar el servicio web y db

1
3137Puntos

Buen tutorial, una pregunta ¿Requiero de un Ubuntu 64bit para poder instalar docker?

1
3137Puntos
8 meses

Parece que no me reconoce el servicio “db” he hecho toda la configuración. y al intentar ir al Admin. me da un error de que el servicio “db” es desconocido.

django.db.utils.OperationalError: could not translate host name "db" to address: Name or service not known
1
1342Puntos
8 meses

no puedes hallar db porque no estan en la misma networks se tienes que especificar una network que los comunique