Continous Deployment und warum Docker doof ist
Es ist mal wieder so weit, Zeit zum ranten. Heutiges Thema ist Continous Deployment und Docker. Wer jetzt schon keine Ahnung hat, wovon ich rede: Für euch ist dieser Blogeintrag wahrscheinlich nichts. Aber wenn ihr das doch lesen wollt, versuche ich die wichtigsten Sachen kurz zu erklären, für nicht Techniker.
Continous Integration & Continous Deployment
Gehen wir von einem kleinen Service im Internet aus, wie zum Beispiel dieser Blog. Es gibt zwei Möglichkeiten, wie neuer Inhalt hier erscheint:
- Ich erzeuge die HTML Dateien bei mir Zuhause und lade sie dann manuell via FTP oder ähnliches auf meinen Server
- Ich schreibe meinen Text, speicher ihn (beziehungsweise push die Änderungen in Git, was aber hier eher unwichtig ist) und ein Server macht den Rest
Man merkt schnell, dass letzterer Ansatz eigentlich gemütlicher ist und nur einmal Konfigurationsaufwand bedeutet. In meinem Beispiel Blog wäre das alles per Hand zu machen jetzt auch nicht der riesen Aufwand, aber auf Dauer schon mehr.
Continous Integration (kurz CI) bedeutet hierbei, dass Änderungen automatisch “übersetzt” werden. Im Falle Blog schreibe ich den Text mit paar Angaben zum Titel, Bild etc. und jekyll erzeugt daraus schöne HTML Dateien, packt automatisch den neuen Post in die Startseite und den RSS-Feed. Das könnte ich jetzt immer manuell ausführen, wenn ich was geändert habe oder ich lasse es automatisch immer machen, wenn ich Änderungen in Git gemacht habe. Diese Automatisierung nennt man CI. Damit hab ich jetzt zwar automatisch immer die aktuellen HTML Dateien, aber die liegen noch nicht auf meinem Webserver.
Continous Deployment (kurz CD) ist dafür zuständig, dass die “übersetzten” Änderungen automatisch veröffentlicht oder bereitgestellt werden. Wenn also Blog in HTML übersetzt wurde läuft im Anschluss mein CD-Job, der die HTML Dateien automatisch auf meinen Webserver kopiert. Dafür habe ich extra einen Account auf meinen Webserver eingerichtet, der nur in das Verzeichnis schreiben kann und sonst nichts böses anrichten könnte.
Ergebnis aus der Kombination von CI und CD ist, dass ich meine Änderungen speicher und wenige Minuten später der Blog aktualisiert ist. Und je größer ein Projekt ist, desto hilfreicher wird dieser Automatismus.
Docker
Docker ist ein System mit dem man einzelne Dienste - wie Webserver, Datenbanken oder Spieleserver - in vorkonfigurierte Pakete (genannt Container) packen kann, um sie zum einen separiert auszuführen und zum anderen ohne viel Aufwand einzurichten.
Wenn man früher beispielsweise als große Website überlaufen wurde und der eine Server von der Nutzerzahl überfordert wurde, musste man einen zweiten Server holen, den Webserver darauf installieren und sicherstellen, dass alles gleich eingerichtet ist, inklusive Abhängigkeiten, Plugins und was weiß ich nicht. Mit Docker muss man nur den Server holen, Docker installieren und den Container starten. Die Konfiguration mit Abhängigkeiten etc. ist bereits fertig. Auch wenn man von einem Serveranbieter zum anderen umzieht hat man dadurch deutlich weniger Aufwand. Ich persönlich hab mir früher eine Woche Zeit genommen für einen Serverumzug, heute mache ich das an einem Nachmittag.
Das separierte Ausführen ist vor allem sicherheitstechnisch interessant. Selbst wenn man es durch irgendeine Sicherheitslücke im Spieleserver schafft, sich dort Administratorrechte zu holen, so ist man immer noch in dem Container und nicht auf dem Gesamtsystem. Er kann dann sehr viel Unsinn in diesem Container anstellen, aber kommt nicht unbedingt an die Datenbank mit irgendwelchen sensiblen Daten oder an den FTP Server, über den er dann Filme verteilen kann.
Man kann Docker ein wenig wie virtuelle Server light sehen. Und manche Leute würden mich wahrscheinlich jetzt für diese Aussage schlagen.
Und jetzt zum eigentlichen Problem
Und ja, hier wird es wieder etwas technischer und die kurzen Einführungen oben werden wahrscheinlich nur sehr begrenzt was gebracht haben. Aber ich habs versucht.
Ich arbeite momentan an einem kleinen Projekt, wo ich eine in Kotlin geschriebene API brauche. Für Dummies: es ist aufwendiger als einfach nur Dateien in den Webserver zu schmeißen, das Ding muss auf meinen Server als Anwendung ausgeführt werden. Jetzt könnte ich dafür natürlich Jetty (Kann diese Anwendungen ausführen) oder ähnliche Server nutzen, aber ich möchte das als VertX Server laufen lassen (gaaanz tolle moderne Technik). Leider habe ich keine Möglichkeit gefunden, meine API-Jar (Die Anwendung) auszuführen und automatisch neu zu laden, wenn die Datei ersetzt wird (Jetty lädt automatisch eine solche Anwendung neu, wenn die Datei ersetzt wurde, ähnlich wie Webserver, die dann die neue HTML Datei nutzen).
Die einzige Möglichkeit die ich gefunden habe: Aus meiner API einen Docker Container zu machen, gibt da für VertX sogar bereits eine schöne Vorlage, Aber sowohl CI als auch CD werden damit grausig. Ich arbeite mit GitLab (Ein Git Service, wo zudem viele tolle Sachen wie CI/CD und Ticketsystem etc. vorhanden sind) und es gibt sogar eine Anleitung (wie man Docker-Container in GitLab-CI baut)[https://docs.gitlab.com/ee/ci/docker/using_docker_build.html]. Das Problem an der ganzen Sache: Um den Container zu bauen, muss man auf irgendeine Weise jeden Sicherheitsaspekt von Docker über den Haufen werfen. Aus meiner Sicht natürlich ein No-Go. Selbst wenn ich es schaffe, den Container irgendwie auf eine sichere Art zu bauen, kommt das Problem wieder bei CD: Im Gegensatz zu dem User für meinen Blog, der nur in ein Verzeichnis schreiben darf, muss ich hierbei entweder dem User erlauben, direkt auf Docker zuzugreifen - womit ich ihm quasi mein komplettes System offenlege - oder ich muss es umständlich etwas bauen, wo der CD-User einen Trigger auslöst, sodass dieser eine Container aktualisiert wird, aber sonst nichts passieren kann.
Das letzte Problem ist also durchaus lösbar, wenn auch minimal umständlich, aber dafür müsste ich es erstmal schaffen, den Container für meine Anwendung zu bauen. Und weil es dafür keine einfache und sichere Lösung gibt, finde ich Docker gerade extrem doof!