Como implantar um aplicativo Django escalável e seguro com o Kubernetes

Introdução

Neste tutorial, você irá implantar um aplicativo de pesquisa do Django em contêiner em um cluster do Kubernetes.

O Django é um framework Web poderoso, que pode ajudar a acelerar a implantação do seu aplicativo Python. Ele inclui diversas funcionalidades convenientes, como um mapeador relacional do objeto, autenticação de usuário e uma interface administrativa personalizável para seu aplicativo. Ele também inclui um framework de cache e encoraja o design de aplicativos organizados através do seu URL Dispatcher e Sistema de modelos.

Em Como construir um aplicativo Django e Gunicorn com o Docker, o aplicativo Polls de tutorial do Django foi modificado de acordo com a metodologia do Twelve-Factor para a construção de aplicativos Web escaláveis e nativos na nuvem. Essa configuração em contêiner foi dimensionada e protegida com um proxy reverso do Nginx e autenticada pelo Let’s Encrypt com certificados TLS seguindo Como dimensionar e proteger um aplicativo Django com o Docker, Nginx e Let’s Encrypt. Neste tutorial final da série De contêineres ao Kubernetes com o Django, o aplicativo modernizado de pesquisa do Django será implantado em um cluster do Kubernetes.

O Kubernetes é um orquestrador de contêineres de código aberto poderoso, que automatiza a implantação, dimensionamento e gerenciamento de aplicativos em contêiner. Os objetos do Kubernetes como os ConfigMaps e Segredos permitem centralizar e desacoplar a configuração dos seus contêineres, enquanto os controladores como Deployments reiniciam automaticamente contêineres que falharam e habilitam o dimensionamento rápido de réplicas de contêineres. A criptografia TLS é habilitada com um objeto Ingress e o Controlador Ingress de código aberto ingress-nginx. O add-on cert-manager do Kubernetes renova e emite certificados usando a autoridade de certificação gratuita Let’s Encrypt.

Pré-requisitos

Para seguir este tutorial, será necessário:

  • Um cluster do Kubernetes 1.15+ com controle de acesso baseado na função (RBAC) habilitado. Essa configuração irá usar um cluster do Kubernetes da DigitalOcean, mas você pode criar um cluster usando outro método.
  • A ferramenta kubectl de linha de comando instalada em sua máquina local e configurada para se conectar ao seu cluster. Você pode ler mais sobre como instalar o kubectl na documentação oficial. Se você estiver usando um cluster do Kubernetes da DigitalOcean, consulte Como se conectar a um cluster do Kubernetes da DigitalOcean para aprender como se conectar ao seu cluster usando o kubectl.
  • Um nome de domínio registrado. Este tutorial usará your_domain.com do início ao fim. Você pode obter um domínio gratuitamente através do Freenom, ou usar o registrador de domínios de sua escolha.
  • Um Controlador Ingress ingress-nginx e o gerenciador de certificados TLS cert-manager instalados no seu cluster e configurados para emitir certificados TLS. Para aprender como instalar e configurar um Ingress com o cert-manager, consulte Como configurar um Nginx Ingress com Cert-Manager no Kubernetes da plataforma DigitalOcean.
  • Um registro de DNS A com your_domain.com apontando para o endereço IP público do Balanceador de carga do Ingress. Se estiver usando a DigitalOcean para gerenciar os registros de DNS do seu domínio, consulte Como gerenciar os registros de DNS para aprender como criar um registro A.
  • Um bucket de armazenamento de objetos S3, como um espaço da DigitalOcean para armazenar os arquivos estáticos do seu projeto Django e um conjunto de chaves de acesso para esse espaço. Para aprender como criar um espaço, consulte a documentação de produto Como criar espaços. Para aprender como criar chaves de acesso para espaços, consulte Compartilhando acesso a espaços com chaves de acesso. Com pequenas alterações, você pode usar qualquer serviço de armazenamento de objetos que o plug-in django-storages suporte.
  • Uma instância de servidor PostgreSQL, banco de dados e usuário para seu aplicativo Django. Com pequenas alterações, você pode usar qualquer banco de dados compatível com o Django.
    • O banco de dados PostgreSQL deve ser chamado de polls (ou outro nome memorável para inserir em seus arquivos de configuração abaixo) e, neste tutorial, o usuário do banco de dados do Django será chamado sammy. Para orientação sobre como criar esses elementos, siga o Passo 1 de Como construir um aplicativo Django e Gunicorn com o Docker. É necessário realizar esses passos a partir da sua máquina local.
    • Um cluster PostgreSQL gerenciado pela DigitalOcean será usado neste tutorial. Para aprender como criar um cluster, consulte a Documentação de produto de banco de dados gerenciados da DigitalOcean
    • É possível instalar e executar sua própria instância do PostgreSQL. Para obter orientações sobre a instalação e administração do PostgreSQL em um servidor Ubuntu, consulte Como instalar e usar o PostgreSQL no Ubuntu 18.04.
  • Uma conta do Docker Hub e repositório público. Para obter mais informações sobre a criação deles, consulte Repositórios da documentação do Docker.
  • O mecanismo Docker instalado em sua máquina local. Consulte Como instalar e usar o Docker no Ubuntu 18.04 para aprender mais.

Assim que tiver esses componentes configurados, tudo estará pronto para seguir o guia.

Passo 1 — Clonando e configurando o aplicativo

Neste passo, vamos clonar o código do aplicativo do GitHub e definir algumas configurações como as credenciais de banco de dados e chaves de armazenamento de objetos.

O código do aplicativo e o Dockerfile podem ser encontrados na ramificação polls-docker do repositório GitHub do aplicativo Polls de tutorial do Django. Esse repositório contém códigos para o aplicativo de amostra Polls da documentação do Django, que ensina como construir um aplicativo de pesquisa a partir do zero.

A ramificação polls-docker contém uma versão em Docker do aplicativo Polls. Para aprender como o aplicativo Polls foi modificado para funcionar efetivamente em um ambiente em contêiner, consulte Como construir um aplicativo Django e Gunicorn com o Docker.

Comece usando o git para clonar o branch polls-docker do repositório GitHub do aplicativo Polls do tutorial do Django em sua máquina local:

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

Navegue até o diretório django-polls:

  • cd django-polls

Esse diretório contém o código Python do aplicativo Django, um Dockerfile que o Docker usará para compilar a imagem do contêiner, bem como um arquivo env que contém uma lista de variáveis de ambiente a serem passadas para o ambiente de execução do contêiner. Verifique o 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"] 

Esse Dockerfile usa a imagem Docker oficial do Python 3.7.4 como base e instala os requisitos de pacote Python do Django e do Gunicorn, conforme definido no arquivo django-polls/requirements.txt. Em seguida, ele remove alguns arquivos de compilação desnecessários, copia o código do aplicativo na imagem e define o PATH de execução. Por fim, ele declara que a porta 8000 será usada para aceitar conexões de contêiner recebidas e executa gunicorn com 3 trabalhadores, escutando na porta 8000.

Para aprender mais sobre cada um dos passos nesse Dockerfile, confira o Passo 6 de Como construir um aplicativo Django e Gunicorn com o Docker.

Agora, crie a imagem usando o docker build:

  • docker build -t polls .

Nós demos o nome de polls para a imagem usando o sinalizador -t e passamos o diretório atual como um contexto de compilação, que é o conjunto de arquivos de referência ao compilar a imagem.

Depois que o Docker compilar e marcar a imagem, liste as imagens disponíveis usando docker images:

  • docker images

Você deve ver a imagem polls listada:

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 executarmos o contêiner Django, precisamos configurar seu ambiente de execução usando o arquivo env presente no diretório atual. Esse arquivo será passado para o comando docker run usado para executar o contêiner, e o Docker irá injetar as variáveis de ambiente configuradas no ambiente de execução do contêiner.

Abra o arquivo env com o nano ou com o seu 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 

Preencha os valores que estão faltando para as seguintes chaves:

  • DJANGO_SECRET_KEY: defina isso como um valor único e imprevisível, conforme detalhado na documentação do Django. Um método para gerar essa chave é fornecido em Ajustando as configurações do aplicativo do tutorial sobre o Aplicativo Django escalável.
  • DJANGO_ALLOWED_HOSTS: essa variável protege o aplicativo e impede ataques de cabeçalho de host HTTP. Para fins de teste, defina isso como *, um coringa que irá corresponder a todos os hosts. Na produção, isso deve ser definido como your_domain.com. Para aprender mais sobre esse ajuste do Django, consulte as Core Settings da documentação do Django.
  • DATABASE_USERNAME: defina isso como o usuário do banco de dados PostgreSQL criado nos passos pré-requisitos.
  • DATABASE_NAME: defina isso como polls ou o nome do banco de dados PostgreSQL criado nos passos pré-requisitos.
  • DATABASE_PASSWORD: defina isso como a senha do usuário do banco de dados PostgreSQL criada nos passos pré-requisitos.
  • DATABASE_HOST: defina isso como o nome do host do seu banco de dados.
  • DATABASE_PORT: defina isso como a porta do seu banco de dados.
  • STATIC_ACCESS_KEY_ID: defina isso como a chave de acesso do seu espaço ou armazenamento de objetos.
  • STATIC_SECRET_KEY: defina isso como o segredo da chave de acesso do seu espaço ou armazenamento de objetos.
  • STATIC_BUCKET_NAME: defina isso como seu nome de espaço ou bucket de armazenamento de objetos.
  • STATIC_ENDPOINT_URL: defina isso como o URL do ponto de extremidade do espaço apropriado ou armazenamento de objetos, como https://your_space_name.nyc3.digitaloceanspaces.com se o espaço estiver localizado na região nyc3.

Assim que terminar a edição, salve e feche o arquivo.

No próximo passo, vamos executar o contêiner configurado localmente e criar o esquema de banco de dados. Além disso, vamos carregar ativos estáticos como folhas de estilos e imagens para o armazenamento de objetos.

Passo 2 — Criando o esquema de banco de dados e carregando ativos para o armazenamento de objetos

Com o contêiner construído e configurado, use o docker run para substituir o conjunto CMD no Dockerfile e criar o esquema de banco de dados usando os comandos manage.py makemigrations e manage.py migrate:

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

Executamos a imagem de contêiner polls:latest, passamos o arquivo de variável de ambiente que acabamos de modificar e substituímos o comando do Dockerfile com sh -c "python manage.py makemigrations && python manage.py migrate", o que irá criar o esquema de banco de dados definido pelo código do aplicativo.

Se estiver executando isso pela primeira vez, você deve ver:

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 

Isso indica que o esquema de banco de dados foi criado com sucesso.

Se estiver executando migrate uma outra vez, o Django irá cancelar a operação a menos que o esquema de banco de dados tenha sido alterado.

Em seguida, vamos executar outra instância do contêiner de aplicativo e usar um shell interativo dentro dela para criar um usuário administrativo para o projeto Django.

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

Isso lhe fornecerá um prompt do shell dentro do contêiner em execução que você pode usar para criar o usuário do Django:

  • python manage.py createsuperuser

Digite um nome de usuário, endereço de e-mail e senha para o seu usuário e, depois de criá-lo, pressione CTRL+D para sair do contêiner e encerrá-lo.

Por fim, vamos gerar os arquivos estáticos para o aplicativo e fazer o upload deles para o espaço da DigitalOcean usando o collectstatic. Observe que esse processo pode demorar um pouco de tempo para ser concluído.

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

Depois que esses arquivos forem gerados e enviados, você receberá a seguinte saída.

Output121 static files copied. 

Agora, podemos executar o aplicativo:

  • 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 

Aqui, executamos o comando padrão definido no Dockerfile, gunicorn --bind :8000 --workers 3 mysite.wsgi:application e expomos a porta do contêiner 8000 para que a porta 80 na sua máquina local seja mapeada para a porta 8000 do contêiner polls.

Agora, você deve ser capaz de navegar até o aplicativo polls usando seu navegador Web digitando http://localhost na barra de URL. Como não há nenhuma rota definida para o caminho /, você provavelmente receberá um erro 404 Page Not Found, o que é esperado.

Navegue até http://localhost/polls para ver a interface do aplicativo Polls:

Interface do aplicativo Polls

Para visualizar a interface administrativa, visite http://localhost/admin. Você deve ver a janela de autenticação do administrador do aplicativo Polls:

Página de autenticação de administrador do Polls

Digite o nome e a senha do usuário administrativo que você criou com o comando createsuperuser.

Depois de autenticar-se, você pode acessar a interface administrativa do aplicativo Polls:

Interface administrativa principal do Polls

Observe que os ativos estáticos para os aplicativos admin e polls estão sendo entregues diretamente do armazenamento de objetos. Para confirmar isso, consulte Testando a entrega de arquivos estáticos de espaços.

Quando terminar de explorar, aperte CTRL+C na janela do terminal executando o contêiner Docker para encerrar o contêiner.

Com a imagem Docker do aplicativo Django testada, ativos estáticos carregados no armazenamento de objetos e o esquema de banco de dados configurado e pronto para ser usado com seu aplicativo, tudo está pronto para carregar sua imagem do aplicativo Django em um registro de imagem como o Docker Hub.

Passo 3 — Enviando a imagem do aplicativo Django para o Docker Hub

Para implementar seu aplicativo no Kubernetes, sua imagem de aplicativo deve ser carregada em um registro como o Docker Hub. O Kubernetes irá puxar a imagem do aplicativo do seu repositório e implantá-la em seu cluster.

É possível usar um registro privado do Docker, como o registro do contêiner da DigitalOcean, atualmente gratuito em acesso antecipado, ou um registro público do Docker como o Docker Hub. O Docker Hub também permite criar repositórios privados do Docker. Um repositório público permite que qualquer pessoa veja e puxe as imagens do contêiner, enquanto um repositório privado permite restringir o acesso a você e seus membros de equipe.

Neste tutorial, vamos enviar a imagem do Django ao repositório público do Docker Hub criado nos pré-requisitos. Também é possível enviar sua imagem a um repositório privado, mas puxar imagens de um repositório privado está além do escopo deste artigo. Para aprender mais sobre a autenticação do Kubernetes com o Docker Hub e puxar imagens privadas, consulte Puxar uma imagem de um registro privado dos documentos do Kubernetes.

Comece fazendo login no Docker Hub em sua 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: 

Digite seu nome de usuário e senha do Docker Hub para fazer login.

A imagem do Django possui atualmente o sinalizador polls:latest. Para enviá-la ao seu repositório do Docker Hub, sinalize novamente a imagem com seu nome de usuário e nome de repositório do Docker Hub:

  • docker tag polls:latest your_dockerhub_username/your_dockerhub_repo_name:latest

Carregue a imagem no repositório:

  • docker push sammy/sammy-django:latest

Neste tutorial, o nome de usuário do Docker Hub é sammy e o nome do repositório é sammy-django. Você deve substituir esses valores pelo seu nome de usuário e nome de repositório do Docker Hub.

Você verá um resultado que se atualiza conforme as camadas da imagem são enviadas ao Docker Hub.

Agora que sua imagem está disponível no Kubernetes no Docker Hub, você pode começar a implantá-la em seu cluster.

Passo 4 — Configurando o ConfigMap

Quando executamos o contêiner do Django localmente, passamos o arquivo env ao docker run para injetar variáveis de configuração no ambiente de tempo de execução. No Kubernetes, as variáveis de configuração podem ser injetadas usando o ConfigMaps e Segredos.

Os ConfigMaps devem ser usados para armazenar informações de configuração não confidenciais, como as configurações do aplicativo, enquanto os Segredos devem ser usados para informações confidenciais como chaves de API e credenciais de banco de dados. Ambos são injetados em contêineres de maneira similar, mas os Segredos têm recursos de controle de acesso e segurança adicionais, como a criptografia em repouso. Os Segredos também armazenam dados em base64, enquanto os ConfigMaps armazenam dados em texto simples.

Para começar, crie um diretório chamado yaml no qual vamos armazenar nossos manifestos do Kubernetes. Navegue até o diretório.

  • mkdir yaml
  • cd

Abra um arquivo chamado polls-configmap.yaml no nano ou seu editor de texto preferido:

  • nano polls-configmap.yaml

Cole o seguinte manifesto do 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" 

As configurações não confidenciais foram extraídas do arquivo env modificado no Passo 1 e coladas em um manifesto do ConfigMap. O objeto do ConfigMap chama-se polls-config. Copie os mesmos valores inseridos no arquivo env no passo anterior.

Por motivos de teste, deixe o DJANGO_ALLOWED_HOSTS como * para desativar a filtragem baseada em cabeçalhos de host. Em um ambiente de produção, isso deve ser definido como o domínio do seu aplicativo.

Quando terminar de editar o arquivo, salve e feche-o.

Crie o ConfigMap em seu cluster usando o kubectl apply:

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

Com o ConfigMap criado, vamos criar o Segredo usado pelo nosso aplicativo no próximo passo.

Passo 5 — Configurando o Segredo

Os valores do Segredo devem ser codificados em base64, o que significa que criar objetos Segredo em seu cluster é ligeiramente mais complicado do que criar ConfigMaps. É possível repetir o processo do passo anterior, manualmente codificar os valores do Segredo em base64 e colá-los em um arquivo de manifesto. Também é possível criá-los usando um arquivo de variável de ambiente, kubectl create e o sinalizador --from-env-file, o que será feito neste passo.

Novamente, vamos usar o arquivo env do Passo 1, removendo variáveis inseridas no ConfigMap. Faça uma cópia do arquivo env chamado polls-secrets no diretório yaml:

  • cp ../env ./polls-secrets

Edite o arquivo em seu editor de preferência:

  • 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 

Exclua todas as variáveis inseridas no manifesto do ConfigMap. Quando terminar, ele deve ficar parecido com isto:

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 

Certifique-se de usar os mesmos valores usados no Passo 1. Quando terminar, salve e feche o arquivo.

Crie o Segredo em seu cluster usando o kubectl create secret:

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

Aqui, criamos um objeto Segredo chamado polls-secret e o passamos no arquivo de Segredos que acabamos de criar.

Verifique o Segredo usando o 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 

Neste ponto, você armazenou a configuração do seu aplicativo em seu cluster do Kubernetes usando os tipos de objeto Segredo e ConfigMap. Agora, estamos prontos para implantar o aplicativo no cluster.

Passo 6 — Implementando o aplicativo do Django usando uma Implantação

Neste passo, você criará um Deployment (implantação) para seu aplicativo do Django. Uma Implantação do Kubernetes é um controlador que pode ser usado para gerenciar aplicativos sem estado em seu cluster. Um controlador é um loop de controle que regula cargas de trabalho aumentando ou diminuindo-as. Os controladores também reiniciam e limpam contêineres com falhas.

As Implantações controlam um ou mais Pods, a menor unidade implantável em um cluster do Kubernetes. Os Pods incluem um ou mais contêineres. Para aprender mais sobre os diferentes tipos de cargas de trabalho que você pode inicializar, consulte Uma introdução ao Kubernetes.

Inicie abrindo um arquivo chamado polls-deployment.yaml no seu editor de texto favorito:

  • nano polls-deployment.yaml

Cole o manifesto de Implantação a seguir:

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 

Preencha o nome apropriado da imagem do contêiner, referenciando a imagem do Polls do Django que você enviou para o Docker Hub no Passo 2.

Aqui, definimos uma Implantação do Kubernetes chamada polls-app e a rotulamos com o par de chave-valor app: polls. Especificamos que queremos executar duas réplicas do Pod definido abaixo do campo template.

Usando o envFrom com o secretRef e o configMapRef, especificamos que todos os dados do Segredo polls-secret e do ConfigMap polls-config devem ser injetados nos contêineres como variáveis de ambiente. As chaves ConfigMap e Segredo tornam-se os nomes das variáveis de ambiente.

Por fim, expomos a containerPort 8000 e a nomeamos gunicorn.

Para aprender mais sobre como configurar as Implantações do Kubernetes, consulte Deployments na documentação do Kubernetes.

Quando terminar de editar o arquivo, salve e feche-o.

Crie uma Implantação no seu cluster usando o kubectl apply -f:

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

Verifique se a Implantação foi implantada corretamente usando o kubectl get:

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

Se encontrar um erro ou algo não estiver funcionando, use o kubectl describe para verificar o Deployment que falhou:

  • kubectl describe deploy

Verifique os dois Pods usando o 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 

Agora, duas réplicas do seu aplicativo Django estão em funcionamento no cluster. Para acessar o aplicativo, é necessário criar um Service (serviço) do Kubernetes, que vamos fazer em seguida.

Passo 7 — Permitindo o acesso externo usando um Serviço

Neste passo, você irá criar um Serviço para seu aplicativo Django. Um Serviço do Kubernetes é uma abstração que permite expor um conjunto de Pods em execução como um serviço de rede. Ao usar um Serviço, é possível criar um ponto de extremidade estável para seu aplicativo que não muda à medida que os Pods são destruídos e recriados.

Existem vários tipos de Serviço, incluindo os Serviços de ClusterIP, que expõem o Serviço em um IP interno do cluster, os Serviços de NodePort, que expõem o Serviço em cada nó em uma porta estática chamada NodePort, além de os Serviços de LoadBalancer, que fornecem um balanceador de carga em nuvem para direcionar o tráfego externo aos Pods no seu cluster (através dos NodePorts, criados por ele automaticamente). Para aprender mais sobre isso, consulte Service nos documentos do Kubernetes.

Em nossa configuração final, vamos usar um Serviço de ClusterIP que é exposto usando um Ingress e um Controlador Ingress configurados nos pré-requisitos deste guia. Por enquanto, para testar se tudo está funcionando corretamente, vamos criar um Serviço de NodePort temporário para acessar o aplicativo Django.

Inicie criando um arquivo chamado polls-svc.yaml usando seu editor favorito:

  • nano polls-svc.yaml

Cole o manifesto de Serviço a seguir:

polls-svc.yaml

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

Aqui, criamos um Serviço de NodePort chamado polls e damos a ele o rótulo app: polls. Em seguida, selecionamos os Pods de backend com o rótulo app: polls e miramos em suas portas 8000.

Quando terminar de editar o arquivo, salve e feche-o.

Implemente o Serviço usando o kubectl apply:

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

Confirme se seu Serviço foi criado usando o 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 

Esse resultado mostra o IP interno do cluster do Serviço e o NodePort (32654). Para nos conectar ao serviço, precisamos dos endereços IP externos para nossos nós de cluster:

  • 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 

Em seu navegador Web, visite seu aplicativo Polls usando um endereço IP externo de qualquer nó e o NodePort. De acordo com o resultado acima, a URL do aplicativo seria: http://203.0.113.1:32654/polls.

Você deve ver a mesma interface do aplicativo Polls que você acessou localmente no Passo 1:

Interface do aplicativo Polls

É possível repetir o mesmo teste usando a rota /admin: http://203.0.113.1:32654/admin. Você deve ver a mesma interface de administrador que antes:

Página de autenticação de administrador do Polls

Neste estágio, você já implantou duas réplicas do contêiner do aplicativo Polls do Django usando uma Implantação. Você também criou um ponto de extremidade de rede estável para essas duas réplicas, e o tornou externamente acessível usando um Serviço de NodePort.

O passo final neste tutorial é proteger o tráfego externo para seu aplicativo usando HTTPS. Para fazer isso, vamos usar o Controlador Ingress ingress-nginx instalado nos pré-requisitos e criar um objeto Ingress para rotear o tráfego externo para o Serviço polls do Kubernetes.

Passo 8 — Configurando o HTTPS usando o Nginx Ingress e o cert-manager

Os Ingresses do Kubernetes permitem o roteamento do tráfego externo ao cluster do seu Kubernetes de maneira flexível para os Serviços dentro de seu cluster. Isso é alcançado usando os objetos do Ingress, que definem as regras para rotear o tráfego HTTP e HTTPS para os Serviços do Kubernetes e para os Controladores do Ingress, os quais implementam as regras fazendo o balanceamento da carga do tráfego e o seu roteamento para os Serviços de backend apropriados.

Nos pré-requisitos, você instalou o Controlador Ingress ingress-nginx e o add-on de automação de certificados TLS cert-manager. Você também definiu a preparação e a produção de ClusterIssuers para seu domínio usando a autoridade de certificação Let’s Encrypt e criou um Ingress para testar a emissão de certificados e a criptografia TLS em dois Serviços de backend fictícios. Antes de continuar com este passo, deve-se excluir o Ingress echo-ingress criado no tutorial pré-requisito:

  • kubectl delete ingress echo-ingress

Se desejar, também pode excluir os Serviços e Implantações fictícios usando o kubectl delete svc e o kubectl delete deploy, mas isso não é essencial para completar este tutorial.

Você também deve ter criado um registro de DNS A com your_domain.com apontando para o endereço IP público do balanceador de carga do Ingress. Se estiver usando um balanceador de carga da DigitalOcean, é possível encontrar esse endereço IP na seção Load Balancers do Painel de controle. Se estiver usando a DigitalOcean para gerenciar os registros de DNS do seu domínio, consulte Como gerenciar os registros de DNS para aprender como criar registros A.

Se estiver usando o Kubernetes da DigitalOcean, também certifique-se de ter implementado a solução descrita no Passo 5 de Como configurar um Nginx Ingress com o Cert-Manager no Kubernetes da DigitalOcean.

Assim que tiver um registro A apontando para o balanceador de carga do Ingress, crie um Ingress para your_domain.com e o Serviço polls.

Abra um arquivo chamado polls-ingress.yaml no seu editor favorito:

  • nano polls-ingress.yaml

Cole o manifesto de Ingress a seguir:

[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 

Criamos um objeto Ingress chamado polls-ingress e o anotamos para instruir o plano de controle para usar o Controlador Ingress ingress-nginx e o ClusterIssuer de preparo. Também habilitamos o TLS para your_domain.com e armazenamos o certificado e a chave privada em um segredo chamado polls-tls. Por fim, definimos uma regra para rotear o tráfego para o host your_domain.com para o Serviço polls na porta 8000.

Quando terminar de editar o arquivo, salve e feche-o.

Crie o Ingress no seu cluster usando o kubectl apply:

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

É possível usar o kubectl describe para rastrear o estado do Ingress que acabou de ser criado:

  • 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 

Também é possível executar um describe no certificado polls-tls para confirmar ainda mais se sua criação foi bem-sucedida:

  • 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 

Isso confirma que o certificado TLS foi emitido com sucesso e a criptografia do HTTPS agora está ativa para your_domain.com.

Como usamos o ClusterIssuer de preparo, a maior parte dos navegadores Web não irá confiar no certificado falso do Let’s Encrypt que ele emitiu, de forma que navegar até your_domain.com irá resultar em uma página de erro.

Para enviar um pedido de teste, vamos usar o wget a partir da linha de comando:

  • 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'. 

Vamos usar o sinalizador sugerido --no-check-certificate para ignorar a validação de certificados:

  • 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> 

Esse resultado mostra o HTML para a página de interface de /polls, o que também confirma que a folha de estilos está sendo exibida a partir do armazenamento de objetos.

Agora que você testou com sucesso a emissão de certificados usando o ClusterIssuer de preparo, modifique o Ingress para usar o ClusterIssuer de produção.

Abra o polls-ingress.yaml para editar mais uma vez:

  • nano polls-ingress.yaml

Modifique a anotação do 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 

Quando terminar, salve e feche o arquivo. Atualize o Ingress usando o kubectl apply:

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

É possível usar o kubectl describe certificate polls-tls e o kubectl describe ingress polls-ingress para rastrear o status da emissão de certificados:

  • 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" 

O resultado acima confirma que o novo certificado de produção foi emitido com sucesso e armazenado no Secredo polls-tls.

Navegue até your_domain.com/polls no seu navegador Web para confirmar se a criptografia do HTTPS está habilitada e tudo está funcionando como esperado. Você deve ver a interface do aplicativo Polls:

Interface do aplicativo Polls

Verifique se a criptografia do HTTPS está ativa no seu navegador Web. Se estiver usando o Google Chrome, chegar na página acima sem erros confirma que tudo está funcionando corretamente. Além disso, você deve ver um cadeado na barra de URL. Clicar no cadeado permitirá verificar os detalhes do certificado do Let’s Encrypt.

Como uma tarefa de limpeza final, você pode alterar opcionalmente o tipo de Serviço polls do NodePort para o tipo exclusivamente interno ClusterIP.

Modifique o polls-svc.yaml usando seu editor:

  • nano polls-svc.yaml

Altere o type de NodePort para 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 

Quando terminar de editar o arquivo, salve e feche-o.

Implemente as alterações usando o kubectl apply:

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

Confirme se seu Serviço foi modificado usando o 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 

Esse resultado mostra que o tipo de Serviço é agora ClusterIP. A única maneira de acessá-lo é através do seu domínio e do Ingress criados neste passo.

Conclusão

Neste tutorial, você implantou um aplicativo Django dimensionável e seguro via HTTPS em um cluster do Kubernetes. O conteúdo estático é servido diretamente do armazenamento de objetos, e o número de Pods em execução pode ser aumentado ou reduzido rapidamente usando o campo replicas no manifesto de Implantação polls-app.

Se estiver usando um espaço da DigitalOcean, também é possível habilitar a entrega de ativos estáticos através de uma rede de entrega de conteúdo e criar um subdomínio personalizado para seu espaço. Por favor, consulte Habilitando o CDN de Como configurar um aplicativo Django dimensionável com os bancos de dados e espaços gerenciados da DigitalOcean para aprender mais.

Para revisar o resto da série, visite nossa página da série De contêineres ao Kubernetes com o Django.