Google App Engine für PHP – erste Schritte mit Silex im SDK

Auf der diesjährigen Google I/O Konferenz 2013 hat Google vor einigen Tagen die Verfügbarkeit von PHP innerhalb der Google App Engine angekündigt. Bislang konnten Anwendungen innerhalb der Google App Engine ausschließlich in Python, Java oder Go entwickelt werden, wobei die Unterstützung von Go nach wie vor als experimentell gekennzeichnet ist. Nun kommt PHP hinzu – und eröffnet damit der meistbenutzten Programmiersprache im Web-Umfeld den Weg in die Google Cloud Infrastruktur.

Bis jetzt ist die Unterstützung von PHP ebenfalls noch in der Vorschau-Phase und damit auch limitiert, so dass jede Applikation explizit freigeschaltet werden muss. Nach welchen Kriterien Google diese Freischaltung vornimmt, weiß nur Google, ich habe vor einigen Tagen für eine minimale Anwendung die Freischaltung beantragt, bislang ist noch nichts geschehen. Google hat eine Web-Site eingerichtet, die als Einstieg für alle PHP-Interessenten dient. Neben den Hinweisen zur Freischaltung finden sich dort der Video-Mitschnitt der Google I/O sowie Links auf die bisher verfügbare Dokumentation.

Google Cloud – die App Engine für PHP

Die technischen Details werden im Vortrag genannt – grundsätzlich handelt es sich um die CGI-Variante von PHP, die gehärtet und minimal in die Laufzeitumgebung der Google App Engine angepasst wurde. Zudem sind einige Dienste verfügbar, die als PHP-Klassen implementiert wurden. Dazu gehören unter anderem die Einbindung von Google Cloud Storage, Mail, Memcache sowie der Google Account User-Authentifizierungsmechanismen. Besonders interessant für alle PHP-Anwendungen, die eine Datenbank voraussetzen, ist die Nutzung von Google Cloud SQL. Dabei handelt es sich um die Datenbank MySQL 5.5, die speziell zur Nutzung innerhalb der Google Cloud angepasst wurde. Zu den Highlights gehören neben der vollständigen Transparenz innerhalb der Google Cloud die automatische Replikation, die sogar mehrere geographische Regionen in mehreren Rechenzentren umfasst. Bei der Einrichtung lässt sich zwischen synchroner und asynchroner Replikation wählen. Damit stellt Google eine relationale Datenbank zur Verfügung, die um Merkmale der unter der NoSQL-Flagge segelnden Produkte ergänzt wurde.

Das App Engine SDK

Zur lokalen Entwicklung und Anpassung eigener Anwendungen an die Google App Engine für PHP bietet Google das App Engine SDK zum Download an. Die Voraussetzungen werden ausführlich in der Dokumentation beschrieben, neben PHP als CGI-Variante benötigt das SDK Python in einer aktuellen Version. Die Einrichtung beschränkt sich auf das Entpacken des SDK. Python sollte im Pfad vorhanden sein, da es zum Start der lokalen Laufzeitumgebung benötigt wird. Für erste Tests empfiehlt es sich, der „Getting started“-Dokumentation zu folgen, dabei wird Hello, World zum Laufen gebracht.

Als Entwickler sollte einem klar sein, dass sich die PHP-Versionen der Google App Engine und der lokalen Umgebung unterscheiden. Insbesondere sind im Produktivsystem unter Umständen nicht alle PHP-Extensions verfügbar, die in der lokalen Variante eingebunden sind. Einen ersten Einblick gibt das bereits zitierte Video, in dem die verfügbaren PHP-Module kurz genannt werden.

Silex – Ihr Auftritt!

Für die ersten Schritte – und vielleicht erste produktive Anwendung – habe ich mir meine momentan in Entwicklung befindliche Web-Site von geschke.net auserkoren. Zwar ist diese minmal gehalten und benötigt genaugenommen nicht einmal PHP, aber im Hintergrund ist inzwischen einiges passiert. Da mir ein CMS viel zu mächtig erschien, und ich mich gerne wieder mit neueren Technologien, insbesondere Frameworks beschäftigen wollte, fiel meine Wahl auf das Silex Micro-Framework, was auf Symfony2-Komponenten aufsetzt. Zwar ist dies immer noch ein wenig oversized, aber auch gedacht als Grundlage weiterer Anwendungen. Die Komponenten für ein Admin-Tool inkl. User-Verwaltung sind bereits fertig, ebenso weitere, hier nicht näher bezeichnete Module, darüber hinaus dient es zu Experimenten, um beispielsweise ad hoc eine Videoplayer-Seite zu erstellen.

Die Verzeichnisstruktur wird teilweise von Silex vorgegeben, zudem finden sich Hinweise auf eine empfohlene Struktur. Der Verzeichnisinhalt des Hauptordners sieht wie folgt aus:

/data/
/includes/
/src/
/vendor/
/views/
/web/
composer.json
composer.lock
composer.phar

Im Verzeichnis data liegen einige Dumps der Datenbank. Diese sind nicht für den Betrieb notwendig, sondern dienen zur Initialisierung bei einem möglichen neuen Deployment. Das Verzeichnis includes ist ein Überbleibsel aus alten Tagen, inzwischen findet sich hier nur noch die recaptchalib.php, die manuell eingebunden wird. Im Verzeichnis src sind die eigenen Klassen bzw. Dateien zu finden, dazu gehören die initiale bootstrap.php, app.php sowie im Namespace Geschkenet die eigentlichen Module.
Angesichts des modernen Paketmanagements mittels Composer ist die Erstellung des passenden Autoloaders kein Problem mehr. Die grundlegende Verwendung von Composer inkl. Installation von Silex sind der Silex-Dokumentation zu entnehmen. Um die eigenen Module bzw. den Namespace zu erreichen, habe ich folgende Zeilen hinzugefügt:

  "autoload": {
        "psr-0": {
            "Geschkenet": "src/"
        }
    }

Damit wird dem Autoloader mitgeteilt, dass im Verzeichnis src der Namespace Geschkenet zu erreichen ist.

Das Verzeichnis views beinhaltet die Twig-Templates in einer zur Anwendung passenden Struktur. Zuletzt sind im Verzeichnis web alle von außen erreichbaren Dateien und Verzeichnisse vorhanden, d.h. JavaScript, CSS, Bilder sowie der minimale Front-Controller index.php, der nur noch aus zwei Zeilen besteht:

$app = require __DIR__ . '/../src/app.php';
$app->run();

Im Webserver wird das Document Root auf dieses Verzeichnis gelenkt und dafür gesorgt, dass alle Requests, die keine Entsprechung im Dateisystem haben (CSS, JavaScript, Bilder), auf die Datei index.php erfolgen.

Betrieb in der Google App Engine Laufzeitumgebung

Bis hierhin wurde noch keine App Engine spezifische Konfiguration beschrieben. Um den Zugriff auf Dateien und Verzeichnisse innerhalb der Google App Engine zu regeln, wird eine Datei app.yaml benötigt, die im Hauptverzeichnis der jeweiligen Anwendung liegt. Für das beschriebene Beispiel sieht die app.yaml wie folgt aus:

application: geschkenet
version: 1
runtime: php
api_version: 1

handlers:
- url: /css
  static_dir: web/css

- url: /js
  static_dir: web/js

- url: /img
  static_dir: web/img

- url: /.*
  script: web/index.php

Die ersten Zeilen beschreiben den Namen der Anwendung, deren Version, die verwendete Laufzeitumgebung sowie deren Version. Interessanter wird es im Bereich „handlers“, dort findet das Mapping von URL auf Dateien und Verzeichnisse statt. Die Syntax ist selbsterklärend – die drei Verzeichnisse css, js und img, die sich im Verzeichnis web befinden, werden jeweils sichtbar gemacht und sind so ansprechbar, als würden sie im Document Root liegen.

Der letzte Eintrag beschreibt den Zugriff auf den Front-Controller. Analog zur beschriebenen Web-Server-Konfiguration werden alle Requests auf die index.php-Datei geleitet.

Damit ist die Konfiguration auch schon fertig und erste Tests können innerhalb der lokalen Laufzeitumgebung stattfinden. Zum Start dient das Skript dev_appserver.py aus dem SDK. Im Beispiel liegen im Verzeichnis geschkenet_appengine alle oben beschriebenen Inhalte.

C:\Users\geschke\google_appengine> dev_appserver.py --log_level=debug --php_executable_path=C:\xampp\php\php-cgi.exe geschkenet_appengine

Nach wenigen Sekunden ist der Web-Server startbereit. Die Laufzeitumgebung der App Engine steht unter http://localhost:8000 zur Verfügung, die eigentliche Anwendung unter http://localhost:8080. Weitere Optionen lassen sich mittels dev_appserver.py –help herausfinden,

Kleinere Hürden und Lösungen

Tatsächlich waren die ersten Schritte derart einfach. Eine Hürde, die mir zunächst den Zugriff auf die CSS- und JavaScript-Dateien verwehrt hatte, waren fehlerhafte Angaben innerhalb static_dir in der app.yaml. Dort darf kein führender Slash enthalten sein, es muss darin etwa „web/css“ heißen, und nicht „/web/css“.

Weitere Änderungen waren – so schien es anfangs – nicht nötig. Jedoch beinhaltet die Anwendung einen geschützten Admin-Bereich, der auf dem Security-Provider von Silex basiert. Die Authentifizierung erfolgt klassisch via Login-Formular, die eingegebenen Daten werden mit den in der Datenbank gespeicherten User-Daten verglichen, bei Erfolg wird der User in der Session gespeichert usw., was eigentlich dem üblichen Verfahren entspricht. Nur genau dies funktionierte zunächst nicht. Die Ursache lag nicht, wie anfangs vermutet, im Zugriff auf die Datenbank. Um eine möglichst ähnliche Umgebung zur später verwendeten Google Cloud SQL zu schaffen, hatte ich die Tabellen aus SQLite in eine MySQL-Datenbank überführt. Diese Daten konnten jedoch problemlos gelesen werden. Nur endete der Request nach Abschicken des Login-Formulars immer wieder auf genau diesem.

Die Lösung lag in der Speicherung der Sessions. Silex nutzt, sofern nichts Anderes konfiguriert wurde, den NativeFileSessionHandler. Wie der Name es vermuten lässt, werden die Session-Daten dabei in Dateien gespeichert. Ganz im Gegensatz dazu nutzt die Google App Engine bereits standardmäßig Memcache für die Session-Daten. Alernative Methoden, z.B. Google Cloud SQL, können verwendet werden. Zur Speicherung von Dateien muss hingegen der Google Cloud Storage Dienst verwendet werden, wofür ebenfalls eine PHP-API zur Verfügung steht. Hier gab es insofern einen Konflikt in den Default-Einstellungen von Silex und Google App Engine. Wie ein Blick in die jeweils aktuell gesetzten Cookies verriet, wurde für jeden Request eine neue Session-ID angelegt, da keine Speicherung erfolgte.

Die notwendige Änderung ist bereits in der Silex-Dokumentation skizziert. Mit der folgenden Zeile wird der NativeFileSessionHandler deaktiviert:

$app['session.storage.handler'] = null;

Dies führte umgehend zum Erfolg – das Einloggen in den Admin-Bereich war kein Problem mehr. Dass nun der Memcache-Dienst verwendet wurde, bestätigte ein Blick in die Web-Oberfläche der Laufzeitumgebung.

Weitere Änderungen waren nicht notwendig – die Anwendung läuft nun in der lokalen Umgebung des App Engine SDK problemlos. Vor dem Deployment in die Google Cloud muss nur noch die Datenbank-Verbindung angepasst werden, statt der lokalen MySQL wird dann Google Cloud SQL verwendet. Die entsprechende Datenbank hatte ich zuvor eingerichtet und der Applikation den Zugriff gestattet. Zur Administration bietet Google eine recht rudimentäre Oberfläche an, die nicht zu vergleichen ist mit PHPMyAdmin, jedoch für das initiale Anlegen der Datenbank bzw. Tabellen genügt.

Deployment

Das Deployment in die Google Cloud Umgebung erfolgt mittels Aufruf eines weiteren Skriptes:

appcfg.py update -R --runtime=php geschkenet_appengine/

Da jedoch die Freischaltung zwingende Voraussetzung ist, ist dies bislang für mich noch reine Theorie. Es bleibt zu hoffen, dass Google die Applikation bald der Whitelist hinzufügt, so dass sich herausfinden lässt, wie sich die Google Cloud in der Realität „anfühlt“. Die Anpassung beschränkte sich bislang auf minimale Änderungen, so dass einem produktiven Betrieb nichts mehr im Wege stehen sollte. Spezielle Dienste der Google Cloud wie Mail, Task Queues oder die User API verwendet die Anwendung im Augenblick nicht. Ebenso werden keine „exotischen“ PHP-Extensions eingesetzt, die einem Betrieb in der App Engine entgegen stehen würden.

Fazit

Bei allen positiven Eindrücken darf nicht vergessen werden, dass Google seine Services nicht verschenkt. Google Cloud SQL ist bislang in einer noch kostenlosen Testphase, danach werden auch für die kleinste Instanz Gebühren verlangt. Google sorgt für Transparenz und bietet eine Übersicht inklusive Beispiel-Rechnungen an. Bei der App Engine gab es bislang ein kostenloses Kontingent, bezogen auf eine Vielzahl von Parametern, darüber hinaus müssen die Dienste bezahlt werden. Dabei lohnt genaues Rechnen – möglicherweise kommen auch andere PaaS-Dienstleister in Betracht, falls die „Cloud“ zwingende Voraussetzung ist – oder vielleicht genötigt soar ein günstiger virtueller Server beim Massenprovider. Oder eine geschickte Kombination der inzwischen zur Verfügung stehenden Technologien.

Aber erstmal bin ich jetzt neugierig auf die App Engine für PHP – Google, lass mich bitte rein! 😉

Update, 12.06.2013:

Google hat mich endlich erhört und die Applikation freigeschaltet! Yeah! Ein kleines Problem gab es noch beim Deployment, und zwar in der app.yaml.

Der Eintrag für den Frontend-Controller lautete:

- url: /.*
  script: /web/index.php

Auf dem Entwicklungssystem mit dem SDK unter Windows lief dies problemlos, jedoch nicht unter Linux, und somit auch nicht im Live-Betrieb.

Korrekt wäre:

- url: /.*
  script: web/index.php

Der führende Slash in der „script:“-Zeile musste entfernt werden. Danach erfolgte das Deployment wie oben beschrieben. Nach kurzer Zeit war die Applikation bereits verfügbar. Der Mailversand funktioniert noch nicht, eine Lösung folgt demnächst.

Der bisherige Eindruck – es macht Spaß, sich mit einer völlig anderen Laufzeitumgebung als unter Apache bzw. Nginx zu beschäftigen. Und ich bin gespannt, wie es weiter geht.

Schreibe einen Kommentar

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

Tags:
Kategorien: PHP Programmierung