Von einem, der auszog, das Kochen zu lernen

PHP 5.4/5.5 mit Vagrant und Chef virtualisieren
Kommentare

Der Einsatz von Virtualisierung bei der Entwicklung von PHP-Anwendungen etabliert sich langsam aber sicher zum Standard. Neben vielen Vorteilen bringt dies aber auch weitere Probleme mit sich. Vor allem die Verwaltung der virtuellen Maschinen gestaltet sich recht aufwändig. Der Einsatz von Vagrant und Chef verspricht Abhilfe und ermöglicht die Automatisierung und Reproduzierbarkeit virtueller Umgebungen.

Die PHP-Community hat vor einiger Zeit einen neuen Releaseprozess per Request for Comments (RFC) definiert. Ziel ist es unter anderem, Releases in kürzeren, und vor allem regelmäßigeren Abständen zu veröffentlichen. Neue Featurereleases soll es laut RFC in jährlichen Abständen geben, die drei Jahre lang unterstützt werden − zwei Jahre für Bugfixes und ein weiteres für Security Fixes. Mindestens jeden Monat soll es neue Bugfix-Releases geben – bei kritischen Sicherheitslücken sogar in kürzeren Abständen.

Kurze Releasezyklen

Für den PHP-Entwickler haben kürzere Releasezyklen vor allem den Vorteil, neue Features schneller nutzen zu können. Gleichzeitig wird der Migrationsaufwand für PHP-Anwendungen überschaubar gehalten. Um jedoch überhaupt die neue PHP-Version nutzen zu können, muss diese erst einmal in der entsprechenden Linux-Distribution zur Verfügung stehen. Nutzt man Shared oder Managed Webserver, muss zusätzlich noch der jeweilige Hosting-Provider die neue PHP-Version anbieten.

Vor allem diese Abhängigkeiten haben leider zur Folge, dass sich neuere PHP-Versionen nicht so schnell verbreiten, wie es sich die Community und viele Entwickler erhoffen. PHP-Anwendungen, -Bibliotheken und -Frameworks können daher nur sehr verzögert die neuen Features und Verbesserungen (Tabelle 1) nutzen. Auch wenn die aktuellen Linux-Distributionen und einige Hosting-Provider bereits PHP 5.4 anbieten, ist knapp zwölf Monate nach dessen Release immer noch PHP 5.3 als der De-facto-Standard auf den meisten Webservern verbreitet. Wie weit und wie schnell sich die kommende Version 5.5 verbreiten wird, ist aktuell noch nicht abzuschätzen.

Neuerungen in PHP 5.4

Neuerungen in PHP 5.5

Traits

Short Array Syntax/Array Dereferencing

Integrated Webserver

kein Safe Mode, Magic Quotes, Register Globals

Performance- und Speicheroptimierungen

Deprecated MySQL-Extension (Ext/MySQL)

Generators

Simplified Password Hashing API

Finally Statement beim Exception Handling

Performance- und Speicheroptimierungen

Tabelle 1: Wichtige Neuerungen in PHP 5.4 und 5.5

Laufzeitumgebung für neue PHP-Versionen

Will man eine neue PHP-Version testen, um eventuell eine PHP-Anwendung zu migrieren, setzt dies zunächst eine entsprechend konfigurierte Laufzeitumgebung voraus. Entweder ersetzt man die alte durch eine neu installierte PHP-Version – mit dem Nachteil, die Anwendung nicht mehr unter der alten Version laufen lassen zu können. Oder man verwaltet mehrere PHP-Versionen auf einem System, was jedoch mit entsprechend hohem Aufwand verbunden ist und unter Umständen weitere Probleme mit sich bringt.

Alternativ dazu kann eine virtualisierte Laufzeitumgebung verwendet werden. Bei der Entwicklung von Webanwendungen ist der Einsatz von Virtualisierung mittlerweile sehr verbreitet, da dies einige Vorteile mit sich bringt: Eine unabhängige Laufzeitumgebung erhöht die Flexibilität und führt zu weniger Beeinträchtigungen des Desktopsystems. Die Produktivumgebung lässt sich in einer VM annähernd identisch nachbilden. Projekte mit speziellen Anforderungen (z. B. unterschiedliche PHP-Versionen) lassen sich in mehreren VMs getrennt voneinander zum Laufen bringen. Der für eine Anwendung nötige Build-Prozess (Unit Tests, Benchmarks, Deployment) kann automatisiert getestet werden. Mithilfe von vorkonfigurierten VMs verringert sich der Einarbeitungsaufwand neuer Teammitglieder in das jeweilige Projekt.

Jedoch gibt es auch einige Nachteile, wovon einer der größten der höhere administrative Aufwand für die Installation, Konfiguration und Wartung der virtuellen Maschinen ist. Je mehr sich die Projekte voneinander unterscheiden (Nginx statt Apache, CouchDB statt MySQL, PHP 5.4 statt 5.3), umso mehr erhöht sich dieser Aufwand mit jeder weiteren VM. Änderungen lassen sich sehr schwer reproduzieren, da eine virtuellen Maschine wegen ihrer Größe nicht zusammen mit dem Projekt versioniert werden sollte. Damit dennoch alle Entwickler in einem Team möglichst auf dem gleichen Stand sind, müssen alle Änderungen an einer VM zentral verwaltet und bereitgestellt werden, was wiederum das Speicher- und Transfervolumen erhöht.

Virtualisierung leicht gemacht

Um Webentwicklern die Virtualisierung ihrer Entwicklungsumgebung deutlich zu erleichtern, wurde das Open-Source-Projekt Vagrant initiiert. Mit dessen Hilfe lassen sich virtuelle Maschinen einfach und schnell erstellen und verwalten. Basierend auf Oracles VirtualBox (weitere Virtualisierer sind geplant) stellt man alle für ein Projekt benötigten Komponenten in einer so genannten „Box“ zusammen.

Mittels der Konfigurationsdatei Vagrantfile kann man das Verhalten von Vagrant und der virtuellen Umgebung projektspezifisch anpassen und konfigurieren. Ein sehr einfaches Vagrantfile zeigt Listing 1. Dass sich aber auch komplexere Umgebungen, bestehend aus mehreren virtuellen Maschinen konfigurieren lassen, zeigt das später folgende Beispielprojekt.

Listing 1

Vagrant::Config.run do |config|
  config.vm.box = "precise64"
  config.vm.box_url = "http://files.vagrantup.com/precise64.box"
  config.vm.host_name = "my_box"
end

Obwohl ein Vagrantfile ein Ruby-Skript ist, sind keine speziellen Ruby-Kenntnisse erforderlich, da es sich hier lediglich um einfache Variablenzuweisungen handelt. Eine Liste aller Konfigurationsoptionen findet man in der Vagrant-Dokumentation. Alle Änderungen an einem Vagrantfile lassen sich mittels Versionskontrolle verwalten. Nachdem ein Entwickler das Projekt ausgecheckt hat, genügt ein einfaches Kommando vagrant up zum Starten der virtuellen Umgebung.

Der Ordner mit dem Vagrantfile (üblicherweise der Root-Ordner eines Projekts) wird in der virtuellen Umgebung mittels Shared Folder zur Verfügung gestellt. Innerhalb der VM ist dies der Ordner /vagrant (Mount Point), was jedoch per Konfiguration angepasst werden kann. Auf die Projektdateien kann sowohl außerhalb als auch innerhalb der VM lesend und schreibend zugegriffen werden.

Prinzipiell würde es genügen, sich ausschließlich auf diese Funktionalität von Vagrant zu beschränken. Man startet eine virtuelle Maschine basierend auf einer Base Box und installiert darin die jeweils benötigte Software. Diesen Zustand verpackt man mittels spezieller Vagrant-Kommandos in eine neue, projektspezifische Base Box. Diese Box stellt man dem Entwicklerteam auf einem zentralen Firmenserver zur Verfügung und referenziert diese im Vagrantfile. Der größte Nachteil dieser Vorgehensweise ist jedoch, dass eine Änderung innerhalb der virtuellen Maschine (z. B. durch Softwareupdates) das erneute Paketieren und Verteilen der Box bedingt.

Automatisierung nach Rezept

Vagrant bietet durch die Integration von Chef die Möglichkeit, Software innerhalb einer VM automatisiert zu installieren und zu konfigurieren (auch „Provisioning“ genannt). Chef ist ein freies, von der Firma Opscode entwickeltes System-Integration-Framework. Mithilfe einer ebenfalls auf Ruby basierenden Domain-specific Language (DSL) lassen sich Administrationsaufgaben abstrakt und plattformunabhängig beschreiben und mittels Versionskontrolle verwalten.

Chef lässt sich entweder standalone lokal in Form von Chef Solo nutzen oder auch in Form von Chef Server/Client. Beide Varianten werden von Vagrant unterstützt, wobei sich der Chef-Code auch unabhängig von Vagrant nutzen lässt, z. B. zur Automatisierung eines Produktivservers.

Eine wesentliche Chef-Komponente ist das so genannte „Cookbook“. Es dient der Organisation bestimmter Adminstrationsszenarien und bildet eine in sich abgeschlossene Einheit. Ein Cookbook besteht aus einem oder mehreren Recipes, kann aber auch andere Komponenten wie Attributes, Files oder Templates beinhalten. Um unterschiedliche Recipes verschiedener Cookbooks für einen bestimmten Anwendungszweck (z. B. einen Webserver) gruppieren zu können, stellt Chef so genannte „Roles“ zur Verfügung. In einer Role werden die benötigten Recipes und deren auszuführende Reihenfolge definiert. Ebenso lassen sich auch Attributes-Werte setzen bzw. überschreiben.

Vagrant und Chef im praktischen Einsatz

Doch genug der Theorie. Am besten lassen sich technische Dinge in der Praxis darstellen. Daher soll im Folgenden anhand eines kleinen Beispielprojekts (sehen

Sie dazu auch den gleichnamigen Kasten) dargestellt werden, wie man mit Vagrant und Chef eine virtualisierte PHP-Laufzeitumgebung verwaltet.

Beispielprojekt

Der gesamte Sourcecode zum Projekt steht auf GitHub [9] frei zur Verfügung. Details zum Projekt können der Datei README.md entnommen werden. Das Projekt verwendet Ubuntu Precise 64-Bit als Serverplattform und wurde darauf getestet.

Im Repository befinden sich zusätzlich folgende Branches, in denen das Projekt um neue Features ergänzt bzw. erweitert wurde:

  • lucid32
  • mysql
  • logging

Es kann sein, dass nach Erscheinen dieses Artikels weitere Branches hinzugefügt werden. Sollte es Probleme geben, steht es jedem Entwickler frei, dies per GitHub Issue oder Pull Request mitzuteilen.

Es soll PHP-Code, in diesem Fall lediglich eine sehr einfache PHP-Infoseite, sowohl unter PHP 5.4 als auch unter 5.5 ausgeführt werden. Dafür werden zwei virtuelle Maschinen mit identischem Software-Stack erstellt, lediglich die PHP-Binaries unterscheiden sich. Neben dem Betriebssystem Ubuntu 12.04 LTS (Precise Pangolin 64-Bit) kommt Nginx als Webserver zum Einsatz. PHP wird mittels FastCGI-Standard (php-fpm) angebunden und ausgeführt. Ein MySQL-Server wird der Einfachheit halber nicht verwendet.

Ubuntu Precise enthält leider nur PHP in der Version 5.3.10 als offizielles Installationspaket. Daher müssen die benötigten PHP-Versionen auf andere Art und Weise installiert werden. Für PHP 5.4 gibt es bereits ein sehr gutes PPA (Personal Package Archive) [10], das für die Installation verwendet wird. Da sich PHP 5.5 derzeit noch in der Entwicklung befindet, gibt es noch keine offizielle Paketquelle. Es wird direkt aus dem offiziellen Sourcecode [11] kompiliert und installiert.

Für das Provisioning kommt Chef Solo zum Einsatz. Es ist flexibel genug und einfacher zu verwenden, da kein spezieller Chef-Server installiert und verwaltet werden muss. Chef Solo läuft lokal in der virtuellen Maschine und bedingt daher, dass alle verwendeten Cookbooks auch lokal zur Verfügung stehen. Die Cookbooks (inklusive deren Abhängigkeiten) sind als Git-Submodule definiert, die vor dem Start von Vagrant und Chef initialisiert werden müssen.

Projektstruktur

Die Daten des Projekts werden in der in Listing 2 dargestellten Verzeichnisstruktur organisiert.

Listing 2

chef/
  cookbooks/
    apt/
      ...
    build-essential/
      ...
    git/
      ...
    nginx/
      ...
    php/
      ...
    php-magazin/
      attributes/
        default.rb
      files/
        default/
          ...
      recipes/
        default.rb
        ...
      templates/
        default/
          ...
      CHANGELOG.md
      metadata.rb
      README.md
  roles/
    php54.rb
    php55.rb
.gitignore
.gitmodules
index.php
README.md
Vagrantfile

Alle für Chef benötigten Daten sind unterhalb des Verzeichnisses chef abgelegt, getrennt von den restlichen Projektdaten. Cookbooks und Roles liegen ebenfalls getrennt voneinander in eigenen Verzeichnissen. Im Cookbook php-magazin werden alle projektspezifischen Aufgaben definiert, die nicht durch andere Cookbooks abgedeckt sind und zusätzlich ausgeführt werden sollen (z. B. das Setzen der Systemzeitzone). Theoretisch könnte man alle derartigen Aufgaben im Standard-Recipe default.rb sammeln. Jedoch hat es sich als sinnvoll erwiesen, für zusammengehörende Aufgaben eigene Recipes zu verwenden. Dies ist übersichtlicher und ermöglicht, die Funktionalität anderer Cookbooks zu ergänzen, ohne diese direkt anpassen zu müssen.

Chef erlaubt auf sehr flexible Weise, Attribute in unterschiedlichen Objekten (z. B. Cookbooks oder Roles) zu definieren. Der Typ eines Attributs und die Reihenfolge der Abarbeitung dieser Objekte bestimmen den endgültigen Wert des jeweiligen Attributs. In den Roles php54.rb und php55.rb werden alle VM-relevanten Attribute gesetzt und die Reihenfolge der jeweils auszuführenden Recipes festgelegt.

Nachdem alle nötigen Chef-Komponenten erstellt wurden, muss Vagrant mitgeteilt werden, wo diese Daten zu finden sind und wie diese verwendet werden sollen. Wie bereits weiter oben erwähnt, findet die gesamte Konfiguration für Vagrant in der Datei Vagrantfile statt (Listing 3).

Listing 3

Vagrant::Config.run do |config|
  # VM for PHP 5.4
  config.vm.define :php54 do |config_php54|
    config_php54.vm.box = "precise64"
    config_php54.vm.box_url = "http://files.vagrantup.com/precise64.box"
  
    config_php54.vm.host_name = "php54"
    config_php54.vm.forward_port 80, 8054

    config_php54.vm.provision :chef_solo do |chef|
      chef.cookbooks_path = "chef/cookbooks"
      chef.roles_path = "chef/roles"
      chef.add_role "php54"
    end
  end

  # VM for PHP 5.5
  config.vm.define :php55 do |config_php55|
    config_php55.vm.box = "precise64"
    config_php55.vm.box_url = "http://files.vagrantup.com/precise64.box"
  
    config_php55.vm.host_name = "php55"
    config_php55.vm.forward_port 80, 8055

    config_php55.vm.provision :chef_solo do |chef|
      chef.cookbooks_path = "chef/cookbooks"
      chef.roles_path = "chef/roles"
      chef.add_role "php55"
    end
  end
end

Es werden zwei virtuelle Maschinen (php54 und php55) definiert und konfiguriert. Beide VMs basieren auf der Base Box precise64. Wurde diese bisher noch nicht verwendet, so versucht Vagrant diese anhand der Option vm.box_url herunterzuladen. Nach dem Download speichert Vagrant diese Box lokal im Verzeichnis ~/.vagrant.d/boxes zwischen. Je mehr virtuelle Maschinen darauf basieren, umso mehr spart man dadurch zukünftig an Zeit und Bandbreite.

Standardmäßig konfiguriert Vagrant für eine virtuelle Maschine ein NAT-Interface (Network Address Translation) als primären Netzwerk-Controller. Der direkte Zugriff auf die Dienste innerhalb der Maschine ist dadurch zunächst erst einmal nicht möglich. Dafür bietet Vagrant das Feature Port Forwarding mittels der Option vm.forward_port an. Ein Nachteil des Port Forwarding ist, dass entsprechend identisch konfigurierte VMs nicht zeitgleich benutzt werden können. Die zuerst gestartete Maschine reserviert den Port exklusiv. Für alle anderen Maschinen müssten die Ports temporär angepasst werden. Alternativ dazu lassen sich mithilfe der Option vm.network andere Netzwerktypen (hostonly und bridged) konfigurieren.

Für das Provisioning mit Chef Solo bietet Vagrant verschiedene Konfigurationsoptionen an. Folgende Optionen sind für das Beispielprojekt relevant:

  • cookbooks_path
  • roles_path
  • add_role

Vagrant versucht die Chef-Cookbooks zunächst in einem Verzeichnis cookbooks relativ unterhalb des Verzeichnisses zu finden, in dem sich das Vagrantfile befindet. Um ein oder mehrere andere Verzeichnisse zu definieren, verwendet man die Option cookbooks_path. Für Roles gilt Ähnliches, jedoch lässt sich mit der Option roles_path nur ein Verzeichnis definieren. Vagrant verwaltet zum Ausführen von Recipes respektive Roles eine so genannte „Run List“ und bietet zum Hinzufügen dergleichen die Optionen add_recipe bzw. add_role an. Chef ermöglicht mit den Roles eine vergleichbare Funktionalität, daher wird für jede VM des Projekts nur eine einzige Role mittels add_role definiert (Listing 4).

name "php54"
description "Role for installing a PHP 5.4 runtime environment."

default_attributes({
  "php" => {
    "install_method" => "package_php54",
    "directives" => {
      "date.timezone" => "UTC",
      "short_open_tag" => "Off"
    }
  }
})

override_attributes({
})

run_list(
  "recipe[php-magazin]",
  "recipe[build-essential]",
  "recipe[apt]",
  "recipe[git]",
  "recipe",
  "recipe",
  "recipe[php-magazin::php]",
  "recipe[nginx]",
  "recipe[php-magazin::nginx]"
)

Alle relevanten Anforderungen sind nun mittels Chef und Vagrant konfiguriert und lassen sich per Versionsverwaltung speichern. Jedes Teammitglied kann mit folgenden Befehlen das Projekt auschecken und die virtuelle Entwicklungsumgebung starten:

$ git clone --recursive https://github.com/foobugs/php-magazin.git php-magazin $ cd php-magazin $ vagrant up

Ohne weitere Parameter startet der Befehl vagrant up alle im Vagrantfile konfigurierten VMs. Viele der Vagrant-Kommandos (siehe auch vagrant help) erlauben jedoch zusätzlich die Angabe einer bestimmten VM:

$ vagrant up php54 $ vagrant up php55

Um auf die Webserver der virtuellen Maschinen zuzugreifen, gibt man folgende URLs im Browser ein: http://localhost:8054 und http://localhost:8055.

Manchmal wird der direkte Shell-Zugriff innerhalb einer gestarteten, virtuellen Maschine benötigt, wofür das Kommando ssh zur Verfügung steht. Mit folgenden Befehlen kann man per SSH auf die Projekt-VMs zugreifen:

$ vagrant ssh php54 $ vagrant ssh php55

Vagrant konfiguriert dafür ein spezielles SSH Port Forwarding (Port 2222). Der Standardbenutzer vagrant identifiziert sich mit einem speziellen SSH-Key. Dieser Benutzer benötigt kein Passwort und hat innerhalb der VM sudo-Rechte. Weitere SSH-Konfigurationen lassen sich mit folgenden Kommandos anzeigen und in die eigene ~/.ssh/config übernehmen:

$ vagrant ssh-config php54 $ vagrant ssh-config php55

Um eine virtuelle Maschine zu beenden bzw. wieder zu starten, gibt es folgende Möglichkeiten:

  1. vagrant halt && vagrant up
  2. vagrant suspend && vagrant resume
  3. vagrant destroy && vagrant up

Mit halt und suspend bleiben alle in einer VM manuell durchgeführten Installationen und Konfigurationen erhalten. Mit destroy gehen derartige Änderungen verloren, da die VM komplett gelöscht wird. Daher sollte man für permanente Änderungen immer ein entsprechendes Chef Recipe erstellen und mittels Versionskontrolle speichern. Aktualisieren die Entwickler eines Teams ihr Projekt (z. B. mit git push), reicht dann ein einfaches vagrant reload, um diese Änderungen zu übernehmen.

Fazit und Ausblick

Bisher war die Verwaltung virtueller Umgebungen für Webentwickler mit mehr oder minder großem Aufwand verbunden. Der Einsatz von Vagrant und Chef ermöglicht jedoch, viele damit verbundenen Aufgaben sehr einfach zu automatisieren. Davon profitiert nicht nur der einzelne Entwickler, sondern das gesamte Team. Der Aufwand, neue Mitarbeiter einzuarbeiten, reduziert sich auf ein Minimum. Die gesamte Entwicklungsumgebung ist wesentlich flexibler und lässt sich reproduzierbar erweitern und anpassen.

Ein weiterer Vorteil: Alle verwendeten Werkzeuge sind als Open-Source-Software frei erhältlich und für den geschäftlichen Einsatz geeignet. Dies trifft auch bzw. vor allem für VirtualBox zu, das unter einem Dual-Lizenzmodell vertrieben wird (GNU General Public License V2 und Personal Use and Evaluation License). Wie der Lizenz-FAQ unter Frage 6 zu entnehmen ist, gilt sowohl der private als auch gewerbliche Gebrauch als „Personal Use“, vorausgesetzt, man installiert die Software selbst auf seinem Rechner.

In diesem Artikel wurde hauptsächlich die lokale, desktopbasierte Entwicklungsumgebung betrachtet. Vagrant und vor allem Chef sind jedoch auch dazu geeignet, in einer serverbasierten Test- bzw. Produktivumgebung eingesetzt zu werden. Dies soll das Thema für einen weiteren Artikel sein und in der folgenden Ausgabe des PHP Magazins beschrieben werden.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -