Implementación de aplicaciones Django en AWS EC2 con Docker

AWS EC2 ofrece aplicaciones de aprovisionamiento y alojamiento en la nube con escalado automático. Implementaremos una aplicación Django en EC2 con Docker.

Introducción

En el vertiginoso campo de las aplicaciones web, la creación de contenedores se ha vuelto no solo común, sino también el modo preferido de empaquetar y entregar aplicaciones web. Los contenedores nos permiten empaquetar nuestras aplicaciones e implementarlas en cualquier lugar sin tener que reconfigurar o adaptar nuestras aplicaciones a la plataforma de implementación.

A la vanguardia de la contenedorización está Estibador, que es una herramienta que se utiliza para empaquetar y ejecutar aplicaciones en contenedores que son independientes de la plataforma. La tecnología sin servidor también está floreciendo en esta era de contenedorización y está demostrando ser la opción preferida por los desarrolladores cuando implementan sus aplicaciones con más y más proveedores que permiten a los usuarios implementar software en contenedores.

Si bien la creación de una aplicación es importante, ponerla a disposición de los usuarios finales también es una parte crucial del producto. En esta publicación, empaquetaremos una aplicación Django usando Docker y la implementaremos en EC2 de Amazon.

¿Qué es EC2?

Nube informática elástica (EC2) de Amazon es una oferta que permite a los desarrolladores aprovisionar y ejecutar sus aplicaciones mediante la creación de instancias de máquinas virtuales en la nube. EC2 también ofrece escalado automático donde los recursos se asignan en función de la cantidad de tráfico recibido.

Al igual que cualquier otra oferta de AWS, EC2 se puede integrar fácilmente con los demás servicios de Amazon, como el Servicio de cola simple (SQS), o el Servicio de almacenamiento sencillo (S3), entre otros.

EC2 tiene las siguientes características:

  • Instancias: entornos informáticos virtuales o servidores que permiten a los desarrolladores ejecutar sus aplicaciones. Estas instancias se pueden configurar en términos de memoria, almacenamiento, poder de cómputo y recursos de red para adaptarse a la necesidad o escenario actual.
  • Imágenes de Amazon Machine (AMI): plantillas preconfiguradas que se utilizan para crear instancias. Vienen con sistemas operativos y software precargado según sea necesario y son personalizables.
  • Volúmenes de almacenamiento de instancias: se utiliza para almacenar datos temporalmente. Estos datos se eliminan cuando se termina la instancia.
  • Volúmenes de Elastic Block Store (EBS): Volúmenes de almacenamiento altamente disponibles y confiables que se adjuntan a las instancias con el fin de almacenar datos de manera persistente. Los datos almacenados en los volúmenes de EBS sobreviven a las instancias y se pueden montar varios volúmenes en una instancia.
  • Grupos de seguridad: cortafuegos virtuales que gobiernan el acceso a las instancias especificando protocolos, rangos de direcciones IP y puertos. Esto nos permite controlar y restringir el tráfico a nuestras instancias.

Estas son solo algunas de las características de Elastic Compute Cloud de Amazon y se pueden encontrar más en la documentación.

Requisitos previos

En este tutorial, crearemos una aplicación web y la implementaremos en el servicio EC2 de Amazon. Para lograrlo necesitamos:

  • Una cuenta de Amazon Web Services (AWS) que nos dará acceso a EC2. A través de este enlace, puede registrarse en el nivel gratuito, que es suficiente para el trabajo de esta publicación.
  • Python 3.6+, Pip y Virtualenv instalados para compilar nuestra aplicación Django.
  • Estibador también será necesario para empaquetar nuestra aplicación y ejecutarla fácilmente en un contenedor que no solo es portátil sino que puede ejecutarse en cualquier lugar donde esté instalado Docker.

Dockerización de una aplicación Django

Comenzaremos por construir nuestra aplicación Django simple y colocarla en un contenedor para permitirnos implementarla fácilmente. Comencemos con la creación de una carpeta para nuestro proyecto:

1
$ mkdir django_ec2 && cd $_

Luego un entorno virtual:

1
$ virtualev --python=python3 env --no-site-packages

Luego, activemos e instalemos Django:

1
2
$ source env/bin/activate
$ pip install Django

Una simple aplicación Django de marcador de posición será suficiente. Todo lo que tenemos que hacer para iniciar el proyecto es ejecutar el comando startproject de django-admin, que inicia un proyecto básico para el nombre de directorio dado:

1
$ django-admin startproject django_ec2_project

Luego, entremos al directorio del proyecto:

1
$ cd django_ec2_project

E inicie un servidor de desarrollo ligero:

1
$ python manage.py runserver

Si todo va bien, deberíamos poder ver la siguiente página de destino cuando accedamos a nuestra aplicación en localhost:8000:

django_setup

Antes de empaquetar nuestra aplicación Django, debemos permitir el tráfico a todas las fuentes, lo que podemos lograr modificando la configuración ALLOWED_HOSTS en django_ec2_project/django_ec2_project/settings.py:

1
2
# Add the asterisk in the empty list
ALLOWED_HOSTS = ['*']

Nota: No es recomendable dejar un comodín en un entorno de producción. Utilice el dominio de su propio sitio de producción en lugar de este.

Dado que esto es suficiente para ser implementado, sigamos adelante y contengamos nuestra aplicación agregando un Dockerfile en la raíz de nuestro proyecto que contenga lo siguiente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
FROM python:3.6-alpine

MAINTAINER Robley Gori <ro6ley.github.io>

EXPOSE 8000

RUN apk add --no-cache gcc python3-dev musl-dev

ADD . /django_ec2

WORKDIR /django_ec2

RUN pip install -r requirements.txt

RUN python django_ec2_project/manage.py makemigrations

RUN python django_ec2_project/manage.py migrate

CMD [ "python", "django_ec2_project/manage.py", "runserver", "0.0.0.0:8000" ]

Este Dockerfile describe cómo se organizará y ejecutará nuestra aplicación. En la parte superior, usamos una imagen base que viene con Python 3.6 instalado. También exponemos el puerto 8000, lo que significa que el tráfico en el contenedor debe dirigirse a ese puerto, que también es desde donde se ejecutará nuestra aplicación Django. Instalamos algunos paquetes en nuestra imagen y luego agregamos nuestra aplicación Django al directorio django_ec2.

Dado que nuestro proyecto Django está en contenedores, no necesitaremos crear un entorno virtual ya que ya está aislado de la máquina que lo ejecutará. Por lo tanto, instalamos los requisitos directamente y ejecutamos las migraciones.

Al final, agregamos el comando que se ejecutará cuando se inicie el contenedor, que en nuestro caso también iniciará nuestra aplicación Django y la ejecutará en el puerto 8000.

Si desea obtener una explicación más detallada sobre este tema, consulte nuestro artículo Dockerización de aplicaciones de Python.

El siguiente paso será construir nuestra imagen Docker usando el Dockerfile anterior. Antes de eso, guardaremos las dependencias instaladas en el entorno en un archivo:

1
$ pip freeze > requirements.txt

Y solo entonces, construyamos la imagen de la ventana acoplable:

1
$ docker build . -t django_ec2

A través de este comando, Docker buscará nuestro Dockerfile en la carpeta actual y lo usará para construir una imagen, que será etiquetada como django_ec2. Una vez que nuestra imagen está construida, podemos ejecutarla usando el comando:

1
$ docker run -d -p 8000:8000 django_ec2

Este comando iniciará nuestro contenedor que tiene nuestra aplicación Django en ejecución y asignará el puerto 8000 en nuestra máquina al puerto 8000 del contenedor, como se especifica en el indicador -p y se ejecutará sin cabeza (incluso después de que cerrar la terminal) como se especifica en el indicador -d.

La misma página de inicio de Django debería darnos la bienvenida cuando naveguemos a localhost:8000 una vez más, solo que esta vez accederemos a la aplicación en el contenedor Docker en lugar de acceder a la aplicación en nuestra máquina local.

Con nuestra imagen lista, debemos publicarla en Dockerhub para facilitar el proceso de implementación en EC2.

Dockerhub es un registro de imágenes preparadas que permite a los usuarios crear y compartir imágenes de Docker personalizadas para todos los fines. También nos permite publicar nuestras imágenes para que sean accedidas en otras plataformas como AWS. En nuestro caso, publicaremos nuestra imagen en Dockerhub y luego la llevaremos a EC2 para su implementación.

Para publicar nuestra imagen, primero debemos crear una cuenta en Dockerhub e iniciar sesión en nuestro terminal:

1
$ docker login

Una vez que haya iniciado sesión, necesitaremos etiquetar nuestra imagen con nuestro nombre de usuario y luego enviarla a Dockerhub:

1
2
$ docker tag django_ec2 <DOCKERHUB_USERNAME>/django_ec2
$ docker push <DOCKERHUB_USERNAME>/django_ec2

Con esto, estamos listos para el siguiente paso, que es implementar nuestra aplicación en Elastic Compute Cloud de Amazon.

Implementando en EC2

Con nuestra imagen de Docker lista y publicada en Dockerhub, ahora podemos iniciar sesión en la consola de nuestra cuenta de AWS y en [Tablero EC2] (https://console.aws.amazon.com/ec2), podemos activar una nueva instancia - que se logra a través de una serie de pasos.

Elija la AMI

El primer paso consiste en seleccionar una Imagen de máquina de Amazon (AMI) que se usará para crear nuestra instancia. Se nos presentan opciones que incluyen Red Hat, Ubuntu Server y Windows Server.

Para esta demostración, necesitaremos una imagen personalizada para ejecutar contenedores y envíos con Docker. Para encontrarlo, escriba ECS en la barra de búsqueda:

aws_ami_selection

El Amazon ECS-Optimized Amazon Linux 2 es ideal para nuestro escenario y es el que elegiremos.

Elija el tipo de instancia

ec2_instance_type

Después de elegir la AMI para nuestra instancia, ahora debemos elegir un tipo de instancia. Nuestra elección aquí dictará la cantidad de recursos que tendrá nuestra instancia en términos de capacidad de rendimiento de CPU, memoria, almacenamiento y red.

Dado que estamos en el nivel gratuito de AWS, seguiremos adelante y utilizaremos la instancia t2.micro, que está diseñada para instancias de propósito general y viene con 1 CPU virtual y 1 GiB de memoria.

La lista contiene tipos de instancias más potentes y otras están optimizadas para poder de cómputo, memoria o almacenamiento.

Configurar instancia

ec2_instance_details

Ahora que hemos elegido el tipo de instancia, el siguiente paso nos permite especificar algunos detalles más sobre nuestra instancia, incluida la cantidad de instancias que se lanzarán en un momento dado, las opciones de red y los sistemas de archivos, entre otros detalles. No haremos ningún cambio en las opciones predeterminadas en este paso.

Agregar almacenamiento

ec2_adding_storage

El cuarto paso implica agregar y especificar los detalles de almacenamiento para nuestra instancia. Esta sección nos permite agregar volúmenes adicionales, especificar el tamaño y los tipos de volumen, y si nuestro almacenamiento estará encriptado o no.

8 GB es la opción predeterminada y es más que suficiente para nuestra sencilla aplicación Django.

Agregar etiquetas

ec2_add_tags

AWS nos permite asignar etiquetas a nuestros recursos a través de las cuales podemos categorizarlos en términos de propósito, acceso o entorno. Las etiquetas no son obligatorias, pero sí muy recomendables para ayudar a identificar los recursos a medida que aumentan en número.

Configurar grupo de seguridad

ec2_configure_security_group

Definimos los grupos de seguridad anteriormente en la publicación y, en este paso del proceso, los configuramos creando un nuevo grupo de seguridad o usando uno existente.

Vamos a crear un nuevo grupo de seguridad que definirá qué tráfico se aceptará en nuestro servidor. La primera regla es la regla SSH que permitirá el tráfico SSH en nuestra instancia a través del puerto 22.

Modificaremos la fuente a Anywhere y también agregaremos una nueva regla para Custom TCP y configuraremos la fuente a Anywhere y el rango de puertos a 8000. Esto nos permitirá acceder a nuestra aplicación web Django a través del puerto 8000.

Revisión y lanzamiento

ec2_review_and_launch

Este es el paso final en el que se nos presentan los detalles de configuración de nuestra instancia para su verificación. También podemos editar la configuración en este punto antes de lanzar nuestra instancia.

Si todo es correcto, finalmente podemos hacer clic en "Iniciar" para finalmente iniciar nuestra instancia:

aws_create_key_pair

Antes de que se inicie nuestra instancia, debemos crear un par de claves que nos permita acceder a nuestra instancia en ejecución. Para ejecutar nuestra aplicación Django, debemos iniciar sesión en la instancia e implementarla allí.

La clave privada se utilizará para autenticarnos y darnos acceso a la instancia para que podamos continuar con nuestra implementación. La confirmación del lanzamiento de la instancia se muestra en la página siguiente:

ec2_instance_launched

Acceso a la instancia EC2

Con la clave privada descargada y la instancia en ejecución, iniciemos sesión e implementemos nuestra aplicación.

Para esto, necesitamos el archivo .pem descargado anteriormente y una ventana de terminal. También necesitaremos un nombre de usuario para la AMI elegida; para la AMI de Amazon Linux, el nombre de usuario predeterminado es ec2-user.

También se requiere el DNS público de la instancia para conectarse y se puede encontrar en la sección de detalles de la instancia en el tablero de la consola de EC2.

Let us open a terminal in the folder that contains our private key file. We'll first need to change the key permissions to avoid seeing an "archivo clave desprotegido" warning:

1
$ chmod 400 <PRIVATE_KEY_FILE_NAME>

Luego podemos usar la utilidad ssh, junto con nuestro archivo de clave, para conectarnos a la instancia:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ ssh -i <PRIVATE_KEY_FILE_NAME> [correo electrónico protegido]<PUBLIC_DNS>

   __|  __|  __|

   _|  (   \__ \   Amazon Linux 2 (ECS Optimized)

 ____|\___|____/

For documentation, visit http://aws.amazon.com/documentation/ecs

12 package(s) needed for security, out of 25 available

Run "sudo yum update" to apply all updates.

-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory

[[correo electrónico protegido]###-##-##-## ~]$

La respuesta anterior significa que hemos iniciado sesión con éxito en nuestra instancia, comenzaremos por extraer la imagen de nuestra aplicación de Dockerhub y ejecutarla con el comando docker run:

1
$ docker run -d -p 8000:8000 <DOCKERHUB_USERNAME>/django_ec2

Una vez que nuestra imagen de Docker se introduce en nuestra instancia y se ejecuta con éxito, ahora podemos acceder a nuestra aplicación Django en la web a través de la misma dirección que usamos para acceder a ella mediante SSH.

Cuando lo hacemos, somos recibidos con:

ec2_instance_deployed

¡Nuestra aplicación Django ya está activa en AWS Elastic Compute Cloud!

Conclusión

En esta publicación, hemos incluido en un contenedor una aplicación Django utilizando Docker y la hemos implementado con éxito en el servicio EC2 de Amazon. También aprendimos qué es EC2 y qué nos ofrece como desarrolladores y cómo podemos aprovecharlo para que nuestras aplicaciones web estén disponibles para los usuarios finales.

El código fuente del script de este proyecto se puede encontrar aquí en GitHub.