50 puntos por xguru 2021-04-12 | 11 comentarios | Compartir por WhatsApp
  • Explicación de la arquitectura de un desarrollador solitario que opera un SaaS sin estrés y a un ritmo tranquilo

  • Armó una infraestructura para operar varios proyectos al mismo tiempo

  • Explica tomando como referencia PanelBear, un SaaS que creó recientemente
    → empezó con SQLite + Django en el VPS más pequeño
    → tras 6 meses de iteración, pasó a Django monolítico + Postgres + ClickHouse (analítica) + Redis (caché) + Celery (tareas programadas) sobre EKS
    → casi todo está automatizado: autoscaling, ingress, certificados TLS, failover, logging, monitoreo, etc.
    → como usa esta configuración en varios proyectos, puede reducir costos e iniciar experimentos realmente fácil
    → casi no le dedica tiempo a administrar la infraestructura (0 a 2 horas al mes)
    → usa la mayor parte del tiempo en desarrollar funciones, dar soporte a clientes y hacer crecer el negocio

  • Usa Kubernetes en AWS, pero no es obligatorio. Aun así, cree que puede operarlo de forma estable porque ya le es familiar.
    → lo aprendió usando esta herramienta durante años en un equipo paciente (que toleraba y ayudaba a contener los errores)
    → "Kubernetes hace complejas las cosas simples, pero también puede simplificar las cosas complejas"

  • DNS, SSL y balanceo de carga automáticos
    → todo el tráfico se envía desde CloudFlare Proxy a AWS L4 NLB (Network Load Balancer)
    → cuando entra una request, el LB la reenvía a uno de los nodos del clúster de k8s
    → estos nodos están en subredes privadas distribuidas en varias AZ (Availability Zone)
    → ingress-nginx (clúster de Nginx) se encarga de que k8s identifique a qué servicio debe ir la solicitud
    → antes de reenviar el tráfico, nginx aplica reglas de rate limiting y traffic shaping
    → en el caso de PanelBear, el contenedor de la app es Django servido con Uvicorn
    → hay algunos archivos de configuración entre Terraform y K8s, compartidos por la mayoría de los proyectos
    → desplegar un proyecto nuevo requiere unas 20 líneas de configuración de ingress

  • Rollout y rollback automáticos
    → cada vez que hace push a master, se ejecuta un pipeline de CI con GitHub Actions
    → inspecciona la base de código y crea un entorno completo con Docker-Compose para pruebas end-to-end
    → si las verificaciones pasan, construye una nueva imagen de Docker y la sube a ECR (el Docker Registry de AWS)
    → un componente de flux en el clúster de k8s ( https://fluxcd.io/ ) sincroniza automáticamente la imagen dentro del clúster
    → Flux ejecuta automáticamente un incremental rollout

  • Horizontal Autoscaling
    → autoscaling basado en uso de CPU/memoria
    → si hay demasiados Pods por nodo en el clúster, crea automáticamente más servidores para aumentar la capacidad y reducir la carga; cuando no hay trabajo, reduce la escala
    → en el caso de PanelBear, ajusta automáticamente las réplicas de los Pods de la API de 2 a 8

  • Caché de static assets usando CDN
    → configura CloudFlare en el DNS para manejar todas las solicitudes y también mitigar DDoS
    → para servir archivos estáticos usa Whitenoise ( https://github.com/evansd/whitenoise ), así que no necesita subir archivos a Nginx/Cloudfront/S3
    → para algunos sitios web estáticos como la landing de PanelBear, usa NextJS

  • Caché de datos de la aplicación
    → en algunas partes usa la caché LRU en memoria que ofrece Python
    → la mayoría de los endpoints usan Redis dentro del clúster

  • Rate limiting por endpoint
    → nginx-ingress aplica rate limiting global, pero a veces necesita límites específicos por endpoint/método
    → usa la librería Django Ratelimit para declarar límites por vista de Django
    → está configurado para rastrear a los clientes que hacen requests a cada endpoint usando Redis como backend (hash basado en clave de cliente, no en IP)

  • Administración de la app
    → el Admin Panel de Django ya ofrece funciones para ver y editar datos
    → agregó funciones como bloquear acceso a cuentas sospechosas / enviar emails de aviso / procesar solicitudes de eliminación de cuenta (al principio hace soft delete y luego borrado completo dentro de 72 horas)

  • Ejecución de tareas programadas
    → en un SaaS se ejecutan varias tareas programadas: reportes diarios para clientes, cálculo de estadísticas de uso cada 15 minutos, emails de métricas para empleados, etc.
    → ejecuta varios workers de Celery y el scheduler Celery beat dentro del clúster; usa Redis como task queue
    → usa HealthChecks.io para recibir avisos por SMS/Slack/Email cuando una tarea programada no se ejecuta correctamente

  • Configuración de la app
    → toda la configuración usa variables de entorno. Es algo antiguo, pero portable y bien soportado

  • Manejo de secretos
    → usa kubeseal. Cifra los Secrets con criptografía asimétrica. Solo los clústeres con permisos para acceder a la clave de descifrado pueden desencriptarlos
    → para proteger los Secrets dentro del clúster usa claves de cifrado de AWS KMS

  • Datos relacionales: Postgres
    → para experimentos opera un contenedor vanilla de Postgres dentro del clúster y hace respaldos diarios a S3 con un K8s Cronjob
    → cuando el proyecto crece, mueve la base de datos fuera del clúster hacia RDS, y deja que AWS se encargue de respaldos cifrados y actualizaciones de seguridad
    → para reforzar la seguridad, la DB de AWS solo es accesible desde la red privada

  • Datos columnares: ClickHouse
    → usa ClickHouse para almacenar y consultar en tiempo real de forma eficiente los datos analíticos de PanelBear
    → es una excelente base de datos columnar, extremadamente rápida y, si la estructura está bien diseñada, logra una alta tasa de compresión (menos almacenamiento = más ingresos)
    → hace self-hosting de una instancia de ClickHouse dentro del clúster de K8s
    → creó un CronJob para respaldar periódicamente los datos columnares en S3
    → tiene algunos scripts para respaldar y restaurar manualmente los datos desde S3 en caso de desastre

  • Descubrimiento de servicios basado en DNS
    → K8s administra automáticamente los registros DNS dentro del clúster para enrutar el tráfico al servicio correspondiente
    → incluso durante el autoscaling, sincroniza automáticamente los registros DNS para conectar con Pods saludables

  • Infraestructura controlada por versión
    → administra Docker, Terraform y los manifests de K8s en un único repositorio (infra mono-repo)
    → permite crear y eliminar infraestructura con comandos simples, y es reproducible mediante control de versiones

  • Terraform para recursos cloud
    → la mayoría de los recursos en la nube se administran con Terraform
    → esto permite documentar y rastrear los recursos y la configuración de la infraestructura

  • K8s manifest para desplegar apps
    → los K8s manifests están escritos en archivos YAML dentro del mono-repo de infraestructura
    → está dividido en dos carpetas: cluster y apps
    cluster incluye configuraciones relacionadas con servicios de todo el clúster, como nginx-ingress, secrets cifrados y scrapers de Prometheus
    apps guarda la información de un namespace por proyecto

  • Suscripciones y pagos
    → procesa todos los pagos con Stripe Checkout
    → como no necesita involucrarse con la información de pago en sí, puede enfocarse en el producto
    → basta con crear una sesión del cliente, redirigir a la página de Stripe y recibir el resultado por WebHook

  • Logging
    → sin usar un agente de logging, basta con imprimir logs en stdout para que k8s los recopile y también haga rotación automáticamente
    → podría enviarlos a Elasticsearch/Kibana mediante FluentBit, etc., pero todavía no lo hace para mantener todo simple
    → para inspeccionar logs usa la herramienta CLI stern

  • Monitoreo y alertas
    → al principio hizo self-hosting de Prometheus / Grafana, pero cuando había problemas en el clúster también se caía el sistema de alertas, lo que era inconveniente
    → por eso cambió a New Relic
    → todos los servicios tienen una integración con Prometheus que recopila métricas automáticamente y puede enviarlas a Datadog, New Relic, Grafana Cloud, etc.; para migrar a New Relic bastó con usar la imagen Docker de Prometheus que ellos ofrecen

  • Seguimiento de errores
    → recopila errores de la aplicación usando Sentry
    → centraliza todas las alertas —downtime, fallas de cron jobs, alertas de seguridad, regresiones de rendimiento, excepciones de la aplicación, etc.— usando el canal #alerts de Slack

  • Profiling y otras cosas útiles
    → cuando necesita análisis profundo usa herramientas como cProfile o snakeviz
    → en la máquina local usa Django Debug Toolbar

11 comentarios

 
wellsbabo 2024-08-13

Gracias

 
admin2 2021-04-13

¿Hay mucha diferencia entre las funciones de Sentry y New Relic?

Pensaba que hacían cosas parecidas, pero todavía no he usado ninguna.

 
kbumsik 2021-04-13

Oh, en nuestra empresa también estamos evaluando adoptar k8s, y es un artículo bastante bueno incluso aunque no se trate de una startup de una sola persona.

 
fortune 2021-04-12

Gracias por el buen artículo. Me voy muy inspirado.

 
khris 2021-04-12

Es un buen artículo incluso si no se trata específicamente de una startup tecnológica de una sola persona.

 
yshrust 2021-04-12

Un typo menor,,

  • Seguimiento de errores

→ usando Sentry para recopilar los errores de la aplicación

=> creo que debería decir “recopilar”

 
xguru 2021-04-12

Gracias. ¡Ya lo corregí~!

 
xguru 2021-04-12

Espero que en nuestro país también aparezcan más desarrolladores independientes o equipos pequeños que ganen dinero con sus propios servicios.

Ojalá que GeekNews crezca como un espacio donde esos servicios puedan darse a conocer y recibir retroalimentación saludable.

 
wellsbabo 2024-08-13

Gracias

 
reedids 2021-04-12

Estoy de acuerdo. Gracias :)

 
e1q88 2021-04-12

👍