Archive

Archives pour la catégorie ‘mod_wsgi’

lancer gunicorn avec runit

10/02/2010 admin Comments off

ATTENTION votre serviteur a fait le test pour vous sur une ubuntu: après avoir installé runit et runit-run, le système ne démarre plus. Pour suivre les étapes de ce billet, il ne faut pas installer runit-run, qui ne doit être installé que lorsque l’on souhaite remplacer totalement le système d’initialisation (et cela demande plus de configuration qu’une simple installation du paquet).

Pour les malheureux qui ont fait les frais de la première version de ce billet (demandant d’installer runit-run), je ne peux que m’excuser platement, et vous fournir la méthode “au secours rescue moi!”: récuperer une installation avec un cd ubuntu. Une fois chrooté sur la partition root, il vous restera à désinstaller le paquet fautif et redémarrer:
        $ aptitude purge runit-run

Edité le 2010/02/10 à 20:58

Pour faire suite au précédent billet gunicorn: un server wsgi ultra simple à utiliser et configurer, voici une recette rapide pour lancer automatiquement (et monitorer) gunicorn avec runit.

Pourquoi runit et pas sysvinit, inittab, upstart, …

Je vous laisse consulter la page benefits sur le site officiel pour vous faire une idée. Pour les personnes ne parlant pas anglais, voici un bref résumé:

  1. Un répertoire par service, contenant un script run
  2. Un environnement d’exécution propre et prédictible pour chaque processus
  3. Service de logging (optionnel) qui sera lancé en même temps que le processus, et en couvrira toute la durée de vie (redémarrages compris!)
  4. Très peu encombrant, efficace… et peut complètement remplacer le système d’initialisation de votre linux

Utiliser runit avec le système d’initialisation actuel

Pour nous faciliter la vie, et ne pas avoir à modifier/importer de nombreux scripts de démarrage pour tous les démons et services déjà installés, nous allons utiliser runit “avec” le système d’initialisation actuel.

Installer runit

$ aptitude install runit

ATTENTION: Si vous installez aussi runit-run, il vous faut absolument configurer votre système (How to replace init), et ce, avant de rebooter (sinon votre système ne démarrera pas, et vous serez contraint à utiliser une méthode de récupération, comme celle présentée en tête de ce billet).

Créer un répertoire pour le service gunicorn et son script de lancement

$ mkdir /etc/sv/gu-monprojet
$ vi /etc/sv/gu-monprojet/run

Et voici le contenu du script run

#!/bin/bash
source /path/to/venv/bin/activate # activer le virtualenv
cd /path/to/django/project
exec gunicorn_django -b localhost:8080 --workers=3

Avec la version de gunicorn utilisée pour l’écriture de cet article, il est nécessaire d’être dans le répertoire du projet django (là ou se situe le fichier settings.py) pour lancer gunicorn_django.

Dans une future version (la modification est dans le trunk à l’heure de l’écriture) il suffira d’indiquer le chemin vers le fichier settings.py comme paramètre à la commande gunicorn_django.

Enfin, ne pas oublier de rajouter les droits d’exécution sur le script qu’on vient de créer:

$ chmod a+x /etc/sv/gu-monprojet

Indiquer à runit qu’il doit lancer le script

Pour celà, un simple lien symbolique, et dans les secondes qui suivent le script sera lancé:

$ ln -s /etc/sv/gu-monprojet /etc/service/

Et c’est tout!

Il suffit maintenant d’en profiter en allant sur http://localhost:8080, en configurant apache pour proxiser les requêtes directement dessus (cf le billet gunicorn: un server wsgi ultra simple à utiliser et configurer), ou encore en utilisant la commande sv pour gérer le service gunicorn:

$ sv status gu-monprojet
$ sv check gu-monprojet
$ sv up gu-monprojet
$ sv down gu-monprojet
$ sv restart gu-monprojet
$ sv hup gu-monprojet
...

gunicorn: un server wsgi ultra simple à utiliser et configurer

09/02/2010 admin Comments off

Deux billets le même jour, c’est fête!

Voici une recette simple pour installer, configurer et utiliser gunicorn avec apache et django.

Installer gunicorn

Pour installer gunicorn dans son environnement virtuel:

$ pip install -E /path/to/venv install gunicorn

Configurer Apache en proxy

Apache servira les fichiers statiques, et “proxisera” toutes les autres requêtes directement à gunicorn qui sera lancé en local sur le port 8080:

<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com

DocumentRoot /path/to/django/project

<Proxy *>
    Order deny,allow
    Allow from all
</Proxy>

# laisser apache servir les fichiers statiques
ProxyPass /robots.txt !
ProxyPass /favicon.ico !
ProxyPass /static/ !

# proxiser toutes les autres requêtes vers gunicorn
ProxyPass / http://localhost:8080/

# robots.txt et favicon.ico sont dans /path/to/django/project/static/
Alias /robots.txt /path/to/django/project/static/robots.txt
Alias /favicon.ico /path/to/django/project/static/favicon.ico

<Directory /path/to/django/project>
    Order deny,allow
    Allow from all
    Options -Indexes
</Directory>
</VirtualHost>

Pour que le tout fonctionne correctement, il faut activer les modules mod_proxy et mod_proxy_html (et en option mod_cache):

$ a2enmod proxy proxy_http cache

Puis de redémarrer le server Apache:

$ /etc/init.d/apache2 restart

Lancer gunicorn

Il suffit de se placer dans le répertoire du projet django (avec le virtualenv activé), puis de taper:

$ gunicorn_django -b localhost:8080 --workers=2

Un ordre d’idée pour le calcul des workers: un de plus que le nombre de CPUs de la machine.

Conclusion

On peut alors se créer un script (a placer dans /etc/init.d) et l’activer pour qu’il se lance automatiquement au démarrage avec la commande update-rc.d (sous Debian), ou utiliser runit (jamais testé, peut-être un futur billet?).

Encore mieux, remplacer Apache par Nginx! (jamais testé non plus, et sûrement un futur billet ;) ).

On peut difficilement faire plus simple!

Django, sqlite et mod_wsgi, attention au piège!

14/03/2009 admin 2 commentaires

Tout d’abord, je tiens à préciser que le problème qui suit n’est pas limité à l’utilisation de django ou de mod_wsgi.

Le contexte

Utilisation de SQLite pour un projet django déployé sur mod_wsgi:

# settings.py
DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = '/opt/mysite/mysite.db'

Et voici les permissions sur le système de fichier:

-rw-rw-rw- 1 ohan ohan 29696 2009-03-14 13:30 mysite.db

Tous les répertoires parents sont eux en 755 (lecture et exécution), ce qui ne devrait donc poser aucun problème, même pour l’utilisateur utilisé par les processus apache/mod_wsgi.

Le problème

Lors de la première tentative d’accès à la base de donnée (par exemple en accédant à l’administration django), une erreur 500 INTERNAL SERVER ERROR est renvoyée, et dans le fichier de log d’apache:

OperationalError: unable to open database file

La solution

Lors de l’accès à un fichier de base de données, SQLite va créer un fichier journal qui lui servira (entre autres) à gérer les accès à cette base. Plus d’informations sur la page expliquant les méthodes de vérouillage: locking in sqlite v3.

Pour créer ce fichier, il faut donc que l’utilisateur puisse écrire dans le répertoire parent.

chmod a+rw /opt/mysite

Ce problème ne devrait se présenter que lors d’un déploiement en environnement de production pour un projet qui utilise SQLite, ou sur un environnement de test si, comme moi, vous préférez tester sur apache directement, et non sur le runserver.

Categories: django, mod_wsgi, sqlite Tags:

Django svn et mod_wsgi, attention au piège!

17/02/2009 admin 2 commentaires

Scénario

Notre cher utilisateur biboul se décide à installer la version de développement de django, que nous appellerons django-trunk, comme indiqué sur la page How To Install Django.

Il lance donc les commandes suivantes:

biboul@laptop:~$ svn co http://code.djangoproject.com/svn/django/trunk/ django-trunk
biboul@laptop:~$ ln -s `pwd`/django-trunk/django /usr/lib/python2.5/site-packages/django
biboul@laptop:~$ ln -s `pwd`/django-trunk/django/bin/django-admin.py /usr/local/bin

Il a bien entendu

  1. configuré son serveur apache pour utiliser le module WSGI
  2. testé avec le script wsgi “hello world” que la configuration était bonne
  3. modifié le script wsgi de manière à utiliser son application django mysite

Le problème

Lors de la première requête à son application mysite, une belle “500 Internal Server Error” s’affiche, avec les messages d’erreurs suivants dans le fichier /var/log/apache2/error_log:

...  mod_wsgi (pid=5803): Target WSGI script '/opt/tcs/tcs.wsgi' cannot be loaded as Python module.
...  mod_wsgi (pid=5803): Exception occurred processing WSGI script '/opt/tcs/tcs.wsgi'.
...  Traceback (most recent call last):
...       File "/opt/tcs/tcs.wsgi", line 6, in <module>
...           import django.core.handlers.wsgi
...  ImportError: No module named django.core.handlers.wsgi

Mais pourquoi donc, alors qu’un import django.core.handlers.wsgi fonctionne correctement, que ce soit dans l’interpréteur ou dans le shell django?

La réponse

Tout simplement parce que le répertoire django-trunk (dont notre cher utilisateur biboul a fait un lien symbolique dans le répertoire site-packages) n’est pas accessible à un utilisateur différent, si il n’est pas dans le même group.
Or, par défaut et sur la plupart des distributions Linux, les processus apache sont lancé avec un utilisateur limité (www-data, www ou encore apache).

La solution

Un simple chmod 755 des répertoires parents au répertoire django-trunk est suffisant pour régler ce problème.
Une autre solution, plus propre et sécurisée, serait de placer le répertoire django-trunk dans le répertoire /opt, et de modifier les liens symboliques pour utiliser ce nouvel emplacement.

Categories: django, mod_wsgi Tags: