Dockerfile for Django ===================== Add one Dockerfile for the Django project, replacing ``core.wsgi`` if needed and ``{{ cookiecutter.project_slug }}``, and another for static files. .. warning:: When deploying Docker, remember to set the number of workers using a environment variable like ``GUNICORN_CMD_ARGS="--workers 3"``. .. literalinclude:: ../../cookiecutter-django/{{cookiecutter.project_slug}}/Dockerfile_django :language: docker :caption: Dockerfile_django .. literalinclude:: ../../cookiecutter-django/{{cookiecutter.project_slug}}/Dockerfile_static :language: docker :caption: Dockerfile_static .. _gunicorn: Gunicorn -------- Worker class ~~~~~~~~~~~~ Gunicorn describes use cases where asynchronous workers `are preferred `__. In particular, check whether the application makes long blocking calls and is therefore `I/O bound `__. .. note:: If Gunicorn is deployed `behind a proxy server `__, like Apache, then it isn't "serving requests directly to the internet." That said, check whether other applications that send requests behind the proxy server are likely to DOS the application (if it were to use a synchronous worker). If not, then the synchronous `worker classes `__ (``sync`` and ``gthreads``) are preferred. .. note:: The ``gthreads`` worker class is synchronous, `despite `__ appearing under `AsyncIO Workers `__. When using the ``sync`` worker class, the `\--timeout option `__ `behaves like a request timeout `__, because the worker can only *either* handle the request or handle the heartbeat. (Gunicorn otherwise has no option like uWSGI's `harakiri `__ for `request timeouts `__.) When using the ``gthreads`` worker class, a main thread `handles the heartbeat `__. As such, we use the ``gthreads`` worker class, to not have to worry about heartbeat timeouts. .. note:: Setting the `\--threads `__ option to more than ``1`` automatically sets the worker class to ``gthreads``. Number of threads ~~~~~~~~~~~~~~~~~ Ensure your code is thread safe. Notably, `psycopg2 cursors are not thread safe `__, though this isn't a concern for typical usage of `Django `__. `When using threads `__, the application is loaded by the worker and some memory is shared between its threads (thus consuming less memory than additional workers would). Unless the server becomes memory-bound, use a minimum number of threads (``2``) and instead increase the number of workers, to lower the risk around thread safety. .. note:: If the application is CPU-bound, additional threads don't help, due to `Python's GIL `__. Instead, add additional workers (up to twice the number of cores). Concurrency ~~~~~~~~~~~ `cores * 2 + 1 `__ is the recommended number of `workers * threads `__. However, multiple applications on the same server need to share the same cores – plus, the server might not be dedicated to Gunicorn. At build time, the mix of applications and number of cores are unknown. As such, we omit the ``--workers`` option (`highest level of precedence `__), and set a `WEB_CONCURRENCY `__ environment variable (lowest level). Docker Compose can then set a `GUNICORN_CMD_ARGS="\--workers 3" `__ environment variable to override the number of workers. The template sets ``WEB_CONCURRENCY=2`` and ``--threads 2`` (as described in the previous section), such that the total concurrency is 4 – one more than ``cores * 2 + 1`` for a single core. Signals ~~~~~~~ The shell form, ``CMD command param1``, `runs the command as a subcommand `__ of ``/bin/sh -c``, which `doesn't pass signals `__. For Gunicorn to receive the ``SIGTERM`` signal and stop gracefully, the exec form, ``CMD ["command", "param1"]``, is used. Reference: `Signal Handling `__ Other options ~~~~~~~~~~~~~ ``--bind 0.0.0.0:8000`` uses Docker's `default bind address for containers `__ and Gunicorn's `default port `__. ``--worker-tmp-dir /dev/shm`` avoids a `potential issue `__. ``--name PROJECTNAME`` helps to `distinguish processes `__ of different applications on the same server. Additional options can be configured from Docker Compose using the `GUNICORN_CMD_ARGS `__ environment variable, though command-line arguments `take precedence `__. Troubleshooting ~~~~~~~~~~~~~~~ Idle workers are regularly killed. As such, it can be hard to debug what happened. See this `FAQ question `__ for some guidance.