- Deine Anwendung nutzt PHP? Dann gibts da ne PHP Binary + ggf. einen HTTP-Server.
- Python Web App? Dann läuft da ebenso Python + ggf. ein HTTP-Server.
- Java Web App? Tomcat, Jetty, Wildfly...
- .NET? Bereits integriert.
- Mehreres davon? Steckt fertig im Container.
- Braucht ne Datenbank? Integrier diese oder stell nen weiteren Container daneben.
- Braucht Redis als Caching? dito
- Benötigt einen AMQP Server? dito
- ELK? dito
- Horizontales Scaling? Einfach nen Parameter hochsetzen.
Deine PHP-Anwendung brauch zwangsweise oder auch nur optional php-gmp? Dann wird das mitgeliefert. Imagemagick? Ist auch bereits mit drin. Deine Anwendung benötigt noch PHP 7.2 (deprecated), ebenso auch mcrypt (ebenso deprecated)? Steckt im Container. Heutzutage hast du ggf. arge Probleme diese Builds selbst zu erstellen. 20 Cronjobs? Wurden bereits eingerichtet.
Weiterer immenser Vorteil von Containern: Immutability. Der Container wird bereitgestellt wie er ist und Änderungen darin werden beim Neustart verworfen (so man nicht Volumes nutzt, und auch die impliziten verwirft). Dass also irgendwer mal Dateien geändert hat und dort bspw. irgendwas überschrieben wird, ist ausgeschlossen.
Irgendwelche Constraints? Die Anwendung soll maximal eine CPU nutzen? Einfach einstellen. Maximal 2 GB RAM nutzen? Einfach einstellen.
Der Vorteil überhaupt imho: Du hast überall die selbe Config laufen, auch bei der Entwicklung. Kein "bei mir lief das noch" mehr. Und ich muss mich nicht mehr um nen lokal laufenden HTTP Server und etwaige VHosts und sonstige Daemons auch in unterschiedlichsten Versionen kümmern.
docker-compose up
+
http://localhost aufrufen und schon läuft das Teil.
In Containern kannst du eben dein "wirklich laufendes" Projekt bereitstellen. Mit ner ZIP stellst du höchstens den Source Code bereit und wälzt die Arbeit für Installation, Absicherung und Wartung für deine Anwendung auf jemand Anderes ab. Bis dein Projekt dann also das erste Mal überhaupt läuft, können dann schon viele viele Monde vergehen. Da kannst du froh sein, wenn es interpretierte Sprachen sind. Wenn du plötzlich für ein Java Projekt einen Build erstellen musst (weil es bspw. keine offiziellen Binaries gibt), bist du ganz schnell aufgeschmissen, wenn du plötzlich NetBeans oder Eclipse als Build Dependency mit dabei hast und es ohne nicht läuft. Nach dem Build kommt aber noch das Deployment mittels Tomcat o.ä., was einem auch nochmal Probleme bereiten kann (wie jede andere Installation natürlich auch, wenn man sich nicht mit dem Projekt und dessen Tools auskennt). Oder bspw. das richtig gute
imapsync - offizielle Binaries existieren nicht. Container aber existieren und auch homebrew bietet fertige Binaries dafür an. In den Ubuntu Repos kein einziger Eintrag. Somit kann es der unbedarfte Admin trotzdem nutzen ohne sich mit Build Tools und deren Konfigurationen beschäftigen zu müssen. Vor allem nicht mit Perl. :O
Nettes Beispiel:
mailu
Bestehend aus:
- nginx (Router für alle Requests)
- dovecot (IMAP/POP3)
- postfix (SMTP)
- Redis (Caching)
- unbound (DNS Resolver)
- rspamd (Spamfilter)
- clamav (Antivirus)
- radicale (Cal-/CardDAV)
- fetchmail (Import externer Konten)
- MySQL (DB)
- Rainloop/Roundcube (Webmail)
- Web-Admin
Den ganzen Kram auf dem Host zu installieren und mich selbst drum zu kümmern... Ne lass mal. Ich hab auch noch mehr zu tun im Leben als mich um die Administration davon zu scheren. So kümmert sich das mailu Projekt selbst (deutlich besser) drum und ich hab meine gewünschte Funktion (Mailserver). Mein einziger notwendiger Eingriff besteht dabei lediglich aus
- aktuelles Image laden
- Container neu starten
Es ist also der kleine, aber feine (und deutliche) Unterschied zwischen "hier, mach mal" und "läuft".
Aber man muss nicht mal den Weg einer Web App gehen, denn selbst stupide CLI Tools kann man problemfrei via Container deployen. Bspw. hab ich immer und immer wieder Probleme mit den pyenv Shims (keine Ahnung wieso, nutze sie ja quasi nie). Ein Aufruf von
youtube-dl
endet also gern mal in kryptischen Fehlermeldung von Python. Irgendwann hatte ich die Schnauze voll und seither geht ein Aufruf von
youtube-dl
nur noch auf
docker run --rm -v "$DIR:/media" tnk4on/yt-dlp "$@"
. Seither gibts keine überflüssigen Fehlermeldungen mehr, weil sich die Installation mal wieder selbst zerstört hat.
testssl nutz ich bspw. auch ausschließlich via Docker und auch andere Tools, die ich selten nutze, für die aber Container bereitgestellt werden. Auch ein
restic gibts in aktueller Version nicht in den Ubuntu Repos. Wieder einzig Container oder homebrew.
Aber um nochmal zur 0815 Web App zurückzukommen: Das Container Image erstellst du
einmalig. In diesem Image sind auch nur die Schritte verewigt, die du auch auf dem Server ausführen würdest (Dockerfiles sind prinzipiell auch nur Shell Scripts), damit deine Anwendung läuft.
Code:
FROM httpd:2.4
RUN apt update \
&& apt install -y gmp-dependency1 gmp-dependency2 ... \
&& docker-php-ext-install gmp ... \
&& a2enmod \
apache-modul1 \
apache-modul2 \
... \
&& a2dismod \
modul1-brauch-ich-nicht \
modul2-brauch-ich-nicht \
... \
&& sed 's/alte-config/neue-config/g' /etc/apache2/... \
&& ...
COPY . /app
RUN mkdir -p /app/cache /app/tmp /app/... \
&& chmod 0770 /app/cache /app/tmp /app/...
docker build .
und schon läuft deine Anwendung prinzipiell. Nur die Sachen installiert, die auch gebraucht werden. Wer keine Container will, kann sich aus dem Dockerfile jeden einzelnen Schritt raussuchen, damit die Anwendung zum Laufen gebracht werden kann. Es dient also gleichzeitig auch zur Dokumentation. Ne richtige Doku sollte man allerdings trotzdem haben, kann dann aber natürlich für einen Build auf das Dockerfile verweisen.
Vorteil: Der ganze Kram wurde gerade weg automatisiert und du musst die Schritte nie wieder manuell und fehlerbehaftet ausführen.
- Neuer Server?
docker-compose up
- Noch ein Server?
docker-compose up
Auch Serverumzüge sind nun extrem billig. Deployment via rsync o.ä. auf den neuen Server kopieren, dort einloggen,
docker-compose up
ausführen, schon läuft alles exakt so wie vorher. Wenn man Named Volumes nutzt, wird es etwas schwerer, aber ist quasi auch nicht mehr als ein Kopieren.
- Update der App?
docker-compose pull && docker-compose up
- Anwendung soll nicht mehr laufen?
docker-compose down
- Anwendung restlos löschen?
rm -r deployment-pfad
(mit Named Volumes wieder ein Schritt mehr)
- Backups? Deployment Pfad kopieren (Named Volumes s.o.)
- Änderung im HTTP-Server (bspw. Redirects/Rewrites/API/CORS/...) - einmal im Container oder x-mal auf jedem Deployment-Host?
Fehlt ein Use Case? Downgrades sind quasi auch nur durch ersetzen des Image Tags möglich. Aber hier muss die Anwendung natürlich mitspielen. Die Möglichkeit mittels Container Deployment ist definitiv vorhanden.
Kubernetes wer will ist dann auch nicht weit entfernt. Man sollte sich hierbei allerdings nicht die Finger verbrennen, denn viele bilden sich zwar viel ein ("Hochverfügbarkeit" und sowas und dann nen 0815 Blog oder Shop betreiben), allerdings wird der Kosten/Nutzen-Faktor selten ausgeschöpft und hiermit handelt man sich dann wirklich Komplexität ein, vor allem wenn es kein Managed Hosting ist, was dann aber auch sauschnell sauteuer werden kann. Kann bei entsprechender Anforderung natürlich trotzdem seine Vorteile voll ausspielen.
Wurde mal wieder länger als gewollt... :/