Es hat sich ausgeMAMPft. Vagrant ist. [Update]

Schon mit dem Update auf Maverick durfte ich meinen gesamten MacPort MAMP-Stack neubauen, mich wieder in die /usr/opt/irgendwas Ubuntu-fremde Pfadstruktur einarbeiten. Jetzt nach Yosemite war wieder ein Komplettupdate nötig. Da ich zunehmend seltener lokal entwickle, sollte der Stack schon irgendwie bekannten Mustern folgen, also Configs in /etc, Webkram in /var/www usw. Lokal läuft ja alles über VHosts, und eine /vhosts Verzeichnis, das sind recht viele.

Da stolpere ich über die Unterstützung von Vagrant in PHPStorm. Was ist das? Automatisch konfigurierte VirtualBoxen, extern konfigurierbar? Und das noch Quellcode-verwaltbar ohne GUI? Das ist doch bestimmt ganz schön komplex? Ja und nein. Ein Erfahrungsbericht mit Versuch und viel Irrtum.

Es gibt reichlich vorkonfigurierte Boxen bei Github und Vagrant Cloud. Ich hab mit vagrant-php-box und vagrant-percona gestartet bzw. inspirieren lassen.

Als Out-of-the-box-Lösung für PHP-Webdev-Stacks gibts mit PhPHPet eine supergeile GUI die am Ende eine Box-Konfiguration ausspuckt. Aber ich will ja ganz spezielle Boxen selber aufsetzen. (“Framework? Nö, da schreib ich mir lieber ein eigenes, muhaha”). Speziell einen Apache-PHP-Box ohne MySQL und ggf. eine MySQL-Box.

MySQL Datenbank Server

Da ich alle Datenbanken lokal in einen Server bündele, möchte ich das auch weiterhin so handhaben für die Bestandsprojekte.

PHP-Entwicklungsserver (ohne MySQL): Da ja die DB ohnehin in einer eigenen Box stecken, braucht die PHP-Box diesen Server nicht.

Erste Idee: Mysql Server in einer einzelnen Box starten. Blöde Idee, scheitert an Rechten auf die gemountete /var/lib/mysql Datenbank-Ordner. Hat einer auch schon bei StackOverflow gefragt, Tipp war dann Impor/Export-Scripte. Ich habe mich dafür entschieden, dass der Mac die Mysql weiter betreiben darf, aber nicht über Mac Port, sondern als Paket direkt von MySQL.

Anleitungen von MySQL:
Howto install Native Package
Installation Systemsteuerung Panel
Bestehenden MySQL-Dienst stoppen

Nach einem Neustart des Dienstes funktionierte es dann auch ganz ordentlich. Bei Zweifeln ob der MySQL überhaupt läuft, kann man in /usr/local/mysql/bin: sudo -u _mysql ./mysqld ausführen.

MySQL doch in ein Vagrant umziehen

Jeff auf Stackoverflow hat mit seiner Frage „Pre-existing MySQL data with Vagrant / VirtualBox“ die gleiche Anforderung gehabt, wurde aber dort auf bessere Varianten verwiesen. Ich möchte es trotzdem in einer eigenen Box. Eine Box mit MySQL als einzigen relevanten Dienst ist mit Puppet-Unterstützung recht fix aufgesetzt, das Daten-Verzeichnis noch nach /var/mysql gemountet und los gehts. Der Start sudo service mysql start scheitert. Bei Boot-Problemen einfach mal ins upstart-Log schauen: sudo less /var/log/upstart/mysql.log. Per sudo -u vagrant mysqld meldet er komische Datei-Zugriffsprobleme. Obwohl die Gruppenschreibrechte auf /var/mysql korrekt sind und er mit dem Nutzer vagrant ganz normal alles machen könnte, meldet MySQL es könne keine Testdatei anlegen.

Generell gestaltete sich die Paketinstallation schwierig, die Post-Install-Scripte (apt-get install ... während der Provisionierung) sind immer wieder ohne erkennbaren Grund abgeschmiert. Eine kurze Recherche ergab, dass es wohl am RAM der Box liegt. Standardmäßig sind 512 MB verordnet, also flux auf 1024 MB angehoben in der Vagrantfile ..

config.vm.provider "virtualbox" do |vm|
  vm.memory = 1024
end

Siehe da, funktioniert besser. Die Einstellung bietet sich auch für die späteren Apaches an, da reagieren die zügiger, gerade auch im Debugging. Aber weiter mit MySQL.

Da der Vagrant unter dem eigenen Nutzeraccount läuft, muss zunächst der eigene Nutzer in die Gruppe _mysql, da das mysql/data Verzeichnis vom Mac MySQL den Besitzer _mysql:_mysql hat. Klar, kann man für das folgende umbiegen, muss man aber nicht. Ich nehme meinen Nutzer in die Gruppe _mysql auf.

sudo dseditgroup -o edit -a ronny -t user _mysql

User mysql wird Mitglied in Gruppe vagrant und umgekehrt:

sudo usermod -a -G mysql vagrant
sudo usermod -a -G vagrant mysql

Und vagrant soll auf /var/log schreiben können, was der Gruppe syslog gehört.

sudo usermod -a -G syslog vagrant
sudo usermod -a -G syslog mysql

Funktioniert leider nicht, immer noch Permission Fehler.

Der Tipp dass evtl. /etc/apparmor.d/local/usr.bin.mysqld fehlen würde, brachte auch nix. Also mal anders probieren. Kann man /var/mysql nicht als User mysql mounten? Ja geht mit VirtualBox als Provider:

config.vm.synced_folder "/Volumes/Daten/mysql", "/var/mysql", id: "mysql",
  owner: "mysql", group: "mysql",
  mount_options: ["dmode=775,fmode=664"]

Blöderweise ermittelt Vagrant beim Boot für Mount die User-ID und Gruppen-ID. Aber die gibts ja vor der Provisionierung nicht. Henne-Ei-Problem – aber in wiederkehrenden Umgebungen ists ja jedes mal gleich, also fixe IDs festgelegt (innerhalb der laufenden Box mit id mysql ermittelt):

config.vm.synced_folder "/Volumes/Daten/mysql", "/var/mysql", id: "mysql",
  owner: 108, group: 113,
  mount_options: ["dmode=775,fmode=664"]

Joar, geht auch vor Provisioning!
MySQL startet natürlich immer noch nicht – selber Senf mit Zugriffsrechten :(

Die Lösung fand ich dann hier – es war doch Apparmor, was verbietet, dass der Nutzer mysql ausserhalb von /var/lib/mysql agieren kann. Jetzt startet der MySQL im Vagrant! Meine my.cnf schaut nun so aus:

[mysqld]
user = mysql
port = 3306
datadir = /var/lib/mysql/vagrant
..

Noch flux den Zugriff von aussen für root eingerichtet:

GRANT ALL ON . to root@'10.0.2.2';
FLUSH PRIVILEGES;

10.0.2.2 ist bekanntlich die Gateway-IP, also die des Hosts (netstat -rn)
Nice!

SSH muss natürlich auf einen anderen Port nach aussen funken, als bei den PHP-Kisten. Die dürfen auf 2222 mappen, der MySQL aber auf 3322. Im Vagrantfile so:

config.vm.network :forwarded_port, guest: 22, host: 3322, id: "ssh"

Das id:"ssh" sorgt dafür, dass er SSH nicht doch per Default wieder auf 2222 mappt.

Die momentane Box-Konfiguration inkl. my.cnf ist bei Github im Projekt vagrant-mysql-shared-folder verfügbar.

[Update 16.11.2014] MySQL startete beim Boot nicht automatisch, bzw. wurde nach 3x mit „init: mysql respawning too fast, stopped“ vom Start ausgenommen. Ein dpkg-reconfigure mysql-server-5.5 behob allerdings das Problem.

Apache

Weiter gehts mit Webserver. Auf Basis der Vagrant-Puppets-Configs von jas0nkim’s my-vagrant-puppet-lamp gehts daran, Flechtie und dessen OXID-Onlineshop fitt zu machen. Das Modul mysql hab ich dabei entfernt (manifests/default.pp + modules/mysql).

Der MySQL ist vom Guest über dessen Gateway erreichbar (netstat -rn), bei mir 10.0.2.2. mysql -uroot -h10.0.2.2 zeigt das es funktioniert. Also dies flux in OXIDs-config eingetragen. Der Aufruf von localhost:8080 zeigt dann schonmal ein funktionierenden Shop, inkl. DB-Verbindung zum Host.

Nun muss noch der Aufruf von http://dev.flechtie.de/ direkt in die Vagrant-Box durchschlagen. Problem ist, dass man leider als Nicht-root-Nutzer unter Mac keinen Port >1024 forwarden darf.

Anleitung für Mac bis inkl. Maverick (ipfw)
Anleitung für Mac ab Yosemite (pf)

Bei mir mit Yosemite also so:
Datei /etc/pf.anchors/com.vagrant

rdr pass on lo0 inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
<leerzeile>

(Leerzeile am Schluss beachten, <leerzeile> weglassen!)

Datei /etc/pf.conf:

rdr-anchor "com.apple/*"
rdr-anchor "vagrant"
...
load anchor "com.apple" from "/etc/pf.anchors/com.apple"
load anchor "vagrant" from "/etc/pf.anchors/com.vagrant"
<leerzeile>

Und aktivieren:

sudo pfctl -f /etc/pf.conf
sudo pfctl -e

Schon zeigt http://dev.flechtie.de/ alles i.O. an.

[Update 19.11.2014] Leider kümmert das Mac beim Boot einen Sch**. Man muss mind. einmal manuell sudo pfctl -e nochmal ausführen damit es wieder klappt. Über Vagrant Trigger kann man das Port-Forwarding aber in die Vagrantfile aufnehmen und somit automatisieren – was Salvatore Garbesi in seinen Blogpost „Vagrant Port Forwarding On Mac“ aufgeschrieben hat.

Diese Einträge sorgen dafür:

config.trigger.after [:provision, :up, :reload] do
  system('echo "
rdr pass on lo0 inet proto tcp from any to 127.0.0.1 port 80 -> 127.0.0.1 port 8080
rdr pass on lo0 inet proto tcp from any to 127.0.0.1 port 443 -> 127.0.0.1 port 8443
" | sudo pfctl -f - > /dev/null 2>&1; echo "==> Fowarding Ports: 80 -> 8080, 443 -> 8443"')
end

config.trigger.after [:halt, :destroy] do
  system("sudo pfctl -f /etc/pf.conf > /dev/null 2>&1; echo '==> Removing Port Forwarding'")
end

Voraussetzung ist das Modul trigger – installiert mit vagrant plugin install vagrant-triggers. Dann können die Anpassungen an der pf.conf übrigens entfallen – schaden aber auch nicht.

Mounting als www-data mit Schreibrechten

So recht gefällt mir es nicht, dass das Verz. in der Box komplett vagrant:vagrant gehört. Besser wäre www-data:www-data, dann kann der Hack der /etc/apache/envvars in der vagrant/modules/apache/manifests/init.pp auch entfallen. Also getan und Box neu provisioniert (ggf. vagrant destroy & vagrant up)

Allerdings ist das www-Verzeichnis auf meiner Hostmaschine noch _www:_www, dem Standard-Apache-Nutzer auf dem Mac. So kann man leider innerhalb der Box dann nicht in die folder_sync-Dateien schreiben. Also flux meinen Nutzer mit in die Gruppe _www aufgenommen:

sudo dseditgroup -o edit -a ronny -t user _www

Sollten Dateien auf dem Host mit Recht 644 bzw. 755 und _www:_www vorhanden sein (gern z.B. tmp-Dateien bei OXID), dann chmod -R g+w tmp

Debugging mit xDebug

Damit das Debuggen mit PHPStorm wie vorher klappt war bissl basteln angesagt, und hauptsächlich die Erkenntnis, dass man den Host als Gateway-IP in den remote_host eintragen muss.

Folgende Zeilen in der php.ini müssen in der Box landen:

[xdebug]
xdebug.remote_enable = 1
xdebug.remote_host = "10.0.2.2"
xdebug.remote_port = 9000
xdebug.remote_handler = "dbgp"
xdebug.profiler_enable = 0
xdebug.profiler_enable_trigger = 1
xdebug.idekey = "vagrant"

Dann kann man im FF via Plugin easyXdebug das Debugging antriggern und im PHPStorm das Debugging einfach aktiveren (Telefonsymbol auf grün schalten).

Vagrant Manager

[Update 27.11.2014]
Vagrant bringt zwar ein paar Kommandozeilentools, aber so ein hübsches Klicki-Bunti-Tool für die Mac Systemzeile ist doch auch was. So sieht man gleich was es für Vagrant-Boxen gibt, und ob sie laufen, ob sie pausiert worden sind u.ä. … Vagrant Manager ist genau das! Das ganze ist Opensource auf GitHub verfügbar und die Leute da freuen sich über ein mittelkleine Spende.

Fazit

Insgesamt hat mich die Sache bislang einige Abende und einen ganzen Sonntag „gekostet“. Aber die Möglichkeiten der Verzinsung sind enorm! Die lokale Entwicklung nun endlich abgekoppelt vom Host-Betriebssystem ist – Windows statt Mac ist ohne Probleme möglich. Und ohne weiteres können neue Boxen zum Spielen und Lernen aufgesetzt werden. Da sind das fantastische PHP-Framework Laravel mit seiner offiziellen lokalen Entwicklungsumgebung Homestead (Projekt bei Github), oder auch ein Symfony (oder hier), ownCloud, ein NodeJS mit Redis und MongoDB (oder auch hier), oder auch Facebooks HHVM. Leider hab ich für appserver.io noch keine Vagrant Box gefunden, challenge accepted!

Fragen und Anregungen gerne via @rhflow_de oder als Kommentar hier.

Rausschmeißer

Lesespaß gibts noch hier beim PHPmagazin: PHP 5.4 und 5.5 mit Vagrant und Chef virtualisieren.