Florian Schlachter Internetservices

Hotline

Der Weg zum schnellen Deployment zurück zum Labor

Deployment von Webanwendungen (in meinem Fall Django-Projekte) kann anstrengend und nervtötend sein - insbesondere dann, wenn stets dieselbe Routine notwendig ist, um die Webanwendung auf dem Server zu aktualisieren und ggf. zu warten.

Gestern habe ich fabric, ein von der Idee her triviales Framework, kennen gelernt, mit dem sich alle nun folgenden Schritte (und sicher noch viele mehr) automatisieren lassen. Es erleichtert einem die Arbeit enorm - ich weiß schon gar nicht mehr, wie ich bislang ohne konnte.

Die gängigsten Schritte beim Deployment sind m.M.n.

  • Sourcecode synchronisieren (committen, pushen, remote updaten)
  • Webanwendung neustarten
  • Nachkontrolle u. Debugging (z. B. Blick in die Fehlerlogs)

Etwas seltener, jedoch auch durchaus noch stets nach Schema F, kümmert man sich um:

  • Aktualisieren von Third-Party-Libraries

Einführung

Fabric ist einfach gestrickt: fabfile.py angelegt, einfache Funktionen geschrieben, die jeweils eine Aufgabe übernehmen. Das Framework bietet unter anderem Funktionen zur lokalen und entfernten Befehlsausführung (local(), run(), sudo(), normales Bash-Script z. B.) und zum Dateitransport (put()). Ist das fabfile angelegt (idealerweise im Project-Root), kann über die Fabric-Anwendung fab auf die einzelnen Funktionen zugegriffen werden. Dabei liest fab das fabfile ein und führt entweder, sofern der Funktionsname als Argument 1 übergeben wurde, die Funktion aus oder präsentiert (ohne Übergabe von Argumenten) alle möglichen Funktionen inklusive ihrer Docstrings:

florian-schlachters-imac:home flosch$ fab
Fabric v. 0.1.1.
No commands given.
Available commands are:
   about      : Display Fabric version, warranty and license information
   access_log : Tail the servers access logfile.
   deploy     : Syncs all repositories and restarts the whole server
   error_log  : Tail the servers error logfile.
   fullhg     : Synchronizes and updates the reps
   help       : Display Fabric usage help, or help for a given command.
   hgsync     : Pushes and pulls to/from remote
   hgupdate   : Updates the reps
   let        : Set a Fabric variable.
   list       : Display a list of commands with descriptions.
   restart    : Restarts django fcgi process
   shell      : Start an interactive shell connection to the specified hosts.
   start      : Starts django fcgi daemon
   stop       : Stops the django daemons
   upgrade    : Upgrades all used Django apps.
Done.

Ausführen der Funktion stop(), die in meinem Fall auf dem Deploy-Server den Django-Prozess stoppt:

florian-schlachters-imac:home flosch$ fab stop
Fabric v. 0.1.1.
Running stop...
Logging into the following hosts as root:
    project.tld
[project.tld] run: ...
Done.
florian-schlachters-imac:pb2 flosch$

Die Kommunikation findet via SSH statt. Dazu stellt fabric nach dem Starten per SSH eine Verbindung mit dem Remote-Host her. Findet keine Anmeldung via Public-Key statt, erfragt es das Passwort des Nutzers (mehr dazu weiter unten).

Konfiguration des fabfile.py

Viel zu Konfigurieren gibt es bei fabric nicht: Mit dem Projektnamen und dem Remote-Host ist es in der Grundkonfiguration eigentlich schon getan:

config.project = 'projectname'
config.fab_hosts = ['project.tld']

Auf Wunsch kann der Hostname mit einem SSH-Benutzernamen versehen werden, gemäß gewöhnlicher Syntax: user@host.tld.

Ferner können Konstanten für die spätere Befehlsausführung festgelegt werden. So kann beispielsweise definiert werden, wo Logfiles liegen, wenn der Pfad später in einigen Befehlen öfter benötigt wird:

config.log_dir = '/var/log/lighttpd/

Der Name der Konstante (hier log_dir) kann frei gewählt werden. Genutzt werden kann der Platzhalter im späteren Verlauf innerhalb eines Befehls via gewöhnlichem String-Formatting. Beispiel:

def access_log():
    "Tail the servers access logfile."
    run('tail -f %(log_dir)saccess.log')

Die Funktion acesss_log() wird weiter unten noch näher erläutert (siehe Nachkontrolle und Debugging).

Synchronisieren der Codebase

Zum Synchronisieren aller Änderungen zwischen Dev-Rechner und Server lohnt die Verwendung einer Versionsverwaltung (ich empfehle Mercurial). Dabei habe ich mir eine Fabric-Funktion gestrickt, die alle Änderungen auf dem Deploy-Server committed (falls ich wirklich mal direkt am Server mit vi Kleinigkeiten korrigieren sollte) und daraufhin alle Änderungen vom Server abholt, meine Änderungen an den Server schickt und letzen Endes am Server die Codebase auf den aktuellsten Stand bringt.

Konkret schauen die drei wichtigsten Funktionen folgendermaßen aus:

def hgsync():
    "Pushes and pulls to/from remote"
    run("cd /srv/project ; hg commit -m 'remote changes'") # remote Befehlsausführung
    local('hg push') # lokale Befehlsausführung
    local('hg pull')

def hgupdate():
    "Updates the reps"
    run('cd /srv/project ; hg update')
    local('hg update')

def fullhg():
    "Synchronizes and updates the reps"
    hgsync()
    hgupdate()

Aufrufen kann ich sie via fab hgsync, fab hgupdate oder fab fullhg. fullhg() hat keine eigene Funktionalität sondern erspart mir lediglich, hgsync() und hgupdate() manuell hintereinander ausführen zu müssen.

Start und Stopp der Webanwendung

Die Leute, die Django in Kombination mit WSGI und Apache nutzen, haben eindeutig die elegantere Möglichkeit, die Webanwendung bei Änderung der Codebase neuzustarten. Hier reicht ein touch des entsprechendens wsgi-Files. Ich nutze jedoch die runfcgi-Methode der manage.py im Daemon- und TCP-Mode. Dabei startet Django FCGI-Prozesse im Hintergrund und akzeptiert Anfragen via TCP-Protokoll auf einem von mir festgelegtem Port. Ich kann die Anwendung nur dann neustarten, wenn ich den alten Prozess terminiere und ihn neu aufrufe.

Update: steph hat mich darauf aufmerksam gemacht, dass der manage.py-Command runfcgi den Parameter pidfile akzeptiert, über den ein Filename angegeben werden kann, in dem die Prozess-ID des Daemon abgelegt wird. Die Variante ist natürlich viel schöner als mein (voriges) herumgegreppe (hast du es hier nicht gelesen, ignoriere es einfach ). Ich habe meine start()- und stop()-Funktionen entsprechend angepasst:

def stop():
    "Stops the django daemons"
    run("if [ -f $(pidfile) ]; then kill `cat $(pidfile)` && rm $(pidfile); fi")

def start():
    "Starts django fcgi daemon"
    run("cd /srv/pb2 ; python ./manage.py runfcgi protocol=fcgi host=127.0.0.1 port=3033 pidfile=$(pidfile)")

start() sollte soweit selbsterklärend sein; stop() prüft, ob das pidfile existiert. Ist dem so, wird der Django-Prozess terminiert und das pidfile gelöscht. Beide Funktionen greifen auf die Konstante config.pidfile zu, in der ich den pidfile-Dateipfad des Projekts (z. B. /myproject/myproject.pid) festgelegt habe.

Nachkontrolle und Debugging

Das bisherige manuelle anmelden am Server + tailen von Logfiles kann auch per fabric automatisiert werden. Per fab access_log loggt es sich ein und zeigt sofort den fortlaufenden Tail des Access- oder Errorlogs. Die Idee habe ich dem django-de-fabric-File entnommen. Danke dafür

def access_log():
    "Tail the servers access logfile."
    run('tail -f %(log_dir)saccess.log')

def error_log():
    "Tail the servers error logfile."
    run('tail -f %(log_dir)serror.log')

Es gibt sicher noch viel mehr Anwendungsgebiete für's Debugging, die per fabric automatisiert werden können. Ich bin an neuen Ideen interessiert!

Aktualisieren von Third-Party-Libraries

Wer ein Verzeichnis mit allen Libraries besitzt (und diese per VCS ausgecheckt hat), möchte möglicherweise mehr oder weniger regelmäßig alle Bibliotheken auf dem Laufenden halten. Hierzu dient ein einfaches Shell-Script, dass ich per run() remote auf dem Deploy-Server ausführe.

def upgrade():
    "Upgrades all used Django apps."

    # Git
    run("for app in /srv/libs/*; do cd $app && git pull && git gc; done", fail='ignore')

    # Svn
    run("for app in /srv/libs/*; do cd $app && svn up; done", fail='ignore')

Das Argument fail='ignore' im run() dient hier übrigens dazu, dass fabric nicht meine Funktion an der aktuellen Stelle ohne weitere Ausführung beendet, sollte ein run() oder sudo() fehlschlagen (z. B. durch einen entsprechenden Returncode). Das tut es nämlich regulär und ist hier nicht gewünscht (einige pulls/updates werden nämlich fehlschlagen, da es sich beiden Verzeichnissen möglicherweise nicht um ein entsprechendes Repository handelt).

Zusammenfassen von Funktionen

Hat man sich seine einzelnen Funktionen für die jeweiligen Aufgaben zusammengeschrieben, können diese noch zu einem großen Deploy-Befehl zusammengefasst werden. Meiner schaut zum Beispiel folgendermaßen aus:

def deploy():
    "Syncs all repositories and restarts the whole server"
    fullhg()
    restart()

Der Sourcecode wird synchronisiert und die Djangoprozesse neugestartet. restart() führt dabei übrigens einfach stop()und start() hintereinander aus.

Möchte ich meine lokalen Änderungen auf meinen Production-Server anwenden, reicht somit ab sofort nur noch ein einfaches fab deploy - und alles geht wie von Zauberhand.

Tipp: Public-Key-Authentication

Damit Fabric nicht bei jedem Aufruf nach dem SSH-Passwort fragt (was auch ziemlich nervig sind kann ), ist die Einrichtung einer SSH Public-Key-Authentication sinnvoll. Mehr Informationen zur Einrichtung finden sich zum Beispiel hier.

FAQ: Was ist mit sudo()?

Ich habe mich zu Testzwecken stets als Benutzer root beim Fremdsystem angemeldet - eigentlich ein Unding, das ich hier auch niemandem empfehlen möchte. Zu diesem Zweck gibt es das Unix-Tool sudo (super user do), das als normaler User eine Befehlsausführung als root ermöglicht. Wann immer also die Ausführung als Administrator notwendig ist, kann auch in fabric sudo() genutzt werden (identisch in der Nutzung wie run()).

Veröffentlichung Beitrag veröffentlicht 30.04.2009 03:22:55 Uhr

Kommentare 0 Kommentar(e)

Quelle Quelle oder weiterführende URL
http://www.nongnu.org/fab/


Labor: Blog & Bookmarks

Blogeintrag Deutscher Django-Verein e. V. gegründet (08.12.2009)
Update 29.01.2010 Der Deutsche Django-Verein e. V. wird seit dem 28.01.2010 im ...
Blogeintrag Kurz notiert: PIL unter Mac OS X (01.09.2009)
Es folgt die zweite Kurzanleitung nach der Installation von psygopg2 unter Mac ...
Blogeintrag Kurz notiert: psycopg2 unter Mac OS X (01.09.2009)
Die Python-PostgreSQL-Bindings ließen sich bei mir mittels easy_install oder pip nicht installieren ...
Alle Beiträge aus dem Labor anzeigen.

Unsere Referenzen (Auszug)

  • psd-tutorials.de [mehr]

    psd-tutorials.de vertraut als eines der führenden deutschen Grafikportale auf unsere Server-Infrastruktur und nutzt diese für seine regelmäßigen Backups.

  • pizzabus.de [mehr]

    pizzabus.de ist die erste deutsche Online-Vermittlungsplattform für Lieferdienste, die Online-Zahlung akzeptiert. pizzabus.de wird von uns in Eigenregie betrieben.

  • rumsoft-webservice.de [mehr]

    Die Firma Rumsoft ist in der Softwareentwicklung tätig und hat ihr Dienstleistungsportfolio durch Wiederverkäufer-Dienstleistungen aus unserem Hause erweitert. In ihrem Namen bietet sie eigene Domain- und Hostingleistungen an.

  • teleskopmanufaktur.de [mehr]

    Für die TeleskopManufaktur haben wir einen umfangreichen und branchenspezifischen Online-Shop entworfen. Umfangreiche Community-Funktionen wie Foren oder Benutzerprofile runden die Internetpräsenz ab.

  • Redaktionssystem SZ-AORTA
  • Kirchengemeinde Alt-Buckow
  • Carl-Zeiss-Oberschule Berlin [mehr]

    Die Carl-Zeiss-Oberschule erhielt ein frisches, neues Design und nimmt unser maßgeschneidertes Webhosting in Anspruch. Über von uns bereitgestellte Mailinglisten hat sich die Berliner Schule ein individuelles Kommunikationsnetzwerk aufgebaut.

  • OpenSeek [mehr]

    Unter dem Projektnamen OpenSeek betreiben wir bereits seit über vier Jahren Forschungen auf den Gebieten der Suchmaschinentechnik und Semantic Search.

  • Anwendung für Bundes-Jugend-Spiele
XING Florian Schlachter
Internetservices & Software Design

Gerlinger Straße 6
12353 Berlin
Deutschland

Telefon: 0800 378 66 57 (gebührenfrei)
Telefax: 030 868 70 53 919 (Faxbox, 24h am Tag)
E-Mail: support@fs-tools.de

USt-IdNr.: DE251185782
zuständiges Finanzamt: Berlin-Neukölln
Rechtsform: Einzelunternehmen

Datenschutzerklärung - Widerrufsrecht - Allgemeine Geschäftsbedingungen

Wir nutzen Icons vom Tango Desktop Project.

Alle Preise sind Endpreise und inklusive der derzeitig gültigen Umsatzsteuer in Höhe von 19%.