Cómo implementar una aplicación Django escalable y segura con Kubernetes

Introducción

En este tutorial, implementará una aplicación de encuestas de Django en contenedor en un clúster de Kubernetes.

Django es un poderoso framework web que puede ayudarle a poner en marcha rápidamente su aplicación o sitio web con Python. Incluye varias características convenientes como un mapeo objeto-relacional, la autenticación de usuarios y una interfaz administrativa personalizable para su aplicación. También incluye un marco de almacenamiento en caché y fomenta el diseño limpio de aplicaciones a través de su Despachador URL y sistema de Plantillas

En Cómo crear una aplicación Django y Gunicorn con Docker, la aplicación de encuestas del Tutorial de Django fue modificada de acuerdo con la metodología de Twelve-Factor para crear aplicaciones web escalables y nativas en la nube. Esta configuración en contenedores se escaló y protegió con un proxy inverso Nginx y certificados TLS proporcionados por Let’s Encrypt en Cómo escalar y proteger una aplicación de Django con Docker, Nginx y Let’s Encrypt. En este tutorial final de la serie “De contenedores a Kubernetes con Django”, la aplicación de encuestas de Django modernizada se implementará en un clúster de Kubernetes.

Kubernetes es un potente orquestador de contenedores de código abierto que automatiza la implementación, el escalamiento y la administración de aplicaciones en contenedores. Los objetos de Kubernetes, como ConfigMaps y Secrets, permiten centralizar y desvincular la configuración de los contenedores, mientras que los controladores como las implementaciones reinician automáticamente los contenedores fallidos y habilitar el escalamiento rápido de las réplicas de contenedores. El cifrado TLS se activa con un objeto Ingress y el controlador de Ingress de código abierto llamado ingress-nginx. El complemento cert-manager de Kubernetes renueva y emite certificados usando la autoridad de certificación de Let’s Encrypt gratuita.

Requisitos previos

Para seguir este tutorial, necesitará lo siguiente:

  • Un clúster de Kubernetes 1.15, o una versión posterior, con control de acceso basado en roles (RBCA) activado. Esta configuración usará un clúster de Kubernetes de DigitalOcean, pero puede crear un clúster usando otro método.
  • La herramienta de línea de comandos kubectl instalada en su equipo local y configurada para conectarse a su clúster. Puede leer más sobre la instalación de kubectl en la documentación oficial. Si está usando un clúster de Kubernetes de DigitalOcean, consulte Cómo conectarse a un clúster Kubernetes de DigitalOcean para aprender a conectarse a su clúster usando kubectl.
  • Un nombre de dominio registrado. Para este tutorial, se utilizará your_domain.com en todo momento. Puede obtener un ejemplar gratis en Freenom o utilizar el registrador de dominios que desee.
  • Un controlador de Ingress ingress-nginx y el administrador de certificados TLS cert-manager instalado en su clúster y configurado para emitir certificados TLS. Para aprender a instalar y configurar un Ingress con cert-manager, consulte Cómo configurar un Ingress de Nginx con Cert-Manager en Kubernetes de DigitalOcean.
  • Un registro DNS A con your_domain.com orientado a la dirección IP pública del equilibrador de cargas de Ingress. Si usa DigitalOcean para administrar los registros DNS de su dominio, consulte Cómo administrar registros DNS para aprender a crear registros A.
  • Un depósito de almacenamiento de objetos S3, como un Space de DigitalOcean, para almacenar los archivos estáticos de su proyecto de Django y un conjunto de claves de acceso para ese espacio. Para obtener información sobre cómo crear Spaces, consulte la documentación de Cómo crear Spaces. Para obtener información sobre cómo crear claves de acceso para Spaces, consulte Compartir el acceso a Spaces con claves de acceso. Con cambios menores, puede usar cualquier servicio de almacenamiento de objetos que admita el complemento django-storages
  • Una instancia de un servidor de PostgreSQL, una base de datos y un usuario para su aplicación de Django. Con cambios menores, puede usar cualquier base de datos que admita Django.
    • La base de datos de PostgreSQL se debería llamar encuestas (o cualquier otro nombre fácil de recordar para ingresar en sus archivos de configuración a continuación). En este tutorial, el usuario de la base de datos de Django se denominará sammy. Para obtener información sobre cómo crearlos, siga el Paso 1 de Cómo crear una aplicación de Django y Gunicorn con Docker. Debe realizar estos pasos desde su máquina local.
    • En este tutorial, se utiliza un clúster de PostgreSQL administrado de DigitalOcean. Para obtener información sobre cómo crear un clúster, consulte la documentación de Bases de datos administradas de DigitalOcean.
    • También puede instalar y ejecutar su propia instancia de PostgreSQL. Para obtener información sobre la instalación y administración de PostgreSQL en un servidor de Ubuntu, consulte Cómo instalar y utilizar PostgreSQL en Ubuntu 18.04.
  • Un Docker Hub cuenta y repositorio público. Para obtener más información sobre cómo crearlos, consulte Repositorios de la documentación de Docker.
  • El motor Docker instalado en su máquina local. Consulte Cómo instalar y usar Docker en Ubuntu 18.04 para obtener más información.

Una vez que haya configurado estos componentes, estará listo para comenzar con esta guía.

Paso 1: Clonar y probar la aplicación

En este paso, clonaremos el código de la aplicación de GitHub y configuraremos ajustes como las credenciales de la base de datos y las claves de almacenamiento de objetos.

El código de la aplicación y Dockerfile se encuentran en la rama polls-docker del repositorio de GitHub de la aplicacipon Polls en el tutorial de Django. Este repositorio contiene el código para la aplicación Polls de muestra de la documentación de Django, que le enseña cómo crear una aplicación de encuestas desde cero.

La rama polls-docker contiene una versión con Docker de esta aplicación Polls. Para obtener información sobre cómo se modificó la aplicación Polls para que funcionara de forma eficaz en un entorno de contenedores, consulte Cómo crear una aplicación de Django y Gunicorn con Docker.

Comience usando git para clonar la rama polls-docker del repositorio de GitHub de la aplicación Polls del tutorial de Django en su máquina local:

  • git clone --single-branch --branch polls-docker https://github.com/do-community/django-polls.git

Diríjase al directorio django-polls:

  • cd django-polls

Este directorio contiene el código de Python de la aplicación de Django, un Dockerfile que Docker utilizará para crear la imagen del contenedor, y un archivo env que contiene una lista de las variables de entorno que se pasarán al entorno de ejecución del contenedor. Inspeccione el Dockerfile:

  • cat Dockerfile
OutputFROM python:3.7.4-alpine3.10  ADD django-polls/requirements.txt /app/requirements.txt  RUN set -ex      && apk add --no-cache --virtual .build-deps postgresql-dev build-base      && python -m venv /env      && /env/bin/pip install --upgrade pip      && /env/bin/pip install --no-cache-dir -r /app/requirements.txt      && runDeps="$(scanelf --needed --nobanner --recursive /env          | awk '{ gsub(/,/, "nso:", $2); print "so:" $2 }'          | sort -u          | xargs -r apk info --installed          | sort -u)"      && apk add --virtual rundeps $runDeps      && apk del .build-deps  ADD django-polls /app WORKDIR /app  ENV VIRTUAL_ENV /env ENV PATH /env/bin:$PATH  EXPOSE 8000  CMD ["gunicorn", "--bind", ":8000", "--workers", "3", "mysite.wsgi"] 

Este Dockerfile utiliza la imagen de Docker oficial de Python 3.7.4 como base e instala los requisitos del paquete de Python de Django y Gunicorn, tal como se define en el archivo django-polls/requirements.txt. A continuación, elimina algunos archivos de compilación innecesarios, copia el código de la aplicación en la imagen y establece el PATH de ejecución. Por último, declara que el puerto 8000 se utilizará para aceptar conexiones de contenedores entrantes y ejecuta gunicorn con 3 trabajadores, escuchando en el puerto 8000.

Para obtener más información sobre cada uno de los pasos de este Dockerfile, consulte el Paso 6 de Cómo crear una aplicación de Django y Gunicorn con Docker.

Ahora, compile la imagen con docker build:

  • docker build -t polls .

Nombramos la imagen polls con el indicador -t y pasamos el directorio actual como contexto de compilación, el conjunto de archivos a los que se debe hacer referencia al construir la imagen.

Una vez que Docker haya compilado y etiquetado la imagen, enumere las imágenes disponibles utilizando docker images:

  • docker images

Debería ver la imagen polls enumerada:

OutputREPOSITORY          TAG                 IMAGE ID            CREATED             SIZE polls               latest              80ec4f33aae1        2 weeks ago         197MB python              3.7.4-alpine3.10    f309434dea3a        8 months ago        98.7MB 

Antes de ejecutar el contenedor de Django, debemos configurar su entorno de ejecución utilizando el archivo env presente en el directorio actual. Este archivo se pasará al comando docker run que se utiliza para ejecutar el contenedor y Docker insertará las variables de entorno configuradas en el entorno en ejecución del contenedor.

Abra el archivo env con nano o su editor favorito:

  • nano env

django-polls/env

DJANGO_SECRET_KEY= DEBUG=True DJANGO_ALLOWED_HOSTS= DATABASE_ENGINE=postgresql_psycopg2 DATABASE_NAME=polls DATABASE_USERNAME= DATABASE_PASSWORD= DATABASE_HOST= DATABASE_PORT= STATIC_ACCESS_KEY_ID= STATIC_SECRET_KEY= STATIC_BUCKET_NAME= STATIC_ENDPOINT_URL= DJANGO_LOGLEVEL=info 

Complete los valores que faltan para las siguientes claves:

  • DJANGO_SECRET_KEY: establézcala en un valor único e impredecible, como se detalla en la documentación de Django. Se proporciona un método para generar esta clave en la sección Ajustar la configuración de la aplicación del tutorial Aplicaciones escalables de Django.
  • DJANGO_ALLOWED_HOSTS: esta variable asegura la aplicación y evita ataques a través del encabezado de host HTTP. Para propósitos de prueba, establézcala en *, un comodín que coincidirá con todos los hosts. En producción, debe establecerlo en your_domain.com. Para obtener más información sobre esta configuración de Django, consulte la sección Configuración principal en la documentación de Django.
  • DATABASE_USERNAME: establézcalo en el usuario de la base de datos de PostgreSQL creado en los pasos de requisitos previos.
  • DATABASE_NAME: establézcalo en polls o el nombre de la base de datos de PostgreSQL creado en los pasos de requisitos previos.
  • DATABASE_PASSWORD: establézcala en la contraseña de la base de datos de PostgreSQL creada en los pasos de requisitos previos.
  • DATABASE_HOST: establézcalo en el nombre de host de su base de datos.
  • DATABASE_PORT: establézcalo en el puerto de su base de datos.
  • STATIC_ACCESS_KEY_ID: establézcala en la clave de acceso de Space o en el almacenamiento de objetos.
  • STATIC_SECRET_KEY: establézcala en Secret de la clave de acceso de su Space o en el almacenamiento de objetos.
  • STATIC_BUCKET_NAME: establézcalo en el nombre de su Space o en el depósito de almacenamiento de objetos.
  • STATIC_ENDPOINT_URL: establézcala en la URL de extremo de Spaces o del almacenamiento del objeto que corresponda, por ejemplo, https://your_space_name.nyc3.digitaloceanspaces.com, si su Space está ubicado en la región nyc3.

Una vez que haya finalizado la edición, guarde y cierre el archivo.

En el siguiente paso, ejecutaremos el contenedor configurado a nivel local y crearemos el esquema de la base de datos. También cargaremos activos estáticos como hojas de estilos e imágenes al almacenamiento de objetos.

Paso 2: Crear el esquema de la base de datos y cargar activos en el almacenamiento de objetos

Con el contenedor creado y configurado, utilizaremos docker run para anular el CMD establecido en Dockerfile y crear el esquema de la base de datos utilizando los comandos manage.py makemigrations y manage.py migrate:

  • docker run --env-file env polls sh -c "python manage.py makemigrations && python manage.py migrate"

Ejecutamos la imagen del contenedor polls:latest, pasamos el archivo de variables de entorno que acabamos de modificar y anulamos el comando de Dockerfile con sh -c "python manage.py makemigrations && python manage.py migrate", lo que creará el esquema de la base de datos definido mediante el código de la aplicación.

Si lo está ejecutando por primera vez, debería ver lo siguiente:

OutputNo changes detected Operations to perform:   Apply all migrations: admin, auth, contenttypes, polls, sessions Running migrations:   Applying contenttypes.0001_initial... OK   Applying auth.0001_initial... OK   Applying admin.0001_initial... OK   Applying admin.0002_logentry_remove_auto_add... OK   Applying admin.0003_logentry_add_action_flag_choices... OK   Applying contenttypes.0002_remove_content_type_name... OK   Applying auth.0002_alter_permission_name_max_length... OK   Applying auth.0003_alter_user_email_max_length... OK   Applying auth.0004_alter_user_username_opts... OK   Applying auth.0005_alter_user_last_login_null... OK   Applying auth.0006_require_contenttypes_0002... OK   Applying auth.0007_alter_validators_add_error_messages... OK   Applying auth.0008_alter_user_username_max_length... OK   Applying auth.0009_alter_user_last_name_max_length... OK   Applying auth.0010_alter_group_name_max_length... OK   Applying auth.0011_update_proxy_permissions... OK   Applying polls.0001_initial... OK   Applying sessions.0001_initial... OK 

Esto indica que el esquema de la base de datos se ha creado correctamente.

Si no está ejecutando migrate por primera vez, Django realizará un no-op a menos que el esquema de la base de datos haya cambiado.

A continuación, ejecutaremos otra instancia del contenedor de la aplicación y utilizaremos una shell interactiva en su interior para crear un usuario administrativo para el proyecto de Django.

  • docker run -i -t --env-file env polls sh

Esto le proporcionará una línea de comandos de shell dentro del contenedor en ejecución que puede usar para crear el usuario de Django:

  • python manage.py createsuperuser

Ingrese un nombre de usuario, una dirección de correo electrónico y una contraseña para su usuario y, una vez que haya creado el usuario, presione CTRL+D para salir del contenedor y cerrarlo.

Por último, generaremos los archivos estáticos de la aplicación y los subiremos al Space de DigitalOcean utilizando collectstatic. Tenga en cuenta que esta operación puede tardar un poco en completarse.

  • docker run --env-file env polls sh -c "python manage.py collectstatic --noinput"

Una vez que estos archivos se hayan generado y cargado, obtendrá el siguiente resultado.

Output121 static files copied. 

Ahora, podemos ejecutar la aplicación:

  • docker run --env-file env -p 80:8000 polls
Output[2019-10-17 21:23:36 +0000] [1] [INFO] Starting gunicorn 19.9.0 [2019-10-17 21:23:36 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1) [2019-10-17 21:23:36 +0000] [1] [INFO] Using worker: sync [2019-10-17 21:23:36 +0000] [7] [INFO] Booting worker with pid: 7 [2019-10-17 21:23:36 +0000] [8] [INFO] Booting worker with pid: 8 [2019-10-17 21:23:36 +0000] [9] [INFO] Booting worker with pid: 9 

Aquí, ejecutamos el comando predeterminado definido en el Dockerfile, gunicorn --bind :8000 --workers 3 mysite.wsgi:application y exponemos el puerto del contenedor 8000 para que el puerto 80 en su máquina local se asigne al puerto 8000 del contenedor polls.

Ahora, debería poder navegar a la aplicación polls desde su navegador web al http://localhost en la barra de direcciones URL. Dado que no hay una ruta definida para la ruta / , es probable que reciba un error de 404 Page Not Found (Página no encontrada), lo que es de esperar.

Diríjase a http://localhost/polls para ver la interfaz de la aplicación Polls:

Interfaz de la aplicación Polls

Para ver la interfaz administrativa, visite http://localhost/admin. Debería ver la ventana de autenticación de administración de la aplicación Polls:

Página de autenticación de administración de Polls

Ingrese el nombre de usuario administrativo y la contraseña que creó con el comando createsuperuser.

Después de la autenticación, podrá acceder a la interfaz administrativa de la aplicación Polls:

Interfaz principal de administración de Polls

Tenga en cuenta que los que los recursos estáticos de las aplicaciones admin y polls se entregan directamente desde el almacenamiento de objetos. Para confirmar esto, consulte Prueba de la entrega de archivos estáticos de Spaces.

Cuando haya terminado de explorar, presione CTRL+C en la ventana de terminal que está ejecutando el contenedor de Docker para cerrar el contenedor.

Con la imagen de Docker de la aplicación de Django probada, los activos estáticos que se cargan en el almacenamiento de objetos y el esquema de la base de datos configurado y listo para ser utilizado en su aplicación, estará listo para subir la imagen de su aplicación de Django a un registro de imágenes como Docker Hub.

Paso 3: Introducir la imagen de la aplicación de Django en Docker Hub

Para implementar su aplicación en Kubernetes, la imagen de su aplicación debe cargarse en un registro como Docker Hub. Kubernetes extraerá la imagen de la aplicación de su repositorio y luego la implementará en su clúster.

Puede usar un registro de Docker privado, como DigitalOcean Container Registry, actualmente gratuito en Early Access o un registro de Docker público como Docker Hub. Docker Hub también le permite crear repositorios de Docker privados. Un repositorio público permite a cualquiera ver y extraer las imágenes del contenedor, mientras que un repositorio privado permite restringir el acceso a usted y a los miembros de su equipo.

En este tutorial, introduciremos la imagen de Django en el repositorio de Docker Hub público creado en los requisitos previos. También puede introducir su imagen en un repositorio privado, pero extraer imágenes de un repositorio privado no es el tema de este artículo. Para obtener más información sobre la autenticación de Kubernetes con Docker Hub y la extracción de imágenes privadas, consulte Extraer una imagen de un registro privado en la documentación de Kubernetes.

Comience iniciando sesión en Docker Hub en su máquina local:

  • docker login
OutputLogin with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username: 

Ingrese su nombre de usuario y contraseña de Docker Hub para iniciar sesión.

La imagen de Django actualmente tiene la etiqueta polls:latest. Para introducirla en su repositorio de Docker Hub, vuelva a etiquetar la imagen con su nombre de usuario de Docker Hub y nombre de repositorio:

  • docker tag polls:latest your_dockerhub_username/your_dockerhub_repo_name:latest

Introduzca la imagen en el repositorio:

  • docker push sammy/sammy-django:latest

En este tutorial, el nombre de usuario de Docker Hub es sammy y el nombre de repositorio es sammy-django. Debe sustituir estos valores por su propio nombre de usuario y nombre de repositorio de Docker Hub.

Verá un resultado que se actualiza a medida que las capas de imágenes se insertan en Docker Hub.

Ahora que su imagen está disponible para Kubernetes en Docker Hub, puede comenzar a implementarla en su clúster.

Paso 4: Configurar ConfigMap

Cuando ejecutamos el contenedor de Django a nivel local, pasamos el archivo env a docker run para insertar variables de configuración en el entorno de tiempo de ejecución. En Kubernetes, las variables de configuración pueden insertarse usando ConfigMaps y Secrets.

ConfigMaps debe usarse para almacenar información de configuración no confidencial, la configuración de la aplicación, mientras que Secrets debe usarse para información confidencial, como claves de API y credenciales de la base de datos. Ambos se insertan en contenedores de forma similar, pero Secrets tienen funciones de control de acceso y seguridad adicionales como encriptación en reposo. Secrets también almacenan datos en base64, mientras que ConfigMaps almacenan datos en texto simple.

Para comenzar, cree un directorio llamado yaml en el que almacenaremos nuestros manifiestos de Kubernetes. Diríjase al directorio.

  • mkdir yaml
  • cd

Abra un archivo llamado polls-configmap.yaml en nano o su editor de texto preferido:

  • nano polls-configmap.yaml

Pegue el siguiente manifiesto de ConfigMap:

polls-configmap.yaml

apiVersion: v1 kind: ConfigMap metadata:   name: polls-config data:   DJANGO_ALLOWED_HOSTS: "*"   STATIC_ENDPOINT_URL: "https://your_space_name.space_region.digitaloceanspaces.com"   STATIC_BUCKET_NAME: "your_space_name"   DJANGO_LOGLEVEL: "info"   DEBUG: "True"   DATABASE_ENGINE: "postgresql_psycopg2" 

Extrajimos la configuración no sensible del archivo env modificado en el Paso 1 y la pegamos en un manifiesto de ConfigMap. El objeto ConfigMap se llama polls-config. Copie los mismos valores que ingresó en el archivo env en el paso anterior.

Para propósitos de prueba, establezca DJANGO_ALLOWED_HOSTS como * para desactivar el filtrado del encabezado de host. En un entorno de producción, debe establecerlo en el dominio de su aplicación.

Cuando haya terminado de editar el archivo, guárdelo y ciérrelo.

Cree ConfigMap en su clúster usando kubectl apply:

  • kubectl apply -f polls-configmap.yaml
Outputconfigmap/polls-config created 

Después de crear ConfigMap, crearemos el Secret que usó nuestra aplicación en el siguiente paso.

Paso 5: Configurar Secret

Los valores de Secret deben estar codificados en base64, lo que significa que crear objetos de Secret en su clúster es ligeramente más complicado que crear ConfigMaps. Puede repetir el proceso del paso anterior, codificando de forma manual los valores de Secret de base64 y pegándolos en un archivo de manifiesto. También puede crearlos usando un archivo de variable de entorno, kubectl create y el indicador --from-env-file, que realizaremos en este paso.

Una vez más, usaremos el archivo env del Paso 1, eliminando las variables insertadas en ConfigMap. Cree una copia del archivo env llamado polls-secrets en el directorio yaml:

  • cp ../env ./polls-secrets

Edite el archivo en el editor de su preferencia:

  • nano polls-secrets

polls-secrets

DJANGO_SECRET_KEY= DEBUG=True DJANGO_ALLOWED_HOSTS= DATABASE_ENGINE=postgresql_psycopg2 DATABASE_NAME=polls DATABASE_USERNAME= DATABASE_PASSWORD= DATABASE_HOST= DATABASE_PORT= STATIC_ACCESS_KEY_ID= STATIC_SECRET_KEY= STATIC_BUCKET_NAME= STATIC_ENDPOINT_URL= DJANGO_LOGLEVEL=info 

Elimine todas las variables insertadas en el manifiesto de ConfigMap. Cuando haya terminado, debe verse así:

polls-secrets

DJANGO_SECRET_KEY=your_secret_key DATABASE_NAME=polls DATABASE_USERNAME=your_django_db_user DATABASE_PASSWORD=your_django_db_user_password DATABASE_HOST=your_db_host DATABASE_PORT=your_db_port STATIC_ACCESS_KEY_ID=your_space_access_key STATIC_SECRET_KEY=your_space_access_key_secret 

Asegúrese de usar los mismos valores que se utilizan en el Paso 1. Cuando haya terminado, guarde y cierre el archivo.

Cree el Secret en su clúster usando kubectl create secret:

  • kubectl create secret generic polls-secret --from-env-file=poll-secrets
Outputsecret/polls-secret created 

Aquí creamos un objeto Secret llamado polls-secret y pasamos el archivo de secrets que acabamos de crear.

Puede inspeccionar el Secret usando kubectl describe:

  • kubectl describe secret polls-secret
OutputName:         polls-secret Namespace:    default Labels:       <none> Annotations:  <none>  Type:  Opaque  Data ==== DATABASE_PASSWORD:     8 bytes DATABASE_PORT:         5 bytes DATABASE_USERNAME:     5 bytes DJANGO_SECRET_KEY:     14 bytes STATIC_ACCESS_KEY_ID:  20 bytes STATIC_SECRET_KEY:     43 bytes DATABASE_HOST:         47 bytes DATABASE_NAME:         5 bytes 

En este punto, almacenó la configuración de su aplicación en el clúster de Kubernetes usando los tipos de objeto Secret y ConfigMap. Ahora estamos listos para implementar la aplicación en el clúster.

Paso 6: Implementar la aplicación de Django usando una implementación

En este paso, creará una implementación para su aplicación de Django. Una implementación de Kubernetes es un controlador que puede usarse para administrar aplicaciones sin estado en su clúster. Un controlador es un bucle de control que regula las cargas de trabajo aumentándolas o reduciéndolas. Los controladores también reinician y eliminan los contenedores fallidos.

Las implementaciones controlan uno o más Pods, la unidad implementable más pequeña de un clúster de Kubernetes. Los Pods están compuestos por uno o más contenedores. Para obtener más información sobre los diferentes tipos de cargas de trabajo que puede iniciar, consulte Introducción a Kubernetes.

Empiece por abrir un archivo llamado polls-deployment.yaml en su editor favorito:

  • nano polls-deployment.yaml

Pegue el siguiente manifiesto de implementación:

polls-deployment.yaml

apiVersion: apps/v1 kind: Deployment metadata:   name: polls-app   labels:     app: polls spec:     replicas: 2   selector:     matchLabels:       app: polls   template:     metadata:       labels:         app: polls     spec:       containers:         - image: your_dockerhub_username/app_repo_name:latest           name: polls           envFrom:           - secretRef:               name: polls-secret           - configMapRef:               name: polls-config           ports:             - containerPort: 8000               name: gunicorn 

Complete el nombre de la imagen del contenedor correspondiente, haciendo referencia a la imagen de Django Polls que agregó a Docker Hub en el Paso 2.

Aquí definimos una implementación de Kubernetes llamada polls-app y la etiquetamos con el par clave-valor app: polls. Especificamos que queremos ejecutar dos réplicas del Pod especificado debajo del campo template.

Usando envFrom con secretRef y configMapRef, especificamos que todos los datos del Secret polls-secret y el ConfigMap polls-config deben insertarse en los contenedores como variables de entorno. Las claves ConfigMap y Secret se convierten en los nombres de las variables de entorno.

Por último, exponemos el containerPort 8000 y lo nombramos gunicorn.

Para obtener más información sobre la configuración de las implementaciones de Kubernetes, consulte Implementaciones en la documentación de Kubernetes.

Cuando haya terminado de editar el archivo, guárdelo y ciérrelo.

Cree la implementación en su clúster usando kubectl apply -f:

  • kubectl apply -f polls-deployment.yaml
  • deployment.apps/polls-app created

Compruebe que la implementación se implementó correctamente usando kubectl get:

  • kubectl get deploy polls-app
OutputNAME        READY   UP-TO-DATE   AVAILABLE   AGE polls-app   2/2     2            2           6m38s 

Si encuentra un error o considera que algo no está funcionando, puede usar kubectl describe para inspeccionar la implementación fallida:

  • kubectl describe deploy

Puede inspeccionar los dos Pods usando kubectl get pod:

  • kubectl get pod
OutputNAME                         READY   STATUS    RESTARTS   AGE polls-app-847f8ccbf4-2stf7   1/1     Running   0          6m42s polls-app-847f8ccbf4-tqpwm   1/1     Running   0          6m57s 

Ahora hay dos réplicas de su aplicación de Django ejecutándose en el clúster. Para acceder a la aplicación, es necesario crear un Service de Kubernetes, lo cual es lo que haremos a continuación.

Paso 7: Permitir el acceso externo mediante un Service

En este paso, creará un Service para su aplicación de Django. Un Service de Kubernetes es una abstracción que le permite exponer un conjunto de Pods en ejecución como servicio de red. Mediante un Service, puede crear un extremo estable para su aplicación que no cambia a medida que los Pods mueren y se vuelvan a crear.

Existen varios tipos de Service, incluidos ClusterIP Services, que exponen el servicio en un IP interno del clúster, NodePort Services que exponen el servicio en cada Nodo en un puerto estático llamado NodePort y LoadBalancer Services que proporcionan un equilibrador de carga en la nube para dirigir el tráfico externo a los Pods de su clúster (a través de NodePorts, que crea automáticamente). Para obtener más información sobre esos servicios, consulte el artículo Service en la documentación de Kubernetes.

En nuestra configuración final, usaremos un Service ClusterIP que se expone usando un Ingress y el controlador de Ingress configurado en los requisitos previos de esta guía. Por ahora, para comprobar que todo funciona correctamente, crearemos un servicio de NodePort temporal para acceder a la aplicación de Django.

Comience creando un archivo llamado polls-svc.yaml usando el editor de su preferencia:

  • nano polls-svc.yaml

Pegue el siguiente manifiesto de Service:

polls-svc.yaml

apiVersion: v1 kind: Service metadata:   name: polls   labels:     app: polls spec:   type: NodePort   selector:     app: polls   ports:     - port: 8000       targetPort: 8000 

Aquí creamos un Service NodePort llamado polls y le asignamos la etiqueta app: polls. A continuación, seleccionamos los Pods backend con la etiqueta app: polls y orientamos sus puertos 8000.

Cuando haya terminado de editar el archivo, guárdelo y ciérrelo.

Implemente el Service usando kubectl apply:

  • kubectl apply -f polls-svc.yaml
Outputservice/polls created 

Confirme que su Service se creó usando kubectl get svc:

  • kubectl get svc polls
OutputNAME    TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE polls   NodePort   10.245.197.189   <none>        8000:32654/TCP   59s 

Este resultado muestra la IP y NodePort internos del clúster de Service (32654). Para conectarse al servicio, se necesitan las direcciones IP externas de los nodos del clúster:

  • kubectl get node -o wide
OutputNAME                   STATUS   ROLES    AGE   VERSION   INTERNAL-IP   EXTERNAL-IP      OS-IMAGE                       KERNEL-VERSION          CONTAINER-RUNTIME pool-7no0qd9e0-364fd   Ready    <none>   27h   v1.18.8   10.118.0.5    203.0.113.1   Debian GNU/Linux 10 (buster)   4.19.0-10-cloud-amd64   docker://18.9.9 pool-7no0qd9e0-364fi   Ready    <none>   27h   v1.18.8   10.118.0.4    203.0.113.2    Debian GNU/Linux 10 (buster)   4.19.0-10-cloud-amd64   docker://18.9.9 pool-7no0qd9e0-364fv   Ready    <none>   27h   v1.18.8   10.118.0.3    203.0.113.3   Debian GNU/Linux 10 (buster)   4.19.0-10-cloud-amd64   docker://18.9.9 

En su navegador web, visite su aplicación Polls usando la dirección IP externa de cualquier nodo y el NodePort. Dado el resultado anterior, la URL de la aplicación sería la siguiente: http://203.0.113.1:32654/polls.

Debería poder ver la misma interfaz de la aplicación Polls a la que accedió a nivel local en el Paso 1:

Interfaz de la aplicación Polls

Puede repetir la misma prueba usando la ruta /admin: http://203.0.113.1:32654/admin. Debería ver la misma interfaz administrativa que antes:

Página de autenticación de administración de Polls

En esta etapa, ya implementó dos réplicas del contenedor de la aplicación Polls de Django usando una implementación. También creó un extremo de red estable para estas dos réplicas e hizo que se pueda acceder a ellas externamente usando un servicio de NodePort

El paso final de este tutorial es proteger el tráfico externo a su aplicación usando HTTPS. Para ello, usaremos el controlador de Ingress-nginx instalado en los requisitos previos y crearemos un objeto de Ingress para dirigir el tráfico externo al servicio de Kubernetes de polls.

Paso 8: Configurar HTTPS usando el Ingress y cert-manager de Nginx

Los Ingress de Kubernetes le permiten dirigir de manera flexible el tráfico del exterior de su clúster de Kubernetes a servicios dentro de su clúster. Esto se realiza usando objetos de Ingress, que definen reglas para dirigir el tráfico HTTP y HTTPS a servicios de Kubernetes, y controladores de Ingress, que implementan las reglas equilibrando la carga de tráfico y dirigiéndola a los servicios de backend correspondientes.

En los requisitos previos, instaló el controlador de Ingress-nginx y el complemento para automatizar certificados TLS cert-manager. También ha configurado el ClusterIssuers de ensayo y producción de su dominio usando la autoridad de certificación Let’s Encrypt, y ha creado un Ingress para probar la emisión de certificados y el cifrado TLS en dos servicios de backend ficticios. Antes de continuar con este paso, debe eliminar el Ingress echo-ingress creado en el tutorial de requisitos previos:

  • kubectl delete ingress echo-ingress

Si desea, también puede eliminar los servicios y las implementaciones ficticios usando kubectl delete svc y kubectl delete deploy, pero no es necesario que lo haga para completar este tutorial.

También debería haber creado un registro DNS A con your_domain.com orientado a la dirección IP pública del equilibrador de cargas de Ingress. Si usa un equilibrador de carga de DigitalOcean, puede encontrar esta dirección IP en la sección Equilibradores de carga del panel de control. Si también usa DigitalOcean para administrar los registros DNS de su dominio, consulte Cómo administrar registros DNS para aprender a crear registros A.

Si usa Kubernetes de DigitalOcean, también asegúrese de implementar la solución descrita en el Paso 5 de Cómo configurar un Ingress de Nginx con Cert-Manager en Kubernetes de DigitalOcean.

Una vez que tenga un registro A que apunte al equilibrador de carga del controlador de Ingress, puede crear un Ingress para your_domain.com y el servicio polls.

Abra un archivo llamado polls-ingress.yaml usando el editor de su preferencia:

  • nano polls-ingress.yaml

Pegue el siguiente manifiesto de Ingress:

[polls-ingress.yaml] apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata:   name: polls-ingress   annotations:     kubernetes.io/ingress.class: "nginx"     cert-manager.io/cluster-issuer: "letsencrypt-staging" spec:   tls:   - hosts:     - your_domain.com     secretName: polls-tls   rules:   - host: your_domain.com     http:       paths:       - backend:           serviceName: polls           servicePort: 8000 

Creamos un objeto de Ingress llamado polls-ingress y lo anotamos para indicarle al plano de control que utilice el controlador de Ingress-nginx y el ClusterIssuer de ensayo. También habilitamos TLS para your_domain.com y almacenamos el certificado y la clave privada en un secret llamado polls-tls. Por último, definimos una regla para dirigir el tráfico del host your_domain.com al servicio polls del puerto 8000.

Cuando haya terminado de editar el archivo, guárdelo y ciérrelo.

Cree el Ingress en su clúster usando kubectl apply:

  • kubectl apply -f polls-ingress.yaml
Outputingress.networking.k8s.io/polls-ingress created 

Puede usar kubectl describe para rastrear el estado del Ingress que acaba de crear:

  • kubectl describe ingress polls-ingress
OutputName:             polls-ingress Namespace:        default Address:          workaround.your_domain.com Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>) TLS:   polls-tls terminates your_domain.com Rules:   Host        Path  Backends   ----        ----  --------   your_domain.com                  polls:8000 (10.244.0.207:8000,10.244.0.53:8000) Annotations:  cert-manager.io/cluster-issuer: letsencrypt-staging               kubernetes.io/ingress.class: nginx Events:   Type    Reason             Age   From                      Message   ----    ------             ----  ----                      -------   Normal  CREATE             51s   nginx-ingress-controller  Ingress default/polls-ingress   Normal  CreateCertificate  51s   cert-manager              Successfully created Certificate "polls-tls"   Normal  UPDATE             25s   nginx-ingress-controller  Ingress default/polls-ingress 

También puede ejecutar un describe en el certificado polls-tls para confirmar una vez más que se creó de manera correcta:

  • kubectl describe certificate polls-tls
Output. . . Events:   Type    Reason     Age    From          Message   ----    ------     ----   ----          -------   Normal  Issuing    3m33s  cert-manager  Issuing certificate as Secret does not exist   Normal  Generated  3m32s  cert-manager  Stored new private key in temporary Secret resource "polls-tls-v9lv9"   Normal  Requested  3m32s  cert-manager  Created new CertificateRequest resource "polls-tls-drx9c"   Normal  Issuing    2m58s  cert-manager  The certificate has been successfully issued 

Esto confirma que el certificado TLS ha sido emitido con éxito y que el cifrado HTTPS ahora está activo para your_domain.com.

Dado que usamos el ClusterIssuer de ensayo, la mayoría de los navegadores de Internet no confiarán en el certificado Let’s Encrypt que emitió. Por lo tanto, dirigirse a your_domain.com lo llevará a una página de error.

Para enviar una solicitud de prueba, usaremos wget desde la línea de comandos:

  • wget -O - http://your_domain.com/polls
Output. . . ERROR: cannot verify your_domain.com's certificate, issued by ‘CN=Fake LE Intermediate X1’:   Unable to locally verify the issuer's authority. To connect to your_domain.com insecurely, use `--no-check-certificate'. 

Usaremos el indicador --no-check-certificate sugerido para omitir la validación del certificado:

  • wget --no-check-certificate -q -O - http://your_domain.com/polls
Output  <link rel="stylesheet" type="text/css" href="https://your_space.nyc3.digitaloceanspaces.com/django-polls/static/polls/style.css">       <p>No polls are available.</p> 

Este resultado muestra el HTML de la página de la interfaz /polls, lo que confirma también que la hoja de estilos se toma desde el almacenamiento de objetos.

Ahora que probó con éxito la emisión de certificados usando el ClusterIssuer de ensayo, puede modificar el Ingress para usar el ClusterIssuer de producción.

Abra polls-ingress.yaml para editar una vez más:

  • nano polls-ingress.yaml

Modifique la anotación cluster-issuer:

[polls-ingress.yaml] apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata:   name: polls-ingress   annotations:     kubernetes.io/ingress.class: "nginx"     cert-manager.io/cluster-issuer: "letsencrypt-prod" spec:   tls:   - hosts:     - your_domain.com     secretName: polls-tls   rules:   - host: your_domain.com     http:       paths:       - backend:           serviceName: polls           servicePort: 8000 

Cuando termine, guarde y cierre el archivo. Actualice el Ingress usando kubectl apply:

  • kubectl apply -f polls-ingress.yaml
Outputingress.networking.k8s.io/polls-ingress configured 

Puede usar kubectl describe certificate polls-tls y kubectl describe ingress polls-ingress para rastrear el estado de emisión del certificado:

  • kubectl describe ingress polls-ingress
Output. . . Events:   Type    Reason             Age                From                      Message   ----    ------             ----               ----                      -------   Normal  CREATE             23m                nginx-ingress-controller  Ingress default/polls-ingress   Normal  CreateCertificate  23m                cert-manager              Successfully created Certificate "polls-tls"   Normal  UPDATE             76s (x2 over 22m)  nginx-ingress-controller  Ingress default/polls-ingress   Normal  UpdateCertificate  76s                cert-manager              Successfully updated Certificate "polls-tls" 

El resultado anterior confirma que el nuevo certificado de producción se emitió y almacenó con éxito en el Secret polls-tls.

Diríjase a your_domain.com/polls en su navegador web para confirmar que el cifrado HTTPS está habilitado y que todo funciona según lo previsto. Debería ver la interfaz de la aplicación Polls:

Interfaz de la aplicación Polls

Verifique que el cifrado HTTPS está activo en su navegador web. Si usa Google Chrome, llegar a la página anterior sin errores confirma que todo funciona correctamente. Además, debe ver un candado en la barra de direcciones URL. Al hacer clic en el candado, se le permitirá inspeccionar los detalles del certificado Let’s Encrypt.

Como tarea de limpieza final, puede cambiar opcionalmente el tipo de servicio polls de NodePort al tipo ClusterIP interno solamente.

Modifique polls-svc.yaml usando su editor:

  • nano polls-svc.yaml

Cambie el type de NodePort a ClusterIP:

polls-svc.yaml

apiVersion: v1 kind: Service metadata:   name: polls   labels:     app: polls spec:   type: ClusterIP   selector:     app: polls   ports:     - port: 8000       targetPort: 8000 

Cuando haya terminado de editar el archivo, guárdelo y ciérrelo.

Implemente los cambios usando kubectl apply:

  • kubectl apply -f polls-svc.yaml --force
Outputservice/polls configured 

Confirme que su Service se modificó usando kubectl get svc:

  • kubectl get svc polls
OutputNAME    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE polls   ClusterIP   10.245.203.186   <none>        8000/TCP   22s 

Este resultado muestra que el tipo de servicio es ahora ClusterIP. La única forma de acceder a él es a través de su dominio y del Ingress creado en este paso.

Conclusión

En este tutorial, implementó una aplicación de Django escalable y protegida con HTTPS en un clúster de Kubernetes. El contenido estático se toma directamente desde el almacenamiento de objetos y el número de Pods en ejecución puede aumentar o disminuir rápidamente usando el campo réplicas en el manifiesto de implementación polls-app.

Si usa un Space de DigitalOcean, también puede habilitar la entrega de activos estáticos a través de una red de entrega de contenido y crear un subdominio personalizado para su Space. Consulte Habilitar CDN en Cómo configurar una aplicación de Django escalable con bases de datos y Spaces administrados por DigitalOcean para obtener más información.

Para revisar el resto de la serie, visite nuestra página “De contenedores a Kubernetes con Django”.