A stack de arquitetura de uma startup de tecnologia de uma pessoa só
(anthonynsimon.com)-
Explicação da arquitetura de um desenvolvedor solo que opera um SaaS de forma tranquila, sem estresse
-
Montou uma infraestrutura para operar vários projetos ao mesmo tempo
-
Explica com base no PanelBear, um SaaS que criou recentemente
→ começou no menor VPS possível com SQLite + Django
→ após 6 meses de iteração, evoluiu para Django monolítico sobre EKS + Postgres + ClickHouse (análises) + Redis (cache) + Celery (tarefas agendadas)
→ quase tudo automatizado: autoscaling, ingress, certificados TLS, failover, logging, monitoramento etc.
→ como usa essa configuração em vários projetos, consegue reduzir custos e iniciar experimentos com muita facilidade
→ quase não gasta tempo com gestão de infraestrutura (0 a 2 horas por mês)
→ usa a maior parte do tempo para desenvolver funcionalidades, dar suporte aos clientes e fazer o negócio crescer -
Usa Kubernetes na AWS, mas isso não é necessariamente obrigatório. Ainda assim, acredita que consegue operar com estabilidade por já estar familiarizado com a ferramenta.
→ aprendeu usando essa ferramenta por vários anos em uma equipe paciente (que aguentava e resolvia os erros junto)
→ "Kubernetes torna o simples complicado, mas também pode tornar o complicado simples" -
DNS, SSL e balanceamento de carga automáticos
→ todo o tráfego é encaminhado do CloudFlare Proxy para o AWS L4 NLB (Network Load Balancer)
→ quando uma request chega, o LB a encaminha para um dos nós do cluster k8s
→ esses nós ficam em sub-redes privadas distribuídas por várias AZs (Availability Zones)
→ quem descobre para qual serviço o k8s deve enviar a requisição é oingress-nginx(cluster Nginx)
→ antes de encaminhar o tráfego, o nginx aplica regras de rate limiting e traffic shaping
→ no caso do PanelBear, o container da aplicação é Django servido pelo Uvicorn
→ existem alguns arquivos de configuração entre Terraform/K8s que são compartilhados pela maioria dos projetos
→ ao implantar um novo projeto, cerca de 20 linhas de configuração de ingress bastam -
Rollout e rollback automáticos
→ toda vez que há push para a branch master, um pipeline de CI é executado com GitHub Actions
→ inspeciona a codebase e monta um ambiente completo com Docker-Compose para testes end-to-end
→ se passar nas verificações, gera uma nova imagem Docker e faz push para o ECR (registro Docker da AWS)
→ o componente flux no cluster k8s ( https://fluxcd.io/ ) sincroniza automaticamente as imagens no cluster
→ o Flux executa rollout incremental automaticamente -
Horizontal Autoscaling
→ autoscaling com base no uso de CPU/memória
→ se houver Pods demais por nó no cluster, cria automaticamente mais servidores para aumentar a capacidade do cluster e reduzir a carga; quando não há trabalho, reduz novamente
→ no caso do PanelBear, ajusta automaticamente as réplicas do Pod da API de 2 até 8 -
Cache de static assets com CDN
→ configura o CloudFlare no DNS para processar todas as requisições e ainda mitigar DDoS
→ para servir arquivos estáticos usa Whitenoise ( https://github.com/evansd/whitenoise ), então não precisa fazer upload dos arquivos para NGinx/Cloudfront/S3
→ em alguns sites estáticos, como a landing page do Panelbear, usa NextJS -
Cache de dados da aplicação
→ em algumas partes usa o cache LRU em memória oferecido pelo Python
→ a maioria dos endpoints usa Redis dentro do cluster -
Rate limiting por endpoint
→ faz rate limiting global nonginx-ingress, mas às vezes é preciso aplicar limites específicos por endpoint/método
→ usa a biblioteca Django Ratelimit para declarar limites por view do Django
→ configurado para usar Redis como backend e rastrear clientes que acessam cada endpoint (hash com base em chave do cliente, não em IP) -
Administração do app
→ o Admin Panel do Django já oferece, por padrão, recursos para visualizar e editar dados
→ adicionou funções como bloquear acesso a contas suspeitas / enviar emails de aviso / processar solicitações de exclusão de conta (primeiro com soft delete, depois exclusão completa em até 72 horas) -
Execução de tarefas agendadas
→ em um SaaS, várias tarefas agendadas rodam: relatórios diários para clientes, cálculo de estatísticas de uso a cada 15 minutos, emails de métricas para a equipe etc.
→ mantém alguns workers do Celery e o scheduler Celery beat rodando dentro do cluster. Usa Redis como fila de tarefas
→ usa o HealthChecks.io para ser avisado por SMS/Slack/Email quando tarefas agendadas não são executadas corretamente -
Configuração do app
→ toda a configuração usa variáveis de ambiente. É antigo, mas portátil e bem suportado -
Protegendo segredos
→ usakubeseal. Ele criptografa os Secrets com criptografia assimétrica. Só clusters com permissão de acesso à chave de descriptografia conseguem descriptografar
→ usa chaves de criptografia do AWS KMS para proteger os Secrets dentro do cluster -
Dados relacionais: Postgres
→ para experimentos, roda um container Postgres vanilla dentro do cluster e faz backup diário para o S3 com um K8s Cronjob
→ quando o projeto cresce, move o banco de dados do cluster para o RDS, deixando a AWS cuidar de backups criptografados, updates de segurança etc.
→ para reforçar a segurança, o banco de dados na AWS só pode ser acessado pela rede privada -
Dados colunares: ClickHouse
→ usa ClickHouse para armazenar com eficiência e consultar em tempo real os dados analíticos do PanelBear
→ é um excelente banco de dados colunar, muito rápido e, com a modelagem certa, oferece alta compressão (menos storage = mais lucro)
→ hospeda a instância do ClickHouse por conta própria dentro do cluster K8s
→ criou um CronJob que faz backup periódico dos dados colunares para o S3
→ tem alguns scripts para backup e restauração manual dos dados a partir do S3 em caso de desastre -
Descoberta de serviços baseada em DNS
→ o K8s gerencia automaticamente os registros DNS dentro do cluster e roteia o tráfego para o serviço correspondente
→ mesmo durante o autoscaling, sincroniza automaticamente os registros DNS para conectar aos Pods saudáveis -
Infraestrutura com versionamento
→ gerencia Docker, Terraform e manifests do K8s em um único repositório (Infra Mono-Repo)
→ é possível criar e remover infraestrutura com comandos simples, e o versionamento permite reprodutibilidade -
Terraform para recursos de cloud
→ a maior parte dos recursos de cloud é gerenciada com Terraform
→ isso permite documentar e rastrear recursos e configurações de infraestrutura -
Manifests de K8s para deploy do app
→ os manifests de K8s estão escritos em arquivos YAML no mono-repo de infraestrutura
→ dividido em duas pastas:clustereapps
→clusterinclui configurações relacionadas a serviços do cluster comonginx-ingress, secrets criptografados e scrapers do Prometheus
→appsarmazena as informações de um namespace por projeto -
Assinaturas e pagamentos
→ usa Stripe Checkout para processar todos os pagamentos
→ como não precisa lidar diretamente com os dados de pagamento, consegue focar no produto
→ basta criar a sessão do cliente, redirecionar para a página da Stripe e receber o resultado por WebHook -
Logging
→ sem usar agente de logging: basta enviar logs para ostdoutque o k8s coleta automaticamente e também faz rotação
→ seria possível enviar para Elasticsearch/Kibana via FluentBit etc., mas ainda não faz isso para manter a simplicidade
→ para inspecionar logs, usa a ferramenta de CLIstern -
Monitoramento e alertas
→ no início hospedava Prometheus / Grafana por conta própria, mas quando havia problema no cluster, o sistema de alertas também caía, o que era inconveniente
→ por isso, migrou para o New Relic
→ todos os serviços têm integração com Prometheus para coletar métricas automaticamente e enviar para Datadog, New Relic, Grafana Cloud etc.; assim, a migração para o New Relic foi possível apenas usando a imagem Docker do Prometheus fornecida por eles -
Rastreamento de erros
→ usa Sentry para coletar erros da aplicação
→ centraliza todos os alertas no canal Slack#alerts: downtime, falhas de cron job, alertas de segurança, regressões de performance, exceções da aplicação etc. -
Profiling e outras coisas úteis
→ quando precisa de análise profunda, usa ferramentas comocProfileousnakeviz
→ na máquina local, usa Django Debug Toolbar
11 comentários
Obrigado.
Há muita diferença de funcionalidade entre o Sentry e o New Relic?
Eu achava que eles faziam coisas parecidas, mas ainda não usei nenhum dos dois.
Ah, nossa empresa também está avaliando adotar k8s, e este é um texto bastante bom mesmo para startups que não são de uma pessoa só.
Obrigado pelo ótimo texto. Saio daqui inspirado.
É um bom texto, mesmo que não seja necessariamente sobre uma startup de uma pessoa só
Tem um pequeno erro de digitação,,
→ usar o Sentry para coletar erros da aplicação
=> acho que o correto é “coletar”
Obrigado. Corrigi~!
Eu espero que surjam mais desenvolvedores solo ou pequenas equipes no país que ganhem dinheiro com seus próprios serviços.
Espero que o GeekNews cresça como um espaço onde esses serviços possam se apresentar e receber feedback saudável.
Retrospectiva de 6 meses operando uma startup SaaS solo https://pt.news.hada.io/topic?id=2415
Operando uma startup de software com o mínimo de esforço https://pt.news.hada.io/topic?id=1534
Relatório sobre o estado do SaaS independente em 2021 [slides de 63 páginas] https://pt.news.hada.io/topic?id=3728
História da experiência de ter falhado ao tentar criar uma empresa de 1 trilhão de won https://pt.news.hada.io/topic?id=2
Eu vendo cebolas na internet https://pt.news.hada.io/topic?id=3
O que um CEO de startup ex-Samsung aprendeu ao perder 1,2 bilhão de won https://pt.news.hada.io/topic?id=3015
Operando uma startup por US$6 ao ano https://pt.news.hada.io/topic?id=1621
Obrigado.
Concordo. Obrigado :)
👍