Deploy escalável para projetos em Django
Construindo deploys prontos para escalar.
Primeiramente para este artigo preciso definir o cenário da nossa stack de aplicação. A título de exemplo, imagine que nossa stack seja composta de:
- Uma aplicação backend feita em sua maior parte com Django e Django Rest framework;
- Uma aplicação frontend feita em sua maior parte com Django e Vuejs;
- Uma aplicação mobile que consome o backend;
- Uma estrutura BFF construída em cima da API REST;
Ainda antes de continuarmos eu preciso vos falar a respeito do escopo deste artigo.
Por propósito de aprendizagem, esta é uma estrutura mínima para projetos crescentes sobre servidores WSGI. Eu não pretendo me aprofundar a respeito dos detalhes técnicos mas garantir que primeiramente falemos a respeito de conceitos. Por favor, sinta-se a vontade para expandir ou reduzir esses conceitos ou fazer ainda qualquer coisa que lhe seja útil.
Escopo definido, vamos lá!
Desenhando o conceito:
LBC - O contêiner de balanceamento de carga:
Aqui todas as requisições de fora chegarão. Por motivos óbvios, este contêiner deverá ser o único ponto de acesso do mundo externo e perigoso para sua aplicação.
De maneira geral, este contêiner irá somente aceitar conexões vindas de:
- Porta 80 via HTTP. Somente necessário para redirecionar acessos HTTP para HTTPS
- Porta 443 via HTTP. Para poder fazer a validação e o acesso HTTP via SSL;
Vamos dar uma olhada nos principais papéis da nossa stack de software do balanceador de carga:
Nginx: Servidor web poderoso para servir arquivos estáticos, mapear acesso WSGI quando necessário e agir como balanceador de carga para cada contêiner de aplicação;
Fail2ban: Este software busca por requisições maliciosas nos arquivos de log a fim de identificar crawlers e bots, checa por tentativas de autenticação inválidas e realiza ações para bani-las;
UFW Firewall: Realiza as ações do fail2ban para negar acessos quando necessário banir requisições maliciosas. Na prática o UFW é uma interface para o bom e velho IPTables;
Quando for necessário escalar esse contêiner, normalmente uma escala vertical resolverá os problemas para esse fim e permitirá mais algumas milhares de requisições a mais.
APC - O contêiner de aplicação:
Para fins de entendimento, observem que as requisições oriundas do mundo externo estão desenhadas no diagrama em laranja, ao passo que as requisições privadas do sistema são desenhadas em verde.
A conexão de requisição oriunda do contêiner de balanceamento de carga para a aplicação será trafegada exclusivamente pela rede privada (VPN) na porta 80, uma vez que, o SSL handshake já foi realizado nele e o destino não é alcancável pela rede externa.
Aqui é onde o deploy de suas aplicações Django irão rodar em cima de um servidor WSGI, (Geralmente Gunicorn ou uWSGI são as escolhas mais comuns). O arquivo SOCK resultante então é mapeado para o Nginx rodando no contêiner de aplicação para que o Nginx do balanceador de carga possa acessá-lo através das requisições vindas de lá;
Quando você precisar escalar esse contêiner, geralmente uma escala horizontal funciona bem. Apenas é necessário que o balanceador de carga reconheça para onde direcionar as requisições e você terá mais um destino para direcionar as requisições de entrada.
ACC - O contêiner de cache e chamadas assíncronas;
A maioria das aplicações modernas em algum momento irão necessitar de algum nível de cache ou de processamento assíncrono. Para essa funcionalidade utilizaremos este contêiner, veja abaixo algumas alternativas de software comumente utilizadas aqui.
Redis: Bom para fazer cache e para lidar com processos assíncronos de filas MQQT;
Memcached: Este é meu serviço de cache favorito e que uso ostensivamente;
RabbitMQ: Um excelente servidor de filas MQQT para tarefas assíncronas, confiável e de alta velocidade;
ElasticSearch: Excelente para realizar cache de consultas constantes da sua aplicação;
Cada contêiner de aplicação deverá ter a habilidade de consultar os serviços deste contêiner em específico para realizar suas tarefas. A respeito de escala, geralmente não é necessário escalar este tipo de contêiner, acredito que em muitos casos, uma simples escala vertical resolverá o problema.
MMC - O contêiner de mídia:
Arquivos de mídia como serviços são um importante conceito para aplicações modernas. Com o Django, o pacote de de aplicação BOTO pode facilmente acessar serviços como AWS S3 ou outros do tipo de "armazenamento de objetos". Até mesmo uma versão só sua como o uma instância MINIO. O mais importante aqui é monitorar sempre o uso de disco, backups frequentes e claro, rodar isso tudo em cima de um bom serviço de CDN. (Um agradecimento especial ao pessoal do Cloudflare a este respeito)
DBC - O contêiner de banco de dados:
A maioria dos bancos de dados relacionais podem ser "tunados" para operação de leitura ou de escrita, entretanto, geralmente eles não podem ser "tunados" para ambas as operações na mesma instância. É usualmente uma boa ideia ter duas ou mais instâncias de banco de dados recebendo replicação em um esquema master -> slave. Assim ao passo que as operações de escritas são feitas para o servidor master e que os slaves recebem as alterações dele, utilizando o conceito de "Database Routers" do Django facilmente podemos apontar nossa aplicação para onde ler ou escrever dados.
Outro ponto interessante a respeito desse esquema de replicação é o de ter um servidor escravo replicado em outro datacenter distante geograficamente para compor um bom plano de recuperação em caso de catástrofes de sistema.
CDC - contêiner de deploy contínuo:
O contêiner de deploy contínuo irá receber todas as informações de "pushes" dos nossos repositórios git e irá disparar para os contêiners de aplicação conhecidos por ele uma ordem para que os sistemas se atualizem. A ideia do deploy contínuo consiste em testar o software com as novas modificações e caso os mesmos passem nos testes fazer o deploy quase ao mesmo tempo que o push foi feito.
Conclusão:
Iniciar um deployment de uma aplicação Django WSGI do jeito certo pode reduzir a quantidade de problemas em projetos de software que necessitam ganhar escala rapidamente. Todos os pontos dessa estrutura levam a um ciclo de projeto maduro e crescente, mas claro que, como disposto no escopo não tem a intenção de ser uma bala de prata. Caso sinta-se aberto para expor seu jeito de fazer deploy, fazer questionamentos ou tirar dúvidas fique a vontade nos comentários.