Wer schnell eine Web-Applikation zusammenklopfen und kostenlos im Netz veröffentlichen möchte, findet bei Heroku ein komfortables System, bei dem man sogar seinen eigenen Webserver mitbringen darf.
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 roten Kopfes vom Tisch fegten. Vielmehr spioniert der Ingenieur von Welt heute gern in den Foren der Konkurrenz, erkennt fortschrittliche Entwicklungen und adaptiert sie zum Einsatz in der bevorzugten Sprache oder Applikations-Stack.
Auch moderne Hoster von Web-Applikationen verschließen sich diesem Trend nicht und bieten ihre Dienste für unterschiedlichste Programmiersprachen und Runtime-Umgebungen an. So zum Beispiel auch der Service auf heroku.com ([3]), der eine Abstraktionsebene über Amazons AWS-Cloud aufsetzt. Er hat seine Plattform bewußt sprach-agnostisch aufgesetzt und bietet Support für etwa ein Dutzend Programmiersprachen an. Der Entwickler entlässt seine Releases mittels 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 Web-Applikation, die das Framework
Mojolicious vom CPAN nutzt, das gleich einen Standalone-Webserver
eingebaut hat. Von der Kommandozeile mit dem Befehl daemon
und einer
Webadresse auf dem lokalen Rechner gestartet wie in Abbildung 1, übergibt
es einem Browser wie in Abbildung 2 den fest einkodierten Textstring.
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: Die Mojolicious-Applikation startet auf Port 8888 des lokalen Rechners. |
Abbildung 2: Das einfache Mojolicious-Skript erzeugt im Browser die gewünschte Ausgabe. |
Um das Ganze im öffentlichen Internet auf einem Heroku-Server laufen zu lassen, sind nur wenige weitere Schritte notwendig. Als erstes muss der User sich kostenlos bei Heroku mit einer Email-Adresse registrieren, weitere Angaben entfallen (Abbildung 3). Bestätigt der User den Eingang der Email, 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 4 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
ein weiteres Mal tippen zu müssen. Weitere Public Keys für weitere Rechner
zur Wartung bereits installierter Applikationen lassen sich mit dem
Werkzeuggürtel und
dem Kommando heroku keys:add
anfügen.
Abbildung 3: Heroku bietet einen kostenlosen Account bei Hinterlegung der Email-Adresse. |
Abbildung 4: Das Kommandozeilen-Tool heroku des "Heroku Toolbelt" loggt den User ein. |
Für eine Perl-Applikation benötigt Heroku noch die
Dateien Makefile.PL
und Perloku
in Listing 2 und 3, um die nötigen CPAN-Module zu installieren, und den
eingebauten Mojolicious-Server des Users anzuwerfen. Zusammen mit
dem vorher erwähnten Applikationsskript myapp.pl
aus Listing 1
liegen sie allesamt in einem lokalen
Verzeichnis, in dem der User dann ein Git-Repository mit git init
anlegt. Die Befehlsfolge git add *
und git commit
mit einem
Commit-Kommentar zementiert die Version fest.
Die Perl-typische Datei Makefile.PL gibt das CPAN-Modul Mojolicious in der Version 3.05 als Abhängigkeit an. Mojolicious selbst ist in sich komplett, benötigt also keine weiteren CPAN-Module.
1 #!/usr/bin/env perl 2 use ExtUtils::MakeMaker; 3 WriteMakefile( 4 PREREQ_PM => {'Mojolicious' => '3.05'} 5 );
1 #!/bin/sh 2 ./myapp.pl daemon -l http://*:$PORT -m production
Um das Triplet an Heroku zu schicken, ruft der User das Kommando
heroku create -s cedar \ --buildpack http://github.com/judofyr/perloku.git
auf. Beim angegebenen buildpack
handelt es sich um einen auf Github
abgelegten Adapter, der Heroku Perl-Applikationen mittels einiger
Skripts schmackhaft macht. Es definiert unter anderem, dass Heroku
das Kommando zum Start der Applikation in der Datei Perloku
findet.
Im lokalen Git-Repository definiert das Kommando heroku create
außerdem eine im Git-Jargon so genannte Remote,
die auf Herokus Git-Repository zeigt, an das der
der User den Code und eventuell fällige Updates mittels
git push heroku master
schickt. Abbildung 5 zeigt die Ausgabe dieser Kommandozeile.
Abbildung 5: Schiebt der User die Applikation in ein Git-Repo auf Heroku, rollt das neue Release automatisch aus. |
Zuerst schickt
Git die drei Source-Dateien an Heroku, welches 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 Shell-Skript Perloku
per Konvention
mit der Environment-Variablen PORT auf, die
auf den Port gesetzt ist, auf dem der in myapp.pl
eingebaute
Webserver auf eingehenden Requests lauschen soll. Das Shell-Skript
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 in Abbildung 5
die offizielle Web-Adresse der Applikation aus
(im Beispiel http://hollow-fog-8976.herokuapp.com)
und ein darauf eingenordeter Browser zeigt das erwartete Ergebnis
(Abbildung 6).
Abbildung 6: Das einfache Hello-Skript läuft nun im offenen Internet auf einem Heroku-Server. |
In der kostenlosen Version laufen die hochgeladenen Standalone-Server zwar durchgängig und speichern Daten im RAM-Speicher des Perl-Prozesses, doch für sogenannte "Add-Ons" wie Datenbanken zur persistenten Speicherung oder NoSQL-Lösungen wie Redis zur Kommunikation zwischen verschiedenen Instanzen zur besseren Skalierung verlangt Heroku eine "Verifizierung" des Accounts, was derzeit nur durch Angabe einer gültigen Kreditkarte möglich ist. Weiter ist zu beachten, dass Heroku die Prozesse nach einigen Stunden herunterfährt, falls die Requests ausbleiben und sie wieder hochfährt, falls neue Requests eintrudeln. Dies merkt der Webkunde durch Verzögerungen beim Laden der Web-Applikation und der Entwickler durch den Verlust aller im flüchtigen Speicher gehaltenen Daten.
Statt Mojolicious kann jedes beliebige vom CPAN installierbare Framework
herhalten, so auch der asynchrone Baukasten AnyEvent mit seinem
Standalone-Webserver AnyEvent::HTTPD. Listing 4 zeigt die Perl-Applikation,
die den Webserver auf dem mit -p
hereingegebenen Port startet,
Requests von Webclients entgegennimmt und mit dem gleichen hart
einkodierten Ausgabe-String beantwortet.
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 5 und 6 zeigen die entsprechend
angepassten Dateien Makefile.PL
und Perloku
, die nun ein
anderes CPAN-Modul zur Installation anfordern und den von Heroku
hereingereichten Port mit -p
übergeben.
1 #!/usr/bin/env perl 2 use ExtUtils::MakeMaker; 3 WriteMakefile( 4 PREREQ_PM => { 5 'AnyEvent::HTTPD' => '0.93', 6 } 7 );
1 #!/bin/sh 2 ./myapp.pl -p $PORT
Statt eines statischen Strings sollte eine nützliche Applikation
freilich lieber dynamische Daten zurückliefern, und so schickt sich
Listing 7 an, die IP des Users anzuzeigen. Im verwendeten
Mojolicious-Framework gibt die Methode remote_address()
des
mittels tx()
erhältlichen Transaktions-Objektes des Requests
die IP-Adresse des Besuchers an.
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;
Abbildung 7 hält jedoch eine Überraschung bereit: Die dort angezeigte IP-Adresse ist im Bereich 10.x.x.x und damit eine nicht-routbare interne Heroku-Adresse, die offenbart, dass auf dieser Plattform magische Zwischenschichten agieren, bevor der Request bei der Applikation eintrifft.
Abbildung 7: Heroku zeigt statt der IP-Adresse des Besuchers eine interne IP-Adresse. |
Wie sich nach einigem Experimentieren herausstellte, ist die
Original-IP glücklicherweise noch im Header x-forwarded-for
des eingehenden
Requests verfügbar, und Listing 8 zaubert sie hervor, sodass Abbildung
8 sie korrekt anzeigt.
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->req->headers->header( 10 "x-forwarded-for" ) ); 11 }; 12 13 app->start;
Abbildung 8: Über den Header x-forwarded-for berichtet Heroku nun die richtige IP-Adresse. |
Aus dem Web-Ökosystem Rails der Programmiersprache Ruby stammt die
Schnittstelle PSGI und die Implementierung Plack ([4]).
Dort heißt das Interface
WSGI und die Implementierung Rack und definiert eine einheitliche
CGI-artige Schnittstelle zwischen beliebigen Webservern und Web-Applikationen.
Wer hat sich nicht schon gefragt, warum jedes Mal, wenn eine Perl-Applikation
von einem praktischen Standalone-Entwicklungsserver aus Performancegründen
auf einen Apache-Produktionsserver übertragen wird, Entwicklungszeit
vergeudet wird, weil mod_perl
und CGI.pm
Parameter unterschiedlich
übergeben? Plack produziert den nötigen Superklebstoff, um jede
PSGI-kompatible Web-Applikation (inklusive Web-Frameworks wie
Catalyst oder Dancer) unmodifiziert auf jedem beliebigen
Webserver laufen zu lassen, für den es einen PSGI-Adapter gibt. Code, der
mit einem Standalone-Server wie Mojolicious enwickelt und
getestet wurde, läuft dann auf Apache1 wie auf Apache2.
Listing 9 zeigt die fertig programmierte Applikation. Das zugehörige
Makefile.PL
zieht lediglich das CPAN-Modul Plack
herein und
Heroku startet den Server nach einem git push
ohne viel Federlesens.
Zu sehen ist, dass PSGI ein denkbar simples Interface erfordert: Alle
eingehenden Parameter kommen als Referenz auf einen Hash herein und
die Applikation liefert eine Referenz auf einen Array mit Status Code,
Headern und schließlich dem Inhalt (Body) der Antwort. So ist sichergestellt,
dass für jeden denkbaren Webserver mit einfachsten Mitteln ein passender
Adapter programmierbar ist.
Das Modul Plack::Runner wirft den in Plack enthaltenen Standalone-Webserver
an, so dass auch dieses Skript nach einem git push
anstandslos auf
heroku.com läuft.
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 [ "Content-type" => "text/html" ], 11 [ "Hello from Plack"] 12 ]; 13 } );
Die Sprache Perl erlebt in letzter Zeit erstaunlicherweise wieder ein Come-Back in der Hoster-Szene: Nicht nur Heroku unterstützt Perl, sondern unter anderem auch die Firmen Dotcloud, Juju, Openshift und Stackato.
Und noch ein Hinweis in eigener Sache: Der erste Artikel der Perl-Snapshot-Reihe im Linux-Magazin erschien im Oktober 1997, also schließen wir diesen Monat das 15. Jahr ab! Ich bedanke mich für alle Leserzuschriften und freue mich auf weitere Anregungen.
Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2012/09/Perl
Tatsuhiko Miyagawa, "Becoming a Polyglot", YAPC::NA 2012
"Polyglot Platform", Heroku Blog, http://blog.heroku.com/archives/2011/8/3/polyglot_platform/
"Plack", der Superklebstoff für Webapplikationen in Perl: http://search.cpan.org/dist/Plack