I was wondering what the correct approach to deploying a containerized Django app using gunicorn & celery was.
Specifically, each of these processes has a built-in way of scaling vertically, using workers for gunicorn and concurrency for celery. And then there is the Kubernetes approach to scaling using replicas
There is also this notion of setting workers equal to some function of the CPUs. Gunicorn recommends
2-4 workers per core
However, I am confused what this translates to on K8s where CPU is a divisible shared resource - unless I use resoureceQuotas.
I want to understand what the Best Practice is. There are three options I can think of:
- Have single workers for gunicorn and a concurrency of 1 for celery, and scale them using the replicas? (horizontal scaling)
- Have gunicorn & celery run in a single replica deployment with internal scaling (vertical scaling). This would mean setting fairly high values of workers & concurrency respectively.
- A mixed approach between 1 and 2, where we run gunicorn and celery with a small value for workers & concurrency, (say 2), and then use K8s Deployment replicas to scale horizontally.
There are some questions on SO around this, but none offer an in-depth/thoughtful answer. Would appreciate if someone can share their experience.
Note: We use the default worker_class sync for Gunicorn