Play Anwendungen mit Docker & AWS Beanstalk in die Cloud bringen

Martin Eigenbrodt

Einleitung

Play ist ein Vertreter der HTTP nahen, requestbasierten Webframeworks. In Gegensatz zu komponentenbasierten Frameworks (wie z.b. JSF) versucht es nicht den HTTP Requests- und Responsezyklus hinter einer Abstraktion zu verstecken. Es gibt keinen Automatismus der z.B. den Zustand von Formularen serverseitig vorhält.

Durch den Verzicht auf serverseitigen Zustand lassen sich solche Applikationen leicht horizontal skalieren. Es liegt also nahe sie in einer elastischen Umgebung zu betreiben, die in der Lage ist je nach Last Server hinzuzufügen und zu entfernen. In diesem Artikel verwende ich Amazons Elastic Beanstalk um auf einfache Weise eine Play-Anwendung hochverfügbar zu deployen.

Docker

Docker ist eine relative junge Open Source Software die Anwendungen in Container verpackt. Solche Container enthalten alle Abhängigkeiten der Anwendung. Docker ist dabei einerseits eine leichtgewichtige Alternative zur Virtualisierung: Jeder Container führt im wesentlichen nur einen Process aus. Die Isolation wird durch CGroups, Namespaces und das Overlay Dateisystem AuFS erreicht. Die andere Leistung von Docker besteht in der Standarisierung des Containers. Einmal erstelle Container können ohne Veränderung auf dem Entwicklerrechner genauso wie in verschiedenen virtuellen oder Cloudumgebungen laufen.

Beanstalk

Elastic Beanstalk (EB) ist ein Platform as a Service Angebot von Amazon. Als Abstraktionsschicht oberhalb von EC2, S3 und anderer Amazon Web Services vereinfacht es das Deployment von Webanwendungen. Beanstalk ermöglicht für diese Anwendungen automatisiertes Deployment und automatische Skalierung.

Wie für PaaS üblich konnte Beanstalk ursprünglich nur sehr spezifische Applikationsformate deployen: Neben WAR-Files auf einen Tomcat waren das Ruby, PHP und Python, .Net und später Node.js Anwendungen. Seit April 2014 können auch Docker Container verwendet werden. Daher kann man nun jede Webanwendung deployen, für die man einen Docker Container bereitstellt. Das macht auch den Weg für Play auf diese Plattform frei.

Dabei führt Beanstalks allerdings nur einen Docker Container auf jeder EC2 Instanz aus. Die Möglichkeit mit Docker Containern die vorhanden Resourcen auszureizen wird daher nicht ausgereizt.

Docker Container in Beanstalk deployen

Es gibt drei Möglichkeiten einen Docker Container in elastic Beanstalks zu deployen.

Aus einem Dockerfile

Falls ein standard Dockerfile genügt, um den Container zu erstellen, kann dieses direkt verwendet werden. Das Dockerfile wird dazu über die Weboberfläche oder ein Kommandozeilenzool zu Beanstalk hochgeladen. EB baut aus dem Dockerfile einen Container und verwendet automatisch den ersten veröffentlichten (“Exposed”) Port des Containers um Http Request zu bearbeiten.

Sobald aber auf ein privates Docker-Repository zurückgegriffen werden soll, zum Bau des Images lokale Dateien nötig sind oder bestimmte Volumes gemounted werden sollen, funktioniert das nicht mehr. In der Dokumentation bei Amazon gibt es ein Beispiel Dockerfile, das das Spiel “2048”" als Webanwendung deployed.

Verwendung eines Dockerrun.aws.json

Bei dieser Variante wir ein AWS spezifischen json file verwendet. EB wertet es aus und lädt das darin referenzierte Image aus einer Docker Registry. Diese Registry kann private sein, in diesem Fall müssen Authorisierungsinformationen in einem verlinktem S3 Objekt abgelegt werden. Das JSON file erlaubt darüberhinaus Einfluss auf die gemappten Ports und Volumes.

ZIP

Für diese mächtigste Option verpackt man das Dockerfile und optional ein Dockerrun.aws.json Datei und beliebige statische Dateien (den “Docker Context”) in ein Zip. Beanstalk entpackt das Zip baut das Dockerfile im resultierenden Verzeichnis.

Ich verwende in diesem Artikel die Zip-Variante, weil sie den Charm hat, in sich abgeschlossen zu sein. Für das Erstellen des Zips ist kein Dockerhost notwendig und es müssen auch keine Abhängigkeiten in externen Repositories vorgehalten werden. Daher läßt sich dieser Prozess auch sehr einfach an einen CI Server übertragen.

Leider läßt sich das so erstellte Zip nicht mehr direkt lokal mit Docker starten, sonder muss erst entpackt werden.

Die Play-Anwendung verpacken

Als Beispielanwendung verwende ich einfach das existierende play-scala template. Die Anwendung generiere ich mit

activator new play-eb play-scala

Play kann von sich aus ein Archiv mit allen Abhängigkeiten erstellen:

cd play-eb
activator dist

Das fertige Zip-File liegt in target/universal/play-eb-1.0-SNAPSHOT.zip

Elastic Beanstalk erwarte das Dockerfile im root verzeichnis des Zip. Um das zu erreichen, legen wir es z.B im Root des Projektes ab und fügen es mit

zip target/universal/play-eb-1.0-SNAPSHOT.zip  Dockerfile

hinzu.

Hier ist das eigentliche Dockerfile (Eine Einführung in Docker gibt es zum Beispiel in Micro Service in Java):

FROM java:7
MAINTAINER Martin Eigenbrodt <Martin.Eigenbrodt@innoq.com>
COPY play-eb-1.0-SNAPSHOT /opt/play-eb
RUN groupadd -r play -g 433 && \
useradd -u 431 -r -g play -d /opt/play-eb -s /sbin/nologin -c "Play user" play && \
chown -R play:play /opt/play-eb
USER play-eb

EXPOSE 9000
CMD ["-Dhttp.address=0.0.0.0", "-J-Xms128M", "-J-Xmx256m"]
ENTRYPOINT ["/opt/play-eb/bin/play-eb"]

Es enthält wenig Überraschungen. Der von Play erstellte Inhalt wird nach opt/play-eb kopiert und zum Starten das darin enthaltene Script ausgeführt.

Erstellen einer Beanstalk Application

Nach der Anmeldung auf https://eu-central-1.console.aws.amazon.com/elasticbeanstalk/home kann durch Klicken auf “Launch Now” und die Wahl von Docker eine neue Beanstalk Anwendung angelegt werden.

Neue Anwendung anlegen
Neue Anwendung anlegen

Nach dem diese bereit ist, lade ich über “Upload and Deploy” das Zip (..target/universal/play-eb–1.0-SNAPSHOT.zip) hoch.

Deploy
Deploy

Nach einiger Zeit ist die Anwendung deployed und kann unter der im Dashboard verlinkten URL (http://default-environment-XXXXXXX.elasticbeanstalk.com/) aufgerufen werden.

Autoscaling

Elastic Beanstalk hat automatisch eine EC2 instanz mit dem Docker Container deployed. Darüber hinaus wurde ein Elastic-Loadbalancer eingerichtet, der in der Lage ist eingehende Aufrufe auf mehrere Instanzen zu verteilen. In der Konfiguration der Applikation kann gewählt werden anhand von welcher Metrik neue Instanzen hinzugefügt und wieder entfernt werden sollen. Neue Instanzen werden automatisch im Loadbalancer registriert.

Fazit

Mit Amazons Elastics Beanstalk & Docker lassen sich Play-Anwendungen sehr schnell deployen. Aber es gibt auch einige Einschränkungen:

Leaky Abstraction

EB verwendet unter der Haub eine ganze Reihe von AWS Services. In diesem Artikel haben wir ec2 Instanzen und den Elastic Loadbalancer gesehen. In der Praxis sind das schnell noch mehr, z.B. S3 für Deployments, CloudWatch für Metriken / Alarme, Security Groups. Für einen sicheren und performanten Betrieb der Anwendung wollen all diese Technologien verstanden sein.

Docker

Docker wird hier mit dem Modell “Ein Container pro Server” verwendet, was sehr untypisch ist. Darüber hinaus verhindert das in diesem Artikel gewählte Deployment-Model mit einem Dockerfile in einem zip das Realisieren von “Write once run everywhere”.

Ein idomatischere Unterstüzung von Docker findet man möglicherweise im recht jungen Amazon EC2 Container Service

Automatische Skalierung

Die automatische Skalierung kann lediglich eine Metrik betrachten. Ein kombinierte Metrik von z.B. CPU und Netwerkverkehr ist nicht möglich.

Thumb martin quadrat

Martin Eigenbrodt is a senior consultant for software architecture and engineering at innoQ. He has many years of experience in building software for the JVM. He focuses on design and implementation of RESTful architectures, Continuous Delivery and modern languages.

More content

Comments

Please accept our cookie agreement to see full comments functionality. Read more