My Universe Logo

Python für Webanwendungen 4: Lieferservice

Posted by Jesco Freund at Oct. 29, 2010 9:56 p.m.

Seit dem vorherigen Teil hat es nun ein paar Tage gedauert - aber hier ist er nun, der versprochene letzte Part. Eine funktionierende Webanwendung ist nun vorhanden, aber noch läuft sie nur im Entwicklungsmodus, mit dem CherryPy-eigenen Webserver. Für eine Produktivumgebung ist definitiv ein gestandener Webserver vorzuziehen, der den statischen Content besser und schneller ausliefert, robust und praxiserprobt ist und sich über entsprechende Startmechanismen automatisch als Dienst starten lässt.

Mit WSGI-Anwendungen und FastCGI hatte ich bisher kein Glück – zu instabil lief dieses Konstrukt, wenn es überhaupt ans Laufen kam. Richtig schnell und robust hingegen laufen bei mir diverse WSGI-Anwendungen in Kombination mit dem Apache Webserver und mod_wsgi. Unter FreeBSD beispielsweise lassen sich beide Pakete bequem aus den Ports installieren, auch Debian bringt ein entsprechendes Paket mit.

Ein bisschen Arbeit bleibt dennoch zu tun – mit dem bisher verwendeten Startskript scripts/myapp.py kann mod_wsgi nichts anfangen. Nicht nur, dass man mit mod_wsgi nicht so ohne weiteres Kommandozeilenargumente übergeben kann (wie wir es bisher mit der Konfigurationsdatei getan haben) – es erwartet auch ein WSGI-Applikationsobjekt, das auf den phantasievollen Namen application hört. Für das Deployment ist es daher am einfachsten, ein separates Startskript anzulegen. In unserem Beispiel sei das scripts/myapp.wsgi, und zwar mit folgendem Inhalt:

config_file = "/usr/local/www/MyApp/config/production.conf"
myapp_path = "/usr/local/www/MyApp"

# import only the absolute minimum
import os
import sys
import cherrypy

sys.path.insert(0, myapp_path)

# config must be updated before importing anything else
cherrypy.config.update(config_file)
cherrypy.config.update({'environment': 'embedded'})

# add all other imports (particularly from myapp) here
from myapp.controller import Root

application = cherrypy.Application(Root(), script_name=None, config=None)

Aus den verwendeten Pfaden lässt sich unschwer erkennen, dass ich das gesamte Anwendungsverzeichnis MyApp nach /usr/local/www/ kopiert habe – unter FreeBSD der übliche Ablageort für Webanwendungen. Unter Linux könnte das auch /srv/www/MyApp sein – ganz nach Ihrem eigenen Geschmack. Das Skript ähnelt weitgehend dem in Teil 1 vorgestellten Startskript (scripts/myapp.py), nur dass der Konfigurationskontext um die Information 'environment': 'embedded' ergänzt wurde. Im Gegenzug wurde auf die Angabe der Konfigurationsinformationen für statische Inhalte verzichtet – die soll schließlich Apache direkt ausliefern. Außerdem wurde cherrypy.quickstart durch die Erzeugung eines WSGI-Applikationsobjektes ersetzt.

Für den produktiven Einsatz wird auch eine Konfigurationsdatei benötigt, die in einigen Punkten von der Entwicklerversion abweicht. So darf in Zusammenspiel mit mod_wsgi für Sessions nicht das RAM Session Backend verwendet werden, da so die Sessions nicht zwischen den einzelnen WSGI-Prozessen synchron gehalten werden könnten. Stattdessen kommt das file-Backend zum Einsatz. Außerdem empfiehlt es sich, zumindest in der Anfangszeit die Aktivitäten der Anwendung und insbesondere aufgetretene Fehler zu protokollieren. Im Produktiv-Einsatz sollten natürlich keine Fehler mehr auftreten, aber so ganz ohne Logs debuggt es sich im Falle eines Falles eben schlecht. Hier eine Konfigurationsdatei (config/production.conf), die sich für den Live-Testbetrieb eignet:

[global]
log.error_file = '/var/log/myapp/error.log'
tools.log_tracebacks.on = True
tools.sessions.on = True
tools.sessions.storage_type = 'file'
tools.sessions.storage_path = '/var/run/myapp'
tools.encode.on = True
tools.decode.on = True
tools.encode.encoding = 'utf-8'
tools.trailing_slash.on = True
theme.dir = '/usr/local/www/MyApp/themes'
theme.name = 'default'
ldap.url = 'ldap://localhost'
ldap.tls = True
ldap.template = 'uid=%s,ou=people,dc=my-domain,dc=tld'

Zu guter Letzt muss nun Apache noch mitgeteilt bekommen, wie die Applikation zu starten und einzubinden ist. Hier ein Konfigurationsausschnitt, der z. B. in einem virtuellen Host eingefügt werden kann:

# Das mod_wsgi Modul muss natürlich geladen werden
LoadModule wsgi_module libexec/apache22/mod_wsgi.so

# Aliase für statische Inhalte
Alias /favicon.ico  /usr/local/www/MyApp/themes/default/static/img/favicon.ico
Alias /static/      /usr/local/www/MyApp/themes/default/static/

# Zugriff auf statische Inhalte ermöglichen
<Directory /usr/local/www/MyApp/themes/default/static>
    Order allow,deny
    Allow from all
</Directory>

# Der ganze Rest wird dann von der Applikation "serviert"
WSGIScriptAlias / /usr/local/www/MyApp/scripts/myapp.wsgi

# Und natürlich auch auf die muss der Webserver zugreifen dürfen
<Directory /usr/local/www/MyApp/scripts>
    Order allow,deny
    Allow from all
</Directory>

Sind alle Verzeichnisse angepasst, Berechtigungen richtig gesetzt, etc., dann genügt es nun, den Indianer zu starten – und schon sollte sich die Applikation im Browser aufrufen lassen.

1 comment | Defined tags for this entry: Apache, CherryPy, code, development, python

Comments

Eine sehr schöne und detailierte Artikelserie - vielen Dank dafür!
/thorsten

ThorstenS on Oct. 30, 2010 14:43 CEST