Wie in den vorigen Teilen der Serie angedeutet, ist der nächste Schritt, ein Provisionierungs-Tool zu nutzen, also ein Tool zur Automatisierung von Infrastruktur, mit dem z.B. Entwicklungs-, Test- und Produktiv-Umgebungen synchron konfiguriert werden können. Dieses ersetzt weitestgehend die Shell-Skripte zur Einrichtung der VM durch eine deklarative Sprache zur Definition des gewünschten Zustands der Systeme. Dieser Unterschied ist entscheidend: wir definieren nicht länger eine Abfolge von Befehlen (also, WIE der Zustand erreicht werden soll), sondern den Zustand selbst, und Puppet kümmert sich um die jeweils notwendige Ausführung.
Populäre Alternativen zu Puppet sind Chef und Ansible (beide in Python geschrieben). Ich habe mich für Puppet entschieden, aus folgenden Gründen:
- es läuft auf Ruby, genau wie Vagrant, also eine zusätzliche Technologie weniger
- es ist für alle gängigen Plattformen verfügbar, läuft also auch unter Windows
- das GUI Tool PuPHPet ermöglicht das Konfigurieren von Vagrant Boxen für PHP Anwendungen (und mittlerweile auch Ruby, Python, NodeJS) in kürzester Zeit und ohne die Syntax der Puppet DSL kennen zu müssen.
PuPHPet
Der PuPHPet Konfigurator ist erreichbar unter http://puphpet.com/ – der Source Code ist aber frei auf GitHub verfügbar, so dass jeder seine eigene Instanz aufsetzen kann, um zusätzliche Features einzubauen oder die Weiterentwicklung voranzutreiben.

PuPHPet auf Github
How do you pronounce PuPHPet?
The p is silent.
Ich werde die Konfiguration hier nicht Schritt für Schritt durchgehen, auf der Seite ist eigentlich alles erklärt und die Benutzerführung ist sehr gut.
Zum Abschluss bekommt man ein Zip-Archiv zum Download angeboten, das die benötigten Dateien für Vagrant und Puppet enthält sowie eine config.yaml-Datei. Alle konfigurierbaren Parameter sind in dieser Datei definiert, der Rest ist jedes Mal gleich, außer evtl. nach Updates des Konfigurators. Das schließt auch die Vagrant-Konfigurationen ein, die sonst im Vagrantfile liegen würden. Das von PuPHPet generierte Vagrantfile liest die Konfigurationen aus der config.yaml aus. Wir erinnern uns, das Vagrantfile ist selbst ein Ruby-Skript, dadurch ist dies ohne weiteres möglich.
Die config.yaml
ist größtenteils selbsterklärend und leicht manuell zu bearbeiten. Es ist aber auch möglich, sie per Drag and Drop in den Konfigurator hochzuladen und dort zu bearbeiten.

Upload per Drag & Drop
Puppet installieren
Zusätzlich zu Vagrant und VirtualBox (siehe Teil 1) benötigen wir auf dem Host-System nun auch Puppet.
Puppet versucht einen auf puppetlabs.com mit allen Tricks dazu zu bringen, die Enterprise Version zu testen, und macht es schwer, die Open Source Version zu finden. Um das abzukürzen, nutzt folgende Links, um direkt zu den Downloads zu gelangen:
Windows: https://downloads.puppetlabs.com/windows/?C=M;O=D
Mac: https://downloads.puppetlabs.com/mac/?C=M;O=D
Es können alle Standardwerte bei der Installation beibehalten werden.
Linux-Benutzer nutzen wie gewohnt den Package Manager ihrer Wahl. Welche Repositories für die verschiedenen System existieren, ist hier erklärt: https://docs.puppetlabs.com/guides/puppetlabs_package_repositories.html
PuPHPet und Skripte
Die Einstellungen in config.yaml sind zwar umfangreich, können aber längst nicht alles abdecken, was in unserer bisherigen Konfiguration mit Shell-Skripten gelöst wurde (siehe Teil 2). Die Lösung dafür sind doch wieder Shell-Skripte, als Ergänzung. PuPHPet führt Skripte in den folgenden Verzeichnissen automatisch nach bestimmten Regeln aus:
- puphpet/files/exec-once – einmalig, bei Provisionierung
- puphpet/files/exec-always – bei jeder Provisionierung
- puphpet/files/startup-once – einmalig, nach dem Booten
- puphet/files/startup-always – nach jedem Booten
Skripte, die in diesen Verzeichnissen liegen, werden in alphabetischer Reihenfolge ausgefühft. Anschließend wird, bei den einmalig auszuführenden Skripten, ein Hash der Datei gespeichert. So können Änderungen an den Dateien erkannt werden, und geänderte Skripte, genau wie neu hinzugefügte, beim nächsten Provisioning bzw. Startup ausgeführt werden.
Die Skripte laufen als root Benutzer, manchmal ist es wünschenswert, sie als „vagrant“ ausführen zu lassen, dazu einfach folgenden Code am Anfang einfügen, mit dem das Skript sich selbst mit geändertem Benutzer startet:
1 2 3 4 5 6 |
#!/bin/sh # always run this script as vagrant user if [ "$USER" != "vagrant" ]; then sudo -u vagrant -H sh -c "sh $0" exit fi |
Die integer_net Basis-Vagrantbox
Unter https://github.com/schmengler/magento-boilerplate habe ich eine fertig für Magento-Projekte konfigurierte Basis-Box bereitgestellt. Derzeit ist sie nutzbar für zwei der in Teil 3 vorgestellten Projekttypen:
- Mit Composer installierte Extensions in /.modman, eigener Code und gekaufte Extensions in /src, alles von der Magento-Installation getrennt
- Magento-Installation mit Extensions und eigenem Code vollständig integriert im Magento-Root (kann auch ein Git Submodul sein)
Erste Schritte
Prüfe die Systemvoraussetzungen, siehe Teil 1 und oben (Puppet installieren).
Klone das Repository von https://github.com/schmengler/magento-boilerplate.git oder lade den Code von https://github.com/schmengler/magento-boilerplate/archive/master.zip herunter.
Führe im Projektverzeichnis „up“ aus (oder falls „.“ nicht im PATH ist „./up“) und folge den Anweisungen in der Konsole:

Konfigurations-Menü beim ersten Start der Vagrantbox
Die gewählte Domain/IP Konfiguration sollte noch in die /etc/hosts Datei eingetragen werden (Unter Windows: C:\Windows\System32\drivers\etc\hosts)
Zur Provisionierung von Magento sind die Skripte in puphpet/files/exec-once wichtig. Für eine frische Magento-Installation müssen hier keine Änderungen vorgenommen werden, wird die Box jedoch für ein bestehendes Projekt erstellt oder soll eine bestehende Datenbank importiert werden, dann sind folgende Skripte entscheidend:
- 80-db-import.sh: Datenbankimport – Standardverhalten ist, die aktuelle DB zu leeren und anschließend die neueste *.sql.gz Datei in systemstorage/live/database zu importieren
- 90-magento.sh bzw. 70-install-magento.sh (je nach Template): Hier wird unter anderem Magento installiert (wenn nicht bereits vorhanden). Dazu wird n98-magerun install genutzt, mit den Parametern kann die Magento-Version angepasst werden und optional die Sample Daten mit installiert werden.
- 91-magento-config.sh: Hier wird die Magento-Konfiguration für das Entwicklungssystem angepasst
Mit den vorangestellten Zahlen im Dateinamen wird die Reihenfolge der Ausführung bestimmt.
Wenn alles vorbereitet ist, kann mit der Provisionierung begonnen werden, das dauert eine Weile, also ist erst mal Zeit für Kaffeepause. Wenn einzelne rote Zeilen über den Bildschirm rauschen, ist das normalerweise kein Problem, genauer hinschauen sollte man allerdings, wenn seitenweise nur noch rot zu sehen ist. Wenn alles erfolgreich durchgelaufen ist, wirst du mit folgendem Menü begrüßt:

Startmenü der Vagrantbox
Diese Optionen gibt es:
- L – Login auf der VM. Entspricht „vagrant ssh“
- M – Login mit direktem Aufruf von „n98-magerun shell“. Nützlich, falls man nur die Magerun-Befehle benötigt, z.B: „cache:flush“. Die Konsole beendet man mit Strg-D.
- H – abschalten der VM. Entspricht „vagrant halt“, es wird aber vorher noch der rsync-Prozess abgeschossen.
- S – VM in Ruhezustand versetzen. Entspricht „vagrant suspend“, aber auch hier wird vorher der rsync-Prozess abgeschossen.
- R – startet den Rsync-Prozess neu (manchmal stürzt er ab, z.B. wenn der Host im Ruhezustand war)
- P – Provisionierung im laufenden Betrieb, z.B. nach Änderung der config.yaml oder wenn neue/geänderte Skripte in puphpet/files/exec-once liegen
In dieser Konsole wird nun auch immer in weißer Schrift angezeigt, wenn der rsync-Watcher arbeitet. Wenn das stört, kannst du natürlich auch eine zweite Konsole aufmachen und dich dort direkt mit „vagrant ssh“ auf der Box einloggen.
Die Konsole kann nun einfach im Hintergrund geöffnet bleiben und der Shop ist im Browser über die konfigurierte Domain zu erreichen, z.B. http://webguys2014.local/
Falls du mit dem Magento-Installations-Wizard begrüßt wirst, liegt es daran, dass noch keine vollständige app/etc/local.xml
in der Installation liegt. Nun gibt es zwei Möglichkeiten:
- Die Einrichtung mit dem Wizard durchführen (Datenbankzugang ist root/root)
- Die Datei
etc/local.xml
anpassen. Diese wird direkt in die Magento-Installation gesymlinkt, so dass sie für das (einheitliche) Entwicklungssystem versioniert werden kann. Die vorhandene Datei ist unvollständig, es fehlt Installationsdatum und Encryption Key. Es macht Sinn diese ggf. aus einem vorhandenen System zu kopieren. Anschließend Cache löschen (Login auf der Box undn98-magerun cache:flush
ausführen) und Shop noch mal aufrufen.
Besonderheiten
- Standardmäßig wird ein Backend-User „admin“ mit dem Passwort „test123“ angelegt. Das kann in puphpet/files/exec-once/91-magento-config.sh geändert werden.
- Die Datei
etc/crontab
wird beim Provisionieren als Crontab installiert. Somit kann auch die Cron-Konfiguration versioniert werden. Der Platzhalter {DOMAIN} wird mit dem Inhalt der Dateietc/domain
ersetzt, die bei der Einrichtung zu Beginn generiert wurde. - Mit
/vagrant/update_systemstorage.sh
(ausgeführt in der Box) wird ein Schnappschuss von Datenbank und media-Verzeichnis des Entwicklungssystems insystemstorage/devbox
gespeichert. So kann dies auch versioniert oder mit anderen Entwicklern geteilt werden. Es ist wegen der großen Menge an Binärdaten allerdings nicht empfehlenswert, dazu das Git-Repository des Projekts selbst zu verwenden. Danke an Fabrizio Branca für die Vorlage auf https://github.com/AOEpeople/Magento_SampleProject! - Die sogenannten Dotfiles, also Unix-Konfigurationsdateien, werden beim Provisionieren aus puphpet/files/dot ins Home-Verzeichnis auf der Box kopiert. Die vorhandenen Standard-Dateien können natürlich mit eigenen ersetzt werden. Da viele Entwickler ihre persönlichen Dotfiles pflegen, kann es sinnvoll sein, das Verzeichnis von der Versionierung auszunehmen.
- Das ssh-Unterverzeichnis in
puphet/files/dot
existiert doppelt: „ssh“ enthält die von Vagrant und PuPHPet generierten Keys für die Vagrantbox. „.ssh“ ist für persönliche private keys reserviert. Diese sollten mit_id_rsa
enden, dann werden sie automatisch mit dem SSH Agent registriert. Notwendig ist das nur, falls von der Box aus auf private Repositories zugegriffen werden muss, ohne dass Agent Forwarding genutzt werden kann. Kopiert werden alle Dateien aus dem Verzeichnis, so dass z.B. auch dieknown_hosts
Datei vorbereitet werden kann. - Alle ausgehenden Emails werden von Mailcatcher abgefangen und können in einem Web-Interface unter http://magento.local:1080/ eingesehen werden (ersetze „magento.local“ durch den Hostnamen der jeweiligen Box)
- Xdebug ist mit dem Standard IDE-Key „xdebug“ konfiguriert. Dies lässt sich wie auch die übrige Xdebug-Konfiguration in
puphpet/config.yaml
ändern. - Zum Debuggen von CLI-Skripten kann „xdebug“ als Alias für „php“ verwendet werden. Dabei ist der IDE-Key „xdebug“ allerdings unveränderbar hart kodiert. Beispiele:
xdebug -d memory_limit=1024M
www/shell/indexer.php
xdebug vendor/phpunit/phpunit/composer/bin/phpunit --filter IntegerNet_Solr
Zur Einrichtung von Xdebug, PHPUnit und Remote Code Execution in PHPStorm plane ich noch einem separaten Artikel.
Ende
Ansonsten ist die Serie „Magento-Entwicklung mit Vagrant“ hiermit vorerst abgeschlossen. Alle Teile zum Nachlesen:
- Vagrant-Einführung
- Beispiel-Setup mit Shell-Skripten
- Projektstrukturen für Magento
- Puppet – Provisioning für Fortgeschrittene
Fragen, Anmerkungen und Kritik zum Thema aber auch zur Basis-Vagrantbox sind herzlich willkommen. Letztere konnte nun schon für eine Reihe von Projekten als Grundlage genutzt werden und dabei von Mal zu Mal optimiert werden. Hier gibt es sicher noch mehr Potential.
Hier noch einmal der Link zur Basis-Vagrantbox:

Author: Fabian Schmengler
Fabian Schmengler ist Diplom-Informatiker und Magento Entwickler bei integer_net. Seine Schwerpunkte sind Backend-Entwicklung, Konzeptionierung und Test-Automatisierung. Seit 2011 ist er Magento Certified Developer, seit 2014 Magento Certified Solution Specialist.
Erst einmal vielen Dank für die 4 Teile .. haben mir sehr weiter geholfen!
Du schreibst ja das rsync die Daten in Echtzeit syncronisiert. Bei mir dauert das aber bis zu 5 Sekunden. Und so kann man ja nicht arbeiten. Vor allem weiß man beim blinden Seitenrefresh nie ob er jetzt schon gesynced hat.
Einzige Möglichkeit so wirklich live zu arbeiten sehe ich über die Remote Host Geschichte in PHPStorm.
Von der Geschwindigkeit her würde mir sogar NFS reichen. Allerdings habe ich unter Windows das Problem dass die Symlinks im Shared Folder dann nicht funkiotnieren.
Hast du auch diese Verzögerung bei rsync?
Danke für dein Feedback, Marcus. Bei mir ist es normalerweise <= 1 Sekunde, und zusammen mit dem Auto-Save Feature von PHPStorm sind die Dateien schneller aktualisiert als ich refreshen kann, es gibt also selten Wartezeit und wenn nur sehr kurze. Ich habe eine SSD-Festplatte, auf anderen Rechnern mit normaler HDD ist es tatsächlich nicht ganz so flott aber 5 Sekunden finde ich schon merkwürdig. Synchronisierst du viele zusätzliche Dateien, wie z.B. Bilder in /media ?
Zum "blinden" Refresh: Weil ich auch gerne sehe, was passiert, lasse ich trotz allem wie beschrieben die Konsole mit dem rsync-auto Output offen, zur Bestätigung dass tatsächlich synchronisiert wurde.
Mir erschließt sich noch nicht ganz, wie man mit diesem Setup einen Magentoshop entwickelt, versioniert und anschließend auf einem Staging- und/oder Live-System deployed. Ich habe das git-Repository „magento-boilerplate“ gecloned, an meine Bedürfnisse angepasst (u.a. NGinX statt Apache) und es funktioniert auch alles soweit. Ich habe alle Anpassungen im „src/“ Verzeichnis gemacht, externe Module liegen in „.modman/“. Ich möchte nun meine Arbeit in ein eigenes Git-Repository einchecken, aber auf der Host-Maschine ist das „.git/“-Verzeichnis von „magento-boilerplate“ im Weg. Ich möchte außerdem die „composer.json“ versionieren, da ich dort weitere Module eingetragen habe.
Das .git Verzeichnis kann im Prinzip gelöscht werden, das magento-boilerplate Repository ist als Vorlage für Projekt-Repositories konzipiert, nicht als eigenständiges zusätzliches Repository.
Cool, genau so habe ich es mir auch gedacht und bereits umgesetzt… 🙂
Jetzt kann ich mich voll und ganz darauf konzentrieren, das Deployment mit git push und entsprechenden Hooks umzusetzen. Du hast da nicht zufällig noch ein paar Blogbeiträge? 😉
Noch nicht 🙂 Aber Deployment mit Git Hooks ist ja relativ straightforward:
https://bitbucket.org/integer_net/magento-scripts/src/ad2d8f9a2aa5e27de1f998e63afd70e745c9e558/bin/git-hook.sh?at=development