50 điểm bởi xguru 2021-04-12 | 11 bình luận | Chia sẻ qua WhatsApp
  • Giải thích kiến trúc của một lập trình viên solo vận hành SaaS chậm rãi, không căng thẳng

  • Đã xây dựng hạ tầng để vận hành đồng thời nhiều dự án

  • Giải thích dựa trên PanelBear, một SaaS mà tác giả gần đây tạo ra
    → Bắt đầu với SQLite + Django trên VPS nhỏ nhất
    → Sau 6 tháng lặp lại cải tiến, chuyển sang Django monolith + Postgres + ClickHouse (phân tích) + Redis (cache) + Celery (tác vụ theo lịch) trên EKS
    → Hầu hết đều được tự động hóa: autoscaling, ingress, chứng chỉ TLS, failover, logging, monitoring, v.v.
    → Vì dùng cấu hình này cho nhiều dự án nên có thể giảm chi phí và bắt đầu thử nghiệm rất dễ dàng
    → Gần như không tốn thời gian quản lý hạ tầng (0~2 giờ mỗi tháng)
    → Phần lớn thời gian được dùng cho phát triển tính năng, hỗ trợ khách hàng và tăng trưởng kinh doanh

  • Dùng Kubernetes trên AWS, nhưng không nhất thiết phải như vậy. Tuy nhiên, tác giả đã quen nên cho rằng có thể vận hành ổn định.
    → Đã học được điều này trong nhiều năm sử dụng công cụ cùng với một đội ngũ kiên nhẫn (cùng chịu đựng và chặn lỗi)
    → "Kubernetes làm những thứ đơn giản trở nên phức tạp, nhưng cũng có thể làm những thứ phức tạp trở nên đơn giản"

  • DNS, SSL và cân bằng tải tự động
    → Toàn bộ lưu lượng được chuyển từ CloudFlare Proxy sang AWS L4 NLB (Network Load Balancer)
    → Khi có request đi vào, LB sẽ chuyển tiếp tới một trong các node của cụm k8s
    → Các node này nằm trong private subnet trải rộng trên nhiều AZ (Availability Zone)
    → ingress-nginx (cụm Nginx) đảm nhiệm việc để k8s xác định service cần xử lý request
    → nginx áp dụng các quy tắc rate limiting và traffic shaping trước khi chuyển tiếp lưu lượng
    → Với PanelBear, container ứng dụng là Django được phục vụ bằng Uvicorn
    → Có một vài file cấu hình giữa Terraform/K8s và phần lớn dự án dùng chung chúng
    → Khi triển khai dự án mới, chỉ cần khoảng 20 dòng cấu hình ingress

  • Rollout và rollback tự động
    → Mỗi lần push lên nhánh master, pipeline CI sẽ chạy bằng GitHub Actions
    → Kiểm tra codebase, dựng môi trường hoàn chỉnh bằng Docker-Compose để chạy kiểm thử E-to-E
    → Nếu vượt qua kiểm tra, sẽ build image Docker mới và push lên ECR (Docker Registry của AWS)
    → Thành phần flux trong cụm k8s ( https://fluxcd.io/ ) sẽ tự đồng bộ image trong cluster
    → Flux tự động thực hiện incremental rollout

  • Horizontal Autoscaling
    → Autoscaling dựa trên mức sử dụng CPU/bộ nhớ
    → Nếu có quá nhiều Pod trên mỗi node của cluster, hệ thống sẽ tự tạo thêm server để tăng dung lượng cụm và giảm tải. Khi không có việc thì thu nhỏ lại
    → Với Panelbear, số bản sao API Pod được tự động điều chỉnh từ 2 đến 8

  • Cache static asset bằng CDN
    → Cấu hình CloudFlare cho DNS để xử lý mọi request và cả chống DDoS
    → Dùng Whitenoise ( https://github.com/evansd/whitenoise ) để phục vụ file static nên không cần upload file lên NGinx/Cloudfront/S3
    → Một số website tĩnh như landing page của Panelbear dùng NextJS

  • Cache dữ liệu ứng dụng
    → Ở một số phần, dùng cache LRU in-memory do Python cung cấp
    → Phần lớn endpoint dùng Redis trong cluster

  • Rate limiting theo từng endpoint
    → nginx-ingress có rate limit toàn cục, nhưng đôi khi cần giới hạn riêng theo endpoint/method
    → Có thể khai báo giới hạn theo từng Django view bằng thư viện Django Ratelimit
    → Dùng Redis làm backend để theo dõi client gọi tới từng endpoint (băm dựa trên khóa client thay vì IP)

  • Quản trị ứng dụng
    → Admin Panel của Django mặc định hỗ trợ xem và chỉnh sửa dữ liệu
    → Đã thêm các chức năng như chặn truy cập tài khoản đáng ngờ / gửi email thông báo / xử lý yêu cầu xóa tài khoản (ban đầu soft delete, sau đó xóa vĩnh viễn trong vòng 72 giờ)

  • Chạy tác vụ theo lịch
    → Trong SaaS có nhiều tác vụ theo lịch: báo cáo hằng ngày cho khách hàng, tính thống kê sử dụng mỗi 15 phút, email chỉ số gửi cho nhân viên, v.v.
    → Đang chạy một vài Celery worker và Celery beat scheduler trong cluster. Redis được dùng làm task queue
    → Dùng HealthChecks.io để nhận thông báo qua SMS/Slack/Email khi tác vụ theo lịch không chạy đúng

  • Cấu hình ứng dụng
    → Mọi cấu hình đều dùng biến môi trường. Cách này cũ nhưng dễ perenos và được hỗ trợ tốt

  • Giữ bí mật an toàn
    → Dùng kubeseal. Secret được mã hóa bằng mật mã bất đối xứng. Chỉ cluster có quyền truy cập khóa giải mã mới có thể giải mã
    → Dùng khóa mã hóa của AWS KMS để bảo vệ các Secret trong cluster

  • Dữ liệu quan hệ: Postgres
    → Để thử nghiệm, chạy container Postgres thuần trong cluster và thực hiện backup hằng ngày lên S3 bằng K8s Cronjob
    → Khi dự án phát triển, cơ sở dữ liệu sẽ được chuyển từ trong cluster sang RDS để AWS xử lý backup mã hóa và cập nhật bảo mật
    → Để tăng cường bảo mật, DB trên AWS chỉ có thể truy cập từ Private Network

  • Dữ liệu dạng cột: ClickHouse
    → Dùng ClickHouse để lưu trữ hiệu quả và truy vấn thời gian thực dữ liệu phân tích của PanelBear
    → Đây là cơ sở dữ liệu columnar rất xuất sắc, cực nhanh và nếu thiết kế cấu trúc tốt thì cho tỷ lệ nén cao (giảm lưu trữ = tăng lợi nhuận)
    → Tự host instance ClickHouse trong cụm K8s
    → Tạo CronJob để định kỳ backup dữ liệu columnar lên S3
    → Có một số script để backup thủ công và khôi phục dữ liệu từ S3 khi có sự cố

  • Service discovery dựa trên DNS
    → K8s tự động quản lý các bản ghi DNS trong cluster để định tuyến lưu lượng tới service tương ứng
    → Tự đồng bộ bản ghi DNS để luôn kết nối tới các pod khỏe mạnh ngay cả khi autoscaling

  • Hạ tầng được quản lý bằng version control
    → Quản lý Docker, Terraform, K8s manifest trong một kho duy nhất (Infra Mono-Repo)
    → Có thể tạo và xóa hạ tầng bằng lệnh đơn giản, đồng thời tái lập nhờ version control

  • Terraform cho Cloud Resource
    → Phần lớn tài nguyên cloud được quản lý bằng Terraform
    → Nhờ đó có thể tài liệu hóa và theo dõi tài nguyên hạ tầng cũng như cấu hình

  • K8s manifest cho triển khai ứng dụng
    → Các K8s Manifest được viết trong file YAML của infra mono repo
    → Chia thành hai thư mục: clusterapps
    cluster chứa cấu hình liên quan tới dịch vụ toàn cụm như nginx-ingress, secret đã mã hóa, Prometheus scraper
    apps lưu thông tin theo namespace, mỗi dự án một namespace

  • Đăng ký và thanh toán
    → Dùng Stripe Checkout để xử lý toàn bộ thanh toán
    → Không cần can thiệp vào thông tin thanh toán nên có thể tập trung vào sản phẩm
    → Chỉ cần tạo session cho khách hàng, redirect sang trang của Stripe rồi nhận kết quả qua WebHook là xong

  • Logging
    → Không dùng logging agent; chỉ cần ghi log ra stdout thì k8s sẽ tự thu thập log và cả rotate
    → Có thể gửi sang Elasticsearch/Kibana qua FluentBit, nhưng hiện chưa làm để giữ mọi thứ đơn giản
    → Để kiểm tra log thì dùng công cụ CLI stern

  • Giám sát và cảnh báo
    → Ban đầu tự host Prometheus / Grafana, nhưng khi cluster gặp sự cố thì hệ thống cảnh báo cũng dừng theo nên bất tiện
    → Vì vậy đã chuyển sang New Relic
    → Mọi service đều có Prometheus Integration để tự thu thập metric và gửi sang Datadog, New Relic, Grafana Cloud, v.v., nên khi chuyển sang New Relic chỉ cần dùng image Docker Prometheus do họ cung cấp

  • Theo dõi lỗi
    → Dùng Sentry để thu thập lỗi ứng dụng
    → Dùng kênh Slack #alerts để tập trung mọi cảnh báo như downtime, lỗi cron job, cảnh báo bảo mật, suy giảm hiệu năng, exception ứng dụng

  • Profiling và những thứ hữu ích khác
    → Khi cần phân tích sâu thì dùng các công cụ như cProfile hoặc snakeviz
    → Trên máy local thì dùng Django Debug Toolbar

11 bình luận

 
wellsbabo 2024-08-13

Cảm ơn bạn

 
admin2 2021-04-13

Chênh lệch về tính năng giữa Sentry và New Relic có lớn không?

Tôi từng nghĩ chúng có chức năng tương tự nhau, nhưng vẫn chưa có dịp dùng thử.

 
kbumsik 2021-04-13

Ồ, công ty chúng tôi cũng đang cân nhắc áp dụng k8s, đây quả là một bài viết khá hay ngay cả khi không phải là startup công nghệ một người.

 
fortune 2021-04-12

Cảm ơn bạn vì bài viết hay. Tôi đã nhận được nhiều cảm hứng.

 
khris 2021-04-12

Ngay cả khi không nhất thiết là startup công nghệ một người, đây vẫn là một bài viết hay.

 
yshrust 2021-04-12

Có một lỗi gõ nhỏ,,

  • Theo dõi lỗi

→ Dùng Sentry để thu thập lỗi ứng dụng

=> Có lẽ là "thu thập" ạ

 
xguru 2021-04-12

Cảm ơn. Tôi đã sửa rồi~!

 
xguru 2021-04-12

Tôi mong ở trong nước cũng sẽ có thêm nhiều lập trình viên solo hoặc các đội ngũ nhỏ kiếm tiền từ chính dịch vụ của mình.

Tôi hy vọng GeekNews ở đây sẽ phát triển thành một nơi để những dịch vụ như vậy giới thiệu bản thân và nhận được những phản hồi lành mạnh.

 
wellsbabo 2024-08-13

Cảm ơn bạn

 
reedids 2021-04-12

Tôi đồng ý. Cảm ơn :)

 
e1q88 2021-04-12

👍