Deploying WordPress mit Git und Capistrano

capistrano

Bereits 2011 hatte Mark Jaquith auf dem WordCamp in San Francisco in seinem Vortrag Capistrano erwähnt. Dabei stellte er fest, dass das Publizieren von Web-Anwendungen mit Hilfe von Capistrano auf unterschiedlichen Servern zu Test- und Entwicklungszwecken einfach und zugleich flexibel erweiterbar abgewickelt werden kann.

Nicht selten kommt es bei Großprojekten vor, dass die Serverlandschaft ausgebaut wird, um den aktuellen Ansturm an Traffic zu bewältigen. Selbst bei kleinen bis mittelgroßen Projekten arbeiten wir bei Inpsyde mit folgender Konstellation:

  • Lokale Entwicklungsumgebung
  • DEV-Server (gemeinsamer Entwicklungsserver)
  • Stage/Test-Server (sollte jeder haben! Kundenfreigabe)
  • Live-Server {n}

Was ist Capistrano?

Capistrano ist ein Kommandozeilen-Programm für die Bereitstellung von Web-Anwendungen auf einem oder mehreren Servern. Es wurde in erster Linie für Anwendungen mit Ruby on Rails entwickelt, funktioniert aber für alle Arten von Web-Anwendungen, darunter natürlich auch WordPress.

Eine typische Anwendung wie eine WordPress-Seite wird normal in einem Versionierungsprogramm (GIT, SVN, CVS …) verwaltet. Nachdem lokal alles entwickelt und getestet worden ist, loggt man sich per SSH sich auf dem Server ein und spielt die Änderungen aus dem Repository des Versionierungsprogramms ein.

An diesem Punkt der Entwicklung kommt Capistrano ins Spiel. Nach einer kurzen Konfiguration wickelt das Programm mit einem einzigen Befehl folgenden Ablauf standardmäßig ab:

  1. Einloggen per SSH auf dem Server
  2. In das richtige Verzeichnis wechseln
  3. Änderungen aus dem Repository einspielen.

Zusätzlich findet automatisch eine Versionierung der verschiedenen Deploys im Dateiverzeichnis statt. Somit können wir jederzeit auf eine ältere Version zurückspringen. Auch kann der Ablauf um weitere Automatismen erweitert werden.

Installation Capistrano

Da Capistrano in Ruby geschrieben ist, muss Ruby auf der lokalen Arbeitsumgebung installiert sein. Die Scripte und Konfigurationsdateien sind ebenfalls in Ruby zu schreiben. Aber schon mit geringen Programmierkenntnissen ist das recht einfach.

Mit dem Befehl ruby --version kann über die Konsole herausgefunden werden, ob Ruby bereits installiert ist. In einigen Linux-Distributionen ist Ruby bereits vorinstalliert, ansonsten muss dies per Paket-Manager über den Befehl apt-get install ruby (in Debian) noch nachgeholt werden. Für Windows und Mac OS X I’ll können die folgenden Installer verwendet werden:

Ruby kommt mit einem eigenen Paket-Manager namens gem. So kann Capistrano anschließend mit folgenden Befehlen lokal über die Konsole installiert werden:

Das erste Paket ist das Hauptprogramm Capistrano, mit dem railsless-deploy-Paket kann man auch Nicht-Rails-Anwendungen per Capistrano deployen. Das dritte Paket liefert noch einige nützliche Erweiterungen zu Capistrano um z.B. “Staging” zu ermöglichen.

Anschließend sollte per

überprüft werden, ob die Installation erfolgreich war. Folgende Meldung müsste dann erscheinen:

Projektstruktur in Git

Für unsere Kunden-Projekte haben wir nur den wp-content-Ordner im Git-Repository. Der uploads-Ordner wird dabei nicht mit ins Git eingecheckt, denn für dynamische Daten haben wir in Capistrano-Projekten einen extra Ordner. Unser Git-Repository sieht also folgendermaßen aus:

Projektstruktur auf dem Server

Als Projektstruktur auf dem Server bietet sich folgende an:

Das wordpress-Verzeichnis ist das Root-Verzeichnis für unsere Webseite. Die Ordner wp-admin und wp-includes sowie die PHP-Dateien im Root-Verzeichnis müssen auf den Server. Der wp-content-Ordner ist leer und bekommt einen Symlink auf your-project/deployments/current. Auf das uploads-Verzeichnis im shared-Ordner gehe ich später noch ein.

WordPress

Damit WordPress die Symlinks korrekt auflöst, muss das WP_CONTENT_DIR neu gesetzt werden. Hierzu kann die PHP-Funktion realpath verwendet werden. Diese löst den Symlink auf das wp-content-Verzeichnis auf und liefert den korrekten Pfad aus.

Capify WordPress

Nachdem alle Vorbereitungen getroffen sind, kommen wir nun zum wichtigsten Teil: WordPress für Capistrano bereitstellen. Dazu navigiere in deiner Konsole in dein wp-content-Verzeichnis des Projektes und gib folgenden Befehl ein:

Dieser Befehl erstellt eine spezielle Datei namens Capfile im wp-content-Ordner und generiert einen Ordner config. Dieser Ordner enthält die wichtigsten Konfigurationsdateien für das Deployen des Projektes. Die Capfile hilft Capistrano beim Laden deiner Konfigurationen und Scripte.

Widmen wir uns erst der Capfile. Dazu öffne die Datei ersetze alle generierten Standardwerte durch folgendes:

Die erste Zeile lädt das railsless-deploy-Modul, das benötigt wird, da wir WordPress, eine nicht-Ruby-Anwendung, mit Capistrano deployen möchten. Der Multistage-Block definiert, welche Stages wir später haben. In default_stage wird einer dieser Stages eingetragen. Zu den gewählten Stages werden wir später gleichnamige Konfigurationsdateien mit den benötigten Serverdaten anlegen.

Zum Schluss laden wir noch die deploy.rb-Datei aus dem config-Verzeichnis. Öffne diese Datei und ersetze alles durch folgende Werte:

Zuerst geben wir unserer Applikation einen Namen. Der nächste Block leitet mit dem SCM (Source Control Management) ein. Hier weisen wir :git zu (weitere SCM hier). In den nachfolgenden Zeilen definieren wir unser Repository und den Branch, welchen wir auf unserem Server haben möchten.
Die Variable deploy_via setzen wir auf :remote_cache. Diese Variante hält auf dem Server eine Kopie des Git-Repositories, führt nur ein “fetch” anstelle eines kompletten “clone” aus und beschleunigt somit dem Deployment-Ablauf. Weitere Deploy-Strategrien findest hier.

Im letzten Block definieren wir in der Variable :copy_exlude nun noch einen Array mit Dateien, die wir nicht auf unserem Server haben wollen, aber in unseren Git-Repo sind. :keep_releases definiert, wie viele Versionen zurück wir aufheben möchten und :use_sudo setzen wir auf false, da wir nicht möchten, dass Capistrano auf dem Server alles via sudo-Befehl ausführt.

Weitere Einstellungen sind in der offiziellen Dokumentation zu finden.

Zu guter letzt legen wir noch im config-Ordner einen Ordner mit der Bezeichnung deploy an. Hier kommen die oben erwähnten 3 Konfigurationsdateien zu den gleichnamigen Stages zum Einsatz:

In die Dateien trägst du dann wie folgt deine Serverzugangsdaten ein:

Der Wert in deploy_to ist das Verzeichnis auf dem Server, wo die Anwendung bereitgestellt wird (siehe Projektstruktur auf dem Server) und der user beinhaltet den SSH-User fürs Deployen. In der letzten Zeile wird der Host für die Rolle :app gesetzt. Diese spielt an diesem Punkt noch keine wichtige Rolle, sollte aber im Hinterkopf behalten werden. Zum Abschluss führen wir noch folgenden Befehl aus:

Dieser Befehl bereitet auf dem Server die benötigten Verzeichnisse vor. Um zu überprüfen, ob alles in Ordnung ist, kann folgender Befehl ausgeführt werden:

Hierbei wird die lokale Umgebung auf dem angegebenen Server überprüft und es wird nach möglichen Problemen gesucht. Sollten hier keine Fehlermeldungen erscheinen und alles korrekt konfiguriert sein, erscheint folgende Meldung:

Unser erster Deploy

Nachdem wir nun alle Konfigurationen erfolgreich abgeschlossen und getestet haben, kann auch endlich deployt werden. Dazu gehe per Konsole in dein Projektverzeichnis wo die Capfile liegt und gebe folgendes ein:

Dieser Befehl wird auf deinem angegeben development-Server the_host.tld einloggen und in das Verzeichnis /path/to/deployments/ navigieren. Anschließend wird er in das Verzeichnis releases den master-Branch von Git klonen. Nun sollte in deiner Konsole eine Menge an Ausgaben zu sehen sein, welche im Grunde sagen, in welcher Phase sie was tun. Am Ende, wenn alles erfolgreich war, sollte nun folgende Meldung stehen:

Um nicht bei jedem Deploy über Capistrano erneut die Zugangsdaten einzugeben, kann ein RSA-Schlüssel generiert werden. Dieser muss auch auf dem Zielserver hinterlegt werden. Einige weiterführende Informationen hierzu findet Ihr hier:

Nun haben wir erfolgreich unseren ersten cap deploy ausgeführt. Jetzt wollen wir doch mal sehen, was passiert ist. Dazu verbinden wir uns via SSH auf unseren Server und navigieren zu unseren deploy_to-Pfad. Dort wirst du nun folgende zwei neue Verzeichnisse sehen:

Das current-Verzeichnis ist dabei ein Symlink auf das neueste Unterverzeichnis in releases.
Nach jedem Deploy wird im releases-Verzeichnis ein neuer Ordner mit dem kompletten Verzeichnis angelegt. Der Symlink auf dem current-Verzeichnis wird dabei immer automatisch aktualisiert.

Rollback

Nicht, dass wir es brauchen, aber was ist wenn mal etwas schief geht und die Seite nach dem deploy nicht mehr erreichbar ist? Die Lösung ist einfach:

Dieser Befehl setzt den aktuellen Symlink auf unseren current-Ordner auf den vorherigen Release. Per

kann man ganz einfach wieder auf die aktuelle Version switchen.

Releases aufräumen

Da wir bei jedem cap deploy einen neuen Release unserer Anwendung erstellen, kann es vorkommen, dass unser release-Ordner mit der Zeit ziemlich voll wird. In unserer deploy.rb haben wir bereits mit set :keep_releases, 5 definiert, dass wir nur die letzten fünf Releases behalten wollen. Allerdings müssen wir Capistrano auch sagen “Räum’ endlich auf!”. Folgender Befehl bringt hier Abhilfe:

Damit man nicht nach jedem Deploy diesen Befehl eingeben muss, können wir ganz bequem dieses Kommando wie folgt ans Ende unserer deploy.rb setzen:

Somit wird nach jedem Deploy-Vorgang der Hook “ cleanup” ausgeführt und überflüssige Releases gelöscht.

Capistrano Shared Files

Wir wissen nun, wie man Deploys und Rollbacks ausführt. Jetzt lernen wir, wie wir unsere freigegebenen Dateien im shared-Ordner verlinken. Da sich ja bei jedem Deploy/Rollback unser wp-content-Verzeichnis verschiebt (neuer Ordner in releases), müssen wir den Symlink für unser uploads-Verzeichnis automatisiert aktualisieren. Was bietet sich da nicht besser an, als selbst eine kleine Aufgabe zu definieren die wir bei jedem Deploy mit ausführen lassen?

Folgende 3 Schritte sind dafür nötig:

1. Erstelle im config-Ordner die Datei task.rb und trage folgende neue Aufgabe ein:

Zunächst definieren wir einen Namespace, unter welchem der Aufruf später erfolgt. Dieser entspricht dem Schema: cap {namepsace}:{task}. Der nächste Block definiert die eigentliche Aufgabe mit der Rollenzuweisung :app. Das heißt, dass unser Task nur für den definierten Server mit der Rolle :app ausgeführt wird. In der 4. Zeile definieren wir den eigentlichen Befehl. Hier wird das Kommando ln -nfs ausgeführt und der Symlink erzeugt. Die Variablen shared_path und release_path sind vordefinierte Variablen von Capistrano.

2. Füge vor load 'config/deploy' in der Capfile folgendes hinzu:

Somit laden wir vor jedem Deploy unsere definierten Tasks und stellen diese zur Verfügung.

3. Öffne deine deploy.rb-Datei und trage deinen neuen Task ans Ende der Datei ein:

Hiermit definieren wir, dass nach dem Abschluss des Deploys die neu definierte Ausgabe ausgeführt wird. Diese aktualisiert den Symlink unseres aktuellen Releases:

auf unserem shared-Ordner

Zusammenfassung

Ich hoffe, Ihr konntet in meinem Beitrag ein paar Einblicke in den Arbeitsablauf bekommen und auch etwas dazulernen. Viele Prozesse lassen sich heutzutage einfach und schnell optimieren. Natürlich gehört auch bei Capistrano etwas Einarbeitungszeit und eine Erst-Konfiguration dazu, aber gerade bei großen Projekten mit vielen Servern spart man enorm Zeit, löst viele Abhängigkeiten durch Verwendung von gemeinsamen Schnittstellen und kann verschiedenste Automatismen in den Deploy-Ablauf mit einbinden.

Anbei noch die ganzen Dateien zum Anschauen und Downloaden:

Beitrag teilen

Author Avatar

Hi! Mein Name ist Chris und ich arbeite als leidenschaftlicher Webentwickler im X-Team der Inpsyde GmbH. Meine Spezialgebiete sind die Backend- und Frontendentwicklung. Wenn ich nicht gerade über Barrierefreiheit und Usability diskutiere, bin ich auf Google+ unterwegs. In meiner Freizeit absolviere ich ein Informatikfernstudium, treibe gern und viel Sport, verschlinge ein Buch nach dem Anderen und blogge auf www.chrico.info.

Auch interessant:

Neue Produktfilter WordPress

Plugins angetestet: WooCommerce Products Filter - Erweiterte Produktfilter

von Michael Firnkes

WooCommerce enthält bereits die wichtigsten Funktionen, damit deine Kunden Produkte nach Preis, Kategorie etc. filtern können. Wem diese Möglichkeiten n ...

Weiterlesen
youtube

Neu: Video-Tutorials für German Market

von Michael Firnkes

Du willst wissen, wie sich die einzelnen Module in unserer Rechtssicherheits-Suite German Market für WooCommerce bedienen lassen? Dann helfen wir dir jetz ...

Weiterlesen
woonews20

WooCommerce Wochenrückblick #20: Conversion, Produktkonfigurator und Woo-Argumente

von Michael Firnkes

Wir sammeln Argumente für das führende Onlineshop-System und für Open Source. Und: Einen Produktkonfigurator kannst du auch mit WooCommerce umsetzen. Di ...

Weiterlesen
ERP

Warum sich der Einsatz eines ERP Systems auch für kleine Händler lohnen kann

von Max Ager

Die eCommerce-Branche ist eine der am schnellsten wachsenden Brachen überhaupt. Über eine Million Onlineshops basieren auf dem bekannten WooCommerce-Syst ...

Weiterlesen

Kommentare

6 Kommentare

  1. #1

    Hallo Christan

    Danke für die ausführliche Beschreibung 🙂

  2. #3

    Ehrlich gesagt habe ich das Tutorial erst im Kopf durchgespielt. Werde es aber diese Woche noch für ein grösseres Projekt in unserer Agentur ausprobieren 🙂

  3. #4

    Hi Chris,

    vielen Dank für das super Tutorial!
    Ganz am Ende hakt es bei mir. Zum Einen muss man (wahrscheinlich mittlerweile) am Ende der deploy.rb den Task wie folgt aufrufen: after “deploy”, “shared:make_symlink”.
    Also an erster Stelle immer noch den Namen des vorherigen Tasks mit angeben. Ansonsten gibts nen Syntax-Fehler.
    Zum anderen legt er bei mir momentan die Symlinks nicht an. Da bin ich grad noch am suchen.

    Viele Grüße
    Christian

  4. #5

    Hi,

    ich nochmal. Ich weiß nicht, woran es lag. Aber so hat es funktioniert:

    In der deploy.rb habe ich zunächst den Task ausgeführt und ganz zum Schluss die alten Deploys aufgeräumt:
    after “deploy:update_code”, “shared:make_symlinks”
    after “deploy”, “deploy:cleanup”

    Und mein Task sieht wie folgt aus:
    namespace :shared do
    desc “Create symlink for uploads”
    task :make_symlinks, :roles => :app do
    run “ln -nfs #{shared_path}/uploads #{release_path}/uploads”
    end
    end

    An der Reihenfolge der Tasks liegt es nicht. Aber so läuft nun alles durch bei mir.

    Dank dir nochmal!

    Viele Grüße
    Christian

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML Tags verwenden: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">