web-dev-qa-db-fra.com

Déployer Django avec gunicorn et nginx

Il s'agit d'une question générale, mais j'aimerais obtenir une réponse canonique. J'ai essayé de déployer un site en utilisant gunicorn et nginx in Django. Après avoir lu des tonnes de tutoriels, j'ai réussi, mais je ne peux pas être sûr que les étapes que j'ai suivies sont assez bonnes pour exécuter un site sans problème ou peut-être qu'il existe de meilleures façons de le faire. Cette incertitude est agaçante.

C'est pourquoi je recherche une réponse très détaillée et bien expliquée pour les débutants. Je ne veux pas trop expliquer ce que je sais et ce que je ne sais pas, car cela pourrait fausser un peu les réponses et d'autres personnes pourraient bénéficier dans une moindre mesure de vos réponses. Cependant, certaines choses que j'aimerais voir mentionnées sont:

  • Quelle "configuration" avez-vous vu fonctionner le mieux? J'ai utilisé virtualenv et déplacé mon projet Django à l'intérieur de cet environnement, mais j'ai vu une autre configuration où il y a un dossier pour les environnements virtuels et d'autres pour les projets.

  • Comment puis-je configurer les choses d'une manière qui permet à plusieurs sites d'être hébergés sur un seul serveur?

  • Pourquoi certaines personnes suggèrent d'utiliser gunicorn_Django -b 0.0.0.0:8000 et d'autres suggèrent gunicorn_Django -b 127.0.0.1:8000? J'ai testé ce dernier dans une instance Amazon EC2 mais cela n'a pas fonctionné tandis que le premier fonctionnait sans problème.

  • Quelle est la logique derrière le fichier de configuration de nginx? Il y a tellement de tutoriels utilisant des fichiers de configuration radicalement différents que je ne sais pas lequel est le meilleur. Par exemple, certaines personnes utilisent alias /path/to/static/folder et d'autres root /path/to/static/folder. Vous pouvez peut-être partager votre fichier de configuration préféré.

  • Pourquoi créons-nous un lien symbolique entre site-available et sites-enabled dans /etc/nginx?

  • Certaines bonnes pratiques sont toujours les bienvenues :-)

Merci

79
Robert Smith

Quelle "configuration" avez-vous vu fonctionner le mieux? J'ai utilisé virtualenv et déplacé mon projet Django à l'intérieur de cet environnement, mais j'ai vu une autre configuration où il y a un dossier pour les environnements virtuels et d'autres pour les projets.

virtualenv est un moyen d'isoler les environnements Python; en tant que tels, il n'a pas un grand rôle à jouer dans déploiement - cependant pendant développement et testing c'est une exigence sinon fortement recommandé.

La valeur que vous obtiendriez de virtualenv est qu'il vous permet de vous assurer que les versions correctes des bibliothèques sont installées pour l'application. Peu importe où vous collez l'environnement virtuel lui-même. Assurez-vous simplement de ne pas l'inclure dans le système de gestion des versions du code source.

La disposition du système de fichiers n'est pas critique. Vous verrez de nombreux articles vantant les vertus des dispositions de répertoires et même des projets squelettes que vous pouvez cloner comme point de départ. Je pense que c'est plus une préférence personnelle qu'une exigence difficile. Bien sûr, c'est agréable d'avoir; mais à moins que vous sachez pourquoi, cela n'ajoute aucune valeur à votre processus de déploiement - alors ne le faites pas car certains blogs le recommandent à moins que cela ait du sens pour votre scénario. Par exemple - pas besoin de créer un setup.py fichier si vous ne disposez pas d'un serveur PyPi privé faisant partie de votre flux de travail de déploiement.

Comment puis-je configurer les choses d'une manière qui permet à plusieurs sites d'être hébergés sur un seul serveur?

Il y a deux choses dont vous avez besoin pour effectuer plusieurs configurations de site:

  1. Un serveur qui écoute sur l'IP publique sur le port 80 et/ou le port 443 si vous avez SSL.
  2. Un tas de "processus" qui exécutent le véritable code source Django.

Les gens utilisent nginx pour # 1 car c'est un proxy très rapide et il ne vient pas avec la surcharge d'un serveur complet comme Apache. Vous êtes libre d'utiliser Apache si vous en êtes à l'aise. Il n'est pas nécessaire que "pour les sites multiples, utilisez nginx"; vous avez juste besoin d'un service qui écoute sur ce port, sait comment rediriger (proxy) vers vos processus exécutant le code réel Django.

Pour le numéro 2, il existe plusieurs façons de démarrer ces processus. gevent/uwsgi sont les plus populaires. La seule chose à retenir ici est n'utilisez pas runserver en production.

Ce sont les exigences minimales absolues. Généralement, les gens ajoutent une sorte de gestionnaire de processus pour contrôler tous les "serveurs Django" (# 2) en cours d'exécution. Ici, vous verrez upstart et supervisor mentionnés. Je préfère le superviseur car il n'a pas besoin de prendre en charge l'ensemble du système (contrairement à upstart). Cependant, encore une fois - ce n'est pas une exigence difficile. Vous pouvez parfaitement exécuter un tas de sessions screen et les détacher. L'inconvénient est que si votre serveur redémarre, vous devrez relancer les sessions d'écran.

Personnellement, je recommanderais:

  1. Nginx pour # 1
  2. Faites votre choix entre uwsgi et gunicorn - j'utilise uwsgi.
  3. superviseur pour gérer les processus backend.
  4. Comptes système individuels (utilisateurs) pour chaque application que vous hébergez.

La raison pour laquelle je recommande # 4 est d'isoler les autorisations; encore une fois, pas une exigence.

Pourquoi certaines personnes suggèrent d'utiliser gunicorn_Django -b 0.0.0.0:8000 et d'autres suggèrent gunicorn_Django -b 127.0.0.1:8000? J'ai testé ce dernier dans une instance Amazon EC2 mais cela n'a pas fonctionné tandis que le premier fonctionnait sans problème.

0.0.0.0 signifie "toutes les adresses IP" - c'est une méta-adresse (c'est-à-dire une adresse d'espace réservé). 127.0.0.1 est une adresse réservée qui pointe toujours vers la machine locale. C'est pourquoi son appelé "localhost". Il n'est accessible qu'aux processus exécutés sur le même système.

En règle générale, le serveur frontal (n ° 1 dans la liste ci-dessus) écoute sur l'adresse IP publique. Vous devez lier explicitement le serveur à une adresse IP.

Cependant, si pour une raison quelconque vous êtes sur DHCP ou si vous ne savez pas quelle sera l'adresse IP (par exemple, c'est un système nouvellement provisionné), vous pouvez dire à nginx/Apache/tout autre processus de se lier à 0.0.0.0. Il doit s'agir d'une mesure temporaire de l'écart .

Pour les serveurs de production, vous aurez une adresse IP statique. Si vous avez une IP dynamique (DHCP), vous pouvez laisser dans 0.0.0.0. Il est cependant très rare que vous disposiez de DHCP pour vos machines de production.

Lier gunicorn/uwsgi à cette adresse est non recommandé en production. Si vous liez votre processus backend (gunicorn/uwsgi) à 0.0.0.0, il peut devenir accessible "directement", en contournant votre proxy frontal (nginx/Apache/etc); quelqu'un pourrait simplement demander http://your.public.ip.address:9000/ et accédez directement à votre application surtout si votre serveur frontal (nginx) et votre processus backend (Django/uwsgi/gevent) fonctionnent sur la même machine.

Vous êtes cependant libre de le faire si vous ne voulez pas avoir à gérer un serveur proxy frontal.

Quelle est la logique derrière le fichier de configuration de nginx? Il y a tellement de tutoriels utilisant des fichiers de configuration radicalement différents que je ne sais pas lequel est le meilleur. Par exemple, certaines personnes utilisent "alias/chemin/vers/statique/dossier" et d'autres "racine/chemin/vers/statique/dossier". Vous pouvez peut-être partager votre fichier de configuration préféré.

La première chose que vous devez savoir sur nginx est qu'il n'est pas un serveur Web comme Apache ou IIS. C'est un proxy. Vous verrez donc différents termes tels que "en amont"/"en aval" et plusieurs "serveurs" définis. Prenez un peu de temps et parcourez d'abord le manuel nginx.

Il existe de nombreuses façons de configurer nginx; mais voici une réponse à votre question sur alias vs root. root est une directive explicite qui lie la racine du document (le "répertoire personnel") de nginx. Il s'agit du répertoire qu'il examinera lorsque vous ferez une demande sans chemin d'accès comme http://www.example.com/

alias signifie "mapper un nom à un répertoire". Répertoires aliasés peut-être pas un sous-répertoire de la racine du document.

Pourquoi créons-nous un lien symbolique entre les sites disponibles et les sites activés dans/etc/nginx?

C'est quelque chose d'unique à Debian (et aux systèmes de type Debian comme Ubuntu). sites-available répertorie les fichiers de configuration de tous les hôtes/sites virtuels du système. Un lien symbolique de sites-enabled à sites-available "active" ce site ou l'hôte virtuel. C'est un moyen de séparer les fichiers de configuration et d'activer/désactiver facilement les hôtes.

105
Burhan Khalid

Je ne suis pas un gourou du déploiement mais je partagerai certaines de mes pratiques pour déployer Django avec gevent (devrait être similaire à gunicorn cependant).

virtualenv est idéal pour des raisons que je n'entrerai pas. J'ai cependant trouvé virtualenv-wrapper ( docs ) très utile, surtout lorsque vous travaillez sur de nombreux projets car il permet de basculer facilement entre les différents virtualenvs. Cela ne s'applique pas vraiment à l'environnement de déploiement, mais lorsque j'ai besoin de dépanner le serveur à l'aide de SSH, j'ai trouvé cela très utile. Un autre avantage de son utilisation est qu'il gère le répertoire virtualenv, donc moins de travail manuel pour vous. Virtualenvs est censé être jetable de sorte que si vous avez des problèmes de version ou tout autre problème d'installation, vous pouvez simplement vider l'env et en créer un nouveau. Par conséquent, il est recommandé de ne pas inclure le code de votre projet dans virtualenv. Il doit être conservé séparément.

Quant à la configuration de plusieurs sites, virtualenv est à peu près la réponse. Vous devez avoir un virutalenv distinct pour chaque projet. Rien que cela peut résoudre de nombreux problèmes. Ensuite, lorsque vous déployez, un processus différent Python exécutera différents sites, ce qui évite tout conflit possible entre les déploiements. Un outil que j'ai particulièrement trouvé très utile pour gérer plusieurs sites sur le même serveur est supervisor ( docs ). Il fournit une interface simple pour démarrer, arrêter et redémarrer différentes instances Django. Il est également capable de redémarrer automatiquement un processus lorsqu'il échoue ou lorsque l'ordinateur démarre. Ainsi, par exemple, si une exception est déclenchée et que rien ne la rattrape, le site Web entier peut tomber en panne. Le superviseur le détectera et redémarrera l'instance Django Voici un exemple de configuration de programme de superviseur (un seul processus):

[program:foo]
command=/path/toviertualenv/bin/python deploy.py
directory=/path/where/deploy.py/is/located/
autostart=true
autorestart=true
redirect_stderr=True
user=www

Pour Nginx, je sais que cela peut être écrasant au début. J'ai trouvé Nginx livre très utile. Il explique toutes les principales directives nginx.

Dans mon installation nginx, j'ai trouvé que la meilleure pratique consiste à configurer uniquement les configurations de base dans le nginx.conf fichier et puis j'ai un dossier séparé sites où je garde les configs nginx pour chacun des sites que j'héberge. Ensuite, j'inclus simplement tous les fichiers de ce dossier dans le fichier de configuration principal. J'utilise la directive include sites/+*.conf;. De cette façon, il inclut uniquement les fichiers commençant par + symbole dans le dossier sites. De cette façon, juste par le nom de fichier, je peux contrôler les fichiers de configuration à charger. Donc, si je souhaite désactiver un certain site, il me suffit de renommer le fichier de configuration et de redémarrer nginx. Je ne sais pas vraiment ce que vous vouliez dire par "lien symbolique entre les sites disponibles et les sites activés dans/etc/nginx" dans votre question car il s'agit de dossiers nommés Apache, mais ils accomplissent une tâche similaire à la directive include.

Quant aux directives root et alias, elles sont à peu près les mêmes sauf là où leur racine est calculée. Dans alias, tout ce qui se trouve dans le location est supprimé, tandis que dans root non. Image que vous avez la configuration nginx suivante:

location /static {
    alias /some/path/;
}
location /static2 {
    root /some/other/path/;
}

Si l'utilisateur accède à ces URL, nginx essaiera de rechercher les fichiers aux endroits suivants sur le système:

/static/hello/world.pdf => /some/path/hello/world.pdf
/static2/hello/world.pdf => /some/other/path/static2/hello/world.pdf

Il s'agit d'une simple configuration pour le site nginx:

server {
    server_name .foodomain.com;
    listen 80;

    access_log logs/foodomain.log;

    gzip                on;
    gzip_http_version   1.0;
    gzip_comp_level     2;
    gzip_proxied        any;
    gzip_min_length     1100;
    gzip_buffers        16 8k;
    gzip_types          text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    # Some version of IE 6 don't handle compression well on some mime-types, so just disable for them
    gzip_disable "MSIE [1-6].(?!.*SV1)";

    # Set a vary header so downstream proxies don't send cached gzipped content to IE6
    gzip_vary on;

    location / {
        proxy_read_timeout      30s;
        proxy_pass              http://localhost:8000;
        proxy_set_header        Host                 $Host;
        proxy_set_header        User-Agent           $http_user_agent;
        proxy_set_header        X-Real-IP            $remote_addr;
    }

    location /media {
        alias   /path/to/media/;
        expires 1y;
    }

    location /static {
        autoindex on;
        expires   1y;
        alias     /path/to/static/;
    }

     location /favicon.ico {
        alias /path/to/favicon.ico;
    }
}

J'espère que cela vous aide un peu.

11
miki725

Vérifiez ceci pour la configuration minimale de gunicorn et nginx requise pour un projet Django. http://agiliq.com/blog/2013/08/minimal-nginx-and-gunicorn-configuration -pour-djang /

2
Akshar Raaj

Eh bien, en ce qui concerne les meilleures pratiques que vous avez posées dans votre question, je ne peux pas m'empêcher de partager un outil qui a fait des merveilles pour moi, littéralement! J'ai moi-même l'habitude de me perdre dans plusieurs fichiers de configuration de gunicorn, nginx, supervisorD pour plusieurs sites! Mais j'avais envie d'automatiser en quelque sorte l'ensemble du processus afin de pouvoir apporter des modifications à mon application/site et le déployer instantanément. Son nom est Django-fagungis. Vous pouvez trouver les détails de mon expérience avec Django Deployment automation here . Je viens de configurer une fois fabfile.py (Django-fagungis utilise le tissu pour automatiser l'ensemble du processus et crée un virtualenv dans votre serveur distant qui est TRÈS pratique pour gérer les dépendances de plusieurs sites hébergés sur un même serveur. Il utilise nginx, gunicorn et supervisorD pour gérer le Django déploiement de projet/site) et Django-fagungis clone mon dernier projet de bitbucket (que j'utilise pour subversioning) et le déploie sur mon serveur distant et je dois juste entrer trois commandes sur Shell de ma machine locale et ça !! Pour moi, cela s'est avéré être la meilleure pratique sans tracas pour Django.

2
Ali Raza Bhayani