Blog // Exirel.me

Apache Proxy + gunicorn + runit + Django

Par Florian Strzelecki - 15:46 - 18.02.2010

Tags : Django, Python, Bonne pratique, gunicorn, Technique

A force d'entendre parler de gunicorn par Benoit Chesneau (sur Twitter et sur IRC) et divers autres djangonautes français qui passent leur temps sur #django-fr, je me suis dis que je devais m'y mettre sérieusement.

Du coup, hier et avant hier, j'ai pris du temps pour l'installer sur ma machine, configurer mon serveur apache, adapter des petites choses...

En tout cas, ça marche du tonnerre, et mes sites en Django tournent désormais sur du apache en proxy + gunicorn !

Poney

Image : Poney - jacme31 (http://www.flickr.com/photos/jacme31/) - Creative Common by-sa

Comme on dit, ça roxx du poney !

Étape 1 : suivre un tutoriel

Je suis un fainéant, et, à ce titre, j'ai tout de suite cherché un tutoriel simple et pratique pour comprendre comment ça marche tout ça.

Ayant Mathieu Agopian sur Twitter qui fait sa pub pour son tutoriel, ce ne fut pas bien compliqué.

Du coup, me voilà à suivre les étapes de l'installation, que je vous résume vite fait :

Si on écarte les quelques minutes de lecture du tutoriel, et les possibles erreurs humaines que l'on peut faire, tout ça fonctionna en moins de 30min.

Et si j'étais pas comme les autres ?

En utilisant gunicorn_django comme indiqué, il est possible de tomber sur quelques erreurs, comme celle de ne pas trouver le fichier "settings.py".

Erreur normale si on a fait de ses settings un module (avec un fichier _init_.py) mais assez surprenant au début. Dans la version que j'utilisais (0.4) gunicorn vérifiait la présence physique du fichier "settings.py".

J'en ai parlé à Benoit sur IRC, qui, après m'avoir vaguement expliqué que ça ne se faisait pas trop (voir l'étape 3), m'indique que c'est corrigé dans le trunk du projet.

Effectivement, dans la minute où je lui en parle, il fait les modifications et les pousse sur le repository du projet. Niveau réactivité, ce qui est quand même très agréable.

J'ai donc installé gunicorn à partir de la dernière version du trunk, grâce à un simple :

$ cd gunicorn
$ python setup.py install

J'ai connu plus difficile. Remember EzPublish...

Étape 2 : automatiser et organiser

Content de moi et de ma petite victoire sur l'inconnu, il me restait encore une chose à faire sur ma machine : rendre le processus automatique et administrable.

Bref, le rendre plus pratique pour un serveur en production.

C'est là que, ô miracle, Mathieu s'étant fendu d'un second article sur gunicorn, j'ai juste eu à suivre son tutoriel sur gunicorn avec runit.

Que j'ai suivi, évidement. Tout c'est bien déroulé, sauf un petit détail :

"Un simple lien symbolique, et dans les secondes qui suivent le script sera lancé."

Petit couac, puisque sur ma machine (Ubuntu 8.04), ce n'était pas le cas. Qu'à cela ne tienne ! Un reboot plus tard et tout allait bien. Sur une autre Ubuntu (9.04 cette fois) cela c'est cependant passé comme indiqué dans le tutoriel.

Il a aussi tenu compte de ma remarque sur une petite précision : j'avais oublié de donner les droits d'exécutions à mon fichier "run", qui du coup ne fonctionnait pas très bien (logique).

Bref, le tout a très bien fonctionné sans aucun soucis pour moi, et j'ai donc pu aller voir du côté de l'étape 3.

Étape 3 : réorganiser mes projets django

Ce n'est pas une étape obligatoire pour faire fonctionner gunicorn ou runit, mais après une discussion avec les djangonautes, j'ai décidé de changer un peu l'organisation de mes projets.

Avant

Avant, j'utilisais le mod_wsgi d'Apache. Du coup, j'indiquais à chaque script wsgi les bons settings à utiliser.

J'avais un seul "projet" mais plusieurs settings.py, et plusieurs urls.py. Pour les organiser - Django is Python! - j'ai transformer ces fichiers comme ceci :

J'ai suivi le même principe avec les urls.py. Cette méthode a l'avantage d'organiser plusieurs projets dans un seul, vu qu'ils partagent une grande partie des Settings, et à peu près toutes les mêmes applications.

Sauf que c'était une fausse bonne idée.

Maintenant

Maintenant, j'utilise gunicorn, et même si je peux lui indiquer quel fichier de settings utiliser, il y a d'autres inconvénients qui sont apparus.

Comme par exemple, devoir gérer plusieurs manage.py. Ou bien quelques petits soucis lors de mise en production...

Bref, j'ai changé tout ça pour cette organisation :

Étape 4 : mise en production

Pas le plus simple, mais pas vraiment le plus compliqué :

Ça aurait du fonctionner tout de suite, mais j'ai commis quelques petites erreurs.

Configuration : de la dev à la prod

Vu que c'est très amateur tout ça, je n'ai pas de dev / preprod / prod. J'ai juste la dev, puis la prod directement. En même temps, je n'ai qu'un seul serveur, des moyens limités, et mes sites ne sont pas à fort trafic.

Bref, des moyens limités et des risques faibles.

Du coup, j'avais bêtement oublié de remplacer quelques configurations propre à mon environnement de développement (comme des chemins d'accès) et des broutilles.

A noter que, lorsque j'ai voulu lancer les services gunicorn avec runit et que j'ai eu des erreurs, mon serveur s'est pris une méchante montée en charge à cause des processus gunicorn.

J'ai donc stoppé les services, et réparé mes erreurs. Et je tiens bien à préciser que c'était les miennes, pas celles de gunicorn.

Un jour, j'automatiserais mon processus de mise en production tiens...

Un port différent par service

Au début, pour chaque projet j'utilisais une url différente : domain.me:8080, another.domain.me:8080, etc... sur le même port.

Erreur ! Il faut utiliser un port différent par service gunicorn utilisé. Au début c'est un peu surprenant, mais ça ne pose finalement pas vraiment de soucis.

J'ai juste eu à modifier les ports (8081, 8082, 8083 et 8084) pour que tout rentre dans l'ordre.

Et c'est tout.

Et oui, mis à part ces deux erreurs purement humaines (ma faute, ma très grande faute), tout c'est très bien passé. D'ailleurs, vous pouvez lire cet article grâce à gunicorn, django, apache en proxy et runit.

Vous aussi, utilisez gunicorn pour votre django !

Que dire ? Tout c'est bien passé sauf quand je me suis trompé ?

Sincèrement, une fois que vous avez installé runit, et lancé votre premier gunicorn... les suivants ne demandent pas plus de 10-15min d'installation, configuration, et mise en production.

Un vrai plaisir !

Ressources utiles :

Et merci à @benoitc et à @magopian pour leur aide, leur réactivité, et leurs réponses !