Wer in seiner Lieblingssprache eine Webapplikation zusammenklopfen und kostenlos veröffentlichen möchte, findet bei Heroku viel Komfort. Sogar ein eigener Webserver darf als Sprungbrett dienen.
Perl-Snapshot feiert Jubiläum!
Der erste Artikel der Perl-Snapshot-Reihe im Linux-Magazin erschien im Oktober 1997, also schließt sie diesen Monat das 15. Jahr ab. Der Autor bedankt sich für alle Leserzuschriften und freut sich auf weitere Anregungen.
In letzter Zeit hört man auf Konferenzen häufig das Wort “Polyglot” [2]: Passé sind die Tage, in denen Entwickler sich mit Tunnelblick auf eine Programmiersprache und ihr Ökosystem konzentrierten und Errungenschaften anderer Systeme mit rotem Kopf für überflüssig erklärten. Vielmehr spioniert der Ingenieur von Welt heute in den Foren der Konkurrenz, erkennt fortschrittliche Entwicklungen und adaptiert sie zum Einsatz in der bevorzugten Sprache oder dem Applikationsstack der Wahl. Auch die Hoster von Webapplikationen unterstützen diesen Trend und bieten ihre Dienste für unterschiedlichste Programmiersprachen und Runtime-Umgebungen an.
Alles schon eingebaut
So verfährt zum Beispiel der Applikationshoster Heroku.com. Er liegt eine Abstraktionsebene über Amazons AWS-Cloud, hat seine Plattform bewusst Sprachen-agnostisch aufgesetzt und unterstützt etwa ein Dutzend Programmiersprachen [3]. Der Entwickler entlässt seine Releases mit Hilfe des Revisionssystems Git in die Freiheit und findet sich losgelöst von den technischen Anforderungen realer Server. Dies erlaubt schnelle Entwicklungszyklen mit erstaunlich wenig administrativem Aufwand.
Listing 1 zeigt eine simple Webapplikation, die das Framework Mojolicious vom CPAN nutzt, das über einen eingebauten Webserver verfügt. Von der Kommandozeile mit dem Befehl »daemon« und einer Webadresse auf dem lokalen Rechner gestartet (Abbildung 1) übergibt es einem Browser den fest einkodierten Textstring (Abbildung 2).
Listing 1
myapp.pl
1 #!/usr/bin/env perl
2 use Mojolicious::Lite;
3
4 get '/' => {
5 text => "I'll be your server tonight." };
6
7 app->start;

Abbildung 1: Im Beispiel startet der Programmierer die Mojolicious-Applikation auf Port 8888 des lokalen Rechners.

Abbildung 2: Ergebnis im Browser: Das einfache Mojolicious-Skript erzeugt im Browser die gewünschte Ausgabe.
Um das Ganze im Internet auf einem Heroku-Server laufen zu lassen, sind nur wenige Schritte notwendig. Als Erstes muss der User sich bei Heroku mit einer E-Mail-Adresse kostenlos registrieren. Weitere Angaben entfallen. Bestätigt der User den Eingang der E-Mail, darf er ein Passwort setzen.
Das Kommandozeilentool “Heroku Toolbelt”, das sich unter Ubuntu Linux mit
wget -qO- https://toolbelt.heroku.com/install.sh | sh
herunterladen und installieren lässt, findet nach dem Aufruf von »heroku login« wie in Abbildung 3 die lokal verwendeten Public Keys und überträgt einen davon nach Bestätigung an den Heroku-Server.
Ab diesem Zeitpunkt kommuniziert der User mit dem Heroku-System, ohne das Passwort nochmals einzutippen. Weitere Public Keys für weitere Rechner zur Wartung bereits installierter Applikationen fügt er mit dem Werkzeuggürtel und dem Kommando »heroku keys:add« an.
Reisegepäck
Für eine Perl-Applikation benötigt Heroku die Dateien »Makefile.PL« sowie das Shellskript »Perloku« . Diese Dateien installieren die nötigen CPAN-Module und werfen den eingebauten Mojolicious-Server an. Listing 2 zeigt das Makefile. Das Shellskript »Perloku« enthält folgendes Kommando:
./myapp.pl daemon -l http://*:$PORT -m production
Zusammen mit dem vorher erwähnten Applikationsskript »myapp.pl« aus Listing 1 liegen beide in einem lokalen Verzeichnis, in dem der User jetzt ein Git-Repository mit »git init« anlegt. Die Befehlsfolgen »git add *« und »git commit« mit einem Commit-Kommentar zementieren die Version.
Die Perl-typische Datei »Makefile.PL« gibt das CPAN-Modul Mojolicious in der Version 3.05 als Abhängigkeit an. Mojolicious hingegen benötigt keine weiteren CPAN-Module. Folgendes Kommando schickt das Triplet jetzt an Heroku:
heroku create -s cedar --buildpack http://github.com/judofyr/perloku.git
Bei »buildpack« handelt es sich um einen auf Github abgelegten Adapter, der Heroku Perl-Applikationen mit Skripten schmackhaft macht. So sagt er Heroku, dass das Kommando zum Start der Applikation in »Perloku« zu finden ist. Im lokalen Git-Repository definiert das Kommando »heroku create« zudem eine im Git-Jargon so genannte Remote, die auf das Heroku-Repository zeigt. An dieses schickt der User den Code mit dem Kommando »git push heroku master« .
So schickt Git zuerst die drei Source-Dateien an Heroku, das dann die in »Makefile.PL« angegebenen CPAN-Module installiert und zum Start des handgestrickten Servers das Kommando in der Datei »Perloku« aufruft. Heroku ruft das Shellskript »Perloku« per Konvention mit der Environment-Variablen »PORT« auf, die auf den Port gesetzt ist, auf dem der in »myapp.pl« eingebaute Webserver auf eingehende Requests lauschen soll. Das Shellskript fügt den Wert in den Parameter für die Option »-l« ein und übergibt das Ganze an »myapp.pl« , das nun genau Bescheid weiß.
Abschließend spuckt Heroku die offizielle Webadresse der Applikation aus, im Beispiel ist das »http://hollow-fog-8976.herokuapp.com« . Ein Browser, der diese Adresse aufruft, zeigt das erwartete Ergebnis (Abbildung 4).
Listing 2
Makefile.PL
1 #!/usr/bin/env perl
2 use ExtUtils::MakeMaker;
3 WriteMakefile(
4 PREREQ_PM => {'Mojolicious' => '3.05'}
5 );
Grenzen testen
In der kostenlosen Version laufen die hochgeladenen Standalone-Server zwar durchgängig und speichern Daten im RAM-Speicher des Perl-Prozesses. Doch für Addons verlangt Heroku, den Account zu verifizieren, was derzeit nur durch Angabe einer gültigen Kreditkarte möglich ist. Beispiele für Addons sind Datenbanken zur persistenten Speicherung oder No-SQL-Lösungen wie Redis zur Kommunikation zwischen verschiedenen Instanzen, die besser skalieren.
Weiter ist zu beachten, dass Heroku die Prozesse nach einigen Stunden herunterfährt, falls die Requests ausbleiben. Trudeln neue Requests ein, starten die Prozesse wieder. Der Webkunde merkt das daran, dass die Webapplikation verzögert lädt, und der Entwickler daran, dass alle im flüchtigen Speicher gehaltenen Daten verloren sind.
Statt Mojolicious kann jedes vom CPAN installierbare Framework herhalten, so auch der asynchrone Baukasten “AnyEvent” mit seinem Standalone-Webserver »AnyEvent::HTTPD« . Listing 3 zeigt die Perl-Applikation, die den Webserver auf dem mit »-p« hereingegebenen Port startet, Requests von Webclients annimmt und mit dem gleichen, hart einkodierten Ausgabe-String beantwortet. Das leicht veränderte »Perloku« übergibt den von Heroku hereingereichten Port mit »-p« :
./myapp.pl -p $PORT
Die in Zeile 4 angepasste Datei »Makefile.PL« aus Listing 2 fordert nun ein anderes CPAN-Modul zur Installation an:
4 PREREQ_PM => {'AnyEvent::HTTPD' => '0.93'}
Statt eines statischen Strings liefert eine nützliche Applikation freilich lieber dynamische Daten zurück. So schickt sich Listing 4 an, die IP des Users anzuzeigen. Im verwendeten Mojolicious-Framework gibt die Methode »remote_address()« die IP-Adresse des Besuchers an. Die Methode verwendet dazu das von »tx()« gelieferte Objekt, das die Transaktionsdaten des Webrequests bereithält.
Listing 3
myapp.pl
01 #!/usr/bin/env perl
02 use AnyEvent::HTTPD;
03 use Getopt::Std;
04
05 getopts "p:", \my %opts;
06
07 my $httpd = AnyEvent::HTTPD->new(
08 port => $opts{ p } );
09
10 $httpd->reg_cb (
11 '/' => sub {
12 my ( $httpd, $req ) = @_;
13
14 $req->respond ( {
15 content => [ 'text/html',
16 "I'll be your server tonight." ]
17 } );
18 },
19 );
20
21 my $cv = AnyEvent->condvar();
22 $cv->recv();
Listing 4
myapp.pl (I)
01 #!/usr/bin/env perl
02 use Mojolicious::Lite;
03
04 get '/whatsmyip' => sub {
05 my( $self ) = @_;
06
07 $self->render( text =>
08 "Your IP is " .
09 $self->tx->remote_address() );
10 };
11
12 app->start;
Der Trick mit der IP
Abbildung 5 hält aber eine Überraschung bereit: Die dort angezeigte IP-Adresse liegt im Bereich 10.x.x.x und ist damit eine nicht routbare interne Heroku-Adresse. Sie offenbart, dass auf dieser Plattform magische Zwischenschichten agieren, bevor der Request bei der Applikation eintrifft. Die erweiterten Zeilen 07 bis 09 von »myapp.pl« aus Listing 4 zaubern die eigentlich gewünschte IP-Adresse des Besuchers hervor:
07 $self->render( text => 08 "Your IP is " . 09 $self->req->headers->header( 10 "x-forwarded-for" ) );
Denn wie sich nach einigem Experimentieren herausstellte, ist die Original-IP glücklicherweise noch im Header »x-forwarded-for« des eingehenden Requests verfügbar. Abbildung 6 zeigt das korrekte Ergebnis.
Geliehenes Superduo:PSGI und Plack
Jedes Mal, wenn eine Perl-Anwendung vom Entwicklungsserver auf einen Apache-Produktionsserver wandert, vergeudet das Zeit, weil »mod_perl« und »CGI.pm« Parameter unterschiedlich übergeben. Wer hat sich nicht schon gefragt, ob das sein muss? Muss es nicht. Die Schnittstelle PSGI und ihre Implementierung Plack [4] stammen aus dem Web-Ökosystem Rails um die Programmiersprache Ruby. Hier heißt das Interface WSGI und seine Implementierung Rack.
WSGI definiert eine einheitliche CGI-artige Schnittstelle zwischen beliebigen Webservern und Webapplikationen. Plack produziert den nötigen Superklebstoff, um jede PSGI-kompatible Webanwendung – inklusive Webframeworks wie Catalyst oder Dancer – unmodifiziert auf einem beliebigen Webserver laufen zu lassen. Voraussetzung ist nur, dass es einen PSGI-Adapter gibt. Mit eigenem Server entwickelter und getesteter Code läuft dann sowohl auf Apache 1 als auch auf Apache 2.
Listing 5 zeigt die fertig programmierte Applikation. Das zugehörige »Makefile.PL« aus Listing 6 zieht lediglich das CPAN-Modul Plack herein und Heroku startet den Server nach einem »git push« ohne viel Federlesen. PSGI erfordert ein denkbar simples Interface: Alle eingehenden Parameter kommen als Referenz auf einen Hash herein und die Applikation liefert eine Referenz auf einen Array mit Statuscode, Headern und schließlich mit dem Inhalt (Body) der Antwort. Das stellt sicher, dass für jeden Webserver mit einfachsten Mitteln ein passender Adapter programmierbar ist.
Das Modul Plack::Runner startet den in Plack enthaltenen Standalone-Webserver, sodass dieses Skript nach einem »git push« anstandslos auf Heroku.com läuft.
Listing 5
myapp.pl (II)
01 #!/usr/bin/env perl
02 use Plack::Runner;
03
04 my $runner = Plack::Runner->new;
05 $runner->parse_options( @ARGV );
06 $runner->run( sub {
07 my( $env ) = @_;
08
09 return [ 200,
10 [ "Contenat-type" => "text/html" ],
11 [ "Hello from Plack"]
12 ];
13 } );
Listing 6
Makefile.PL
1 #!/usr/bin/env perl
2 use ExtUtils::MakeMaker;
3 WriteMakefile(
4 PREREQ_PM => {
5 'PLACK' => '0.9969' }
6 );
Bereit zum Abheben
Infos
- Listings zu diesem Artikel:ftp://www.linux-magazin.de/pub/listings/magazin/2012/09/Perl
- Tatsuhiko Miyagawa, “Becoming a Polyglot”, YAPC::NA 2012:http://act.yapcna.org/2012/talk/142
- Heroku als “Polyglott Platform”:http://blog.heroku.com/archives/2011/8/3/polyglot_platform/
- Plack: http://search.cpan.org/dist/Plack










