Home Container, Container über alles?
Post
Cancel

Container, Container über alles?

Es folgt ein (leicht angepisster) Monolog oder Rant, je nachdem wie man es lesen will.

präampel

Seit einigen Jahren werden ja Container als der neue Heilsbringer gehandelt.
Aber ist dem auch so?
Dazu muss man sich deutlich mehr mit der Materie beschäftigen, als nur gehypte Buzzwords zu verwenden.

Denn neben Docker gibt es den darauf aufbauenden Kubernetes Hype …

Aber erstmal zurück zum Anfang.
Alles, was wir benötigen um Services - sei es ein Kubernetes Cluster, oder “Serverless-Bullshit” - zur Verfügung stellen zu können ist HARDWARE.
Richtig. Dieser Oldschoolrotz, den alle wegdefinieren wollen.

Und hier hat man leider nicht viel zur Auswahl.
Entweder man setzt sich in den Intelkompatiblen Zug names x86, versucht sich mit ARM Technik, oder irgend etwas mit RISC.

Dann hören aber die Alternativen auch schon auf.

Leider. Denn ein wenig mehr Auswahl bei der Basistechnologie wäre AFAIK sinnvoll.

Historie

Der Großteil setzt zur Zeit auf x86, den Mist, den Intel irgendwann in den 80igern auf den Markt brachte.
Warum Mist? Weil selbst aktuelle 64Bit Prozessoren noch Teile aus der i386 Ära aus “Kompatibilitätsgründen” mitschleifen.
Du kannst die CPU als im Legacy Mode wie einen i386 betreiben.

Aber was solls, ist nur Ballast.

Interessanter ist dagegen, was die darunterliegende - IBM-PC kompatible - Architektur für Altlasten pflegt.

Angefangen von einem immer ausladenden BIOS (jetzt UEFI genannt) über die begrenzte Anzahl von Interrupts und die verschiedene Behandlung von Interrupt-Vektoren …

Sobald man da tiefer eintaucht stellt man fest, dass sich die grundlegende Basisarchitektur, die ja in den 1980igern entwickelt wurde, nicht geändert hat.

Was hat sich denn geändert?

Wir haben schnellere CPUs (die jetzt noch länger auf Eingaben an der Tastatur warten können).
Wir haben mehr RAM zur Verfügung. Und leider immer fettere Betriebssysteme, die diesen Vorteil ständig auffressen.
Wir haben größere Speichermedien. Siehe bei RAM.
Das Bussystem, zur Kommunikation mit der Peripherie hat sich (mehrmals) geändert.

Und leider nicht immer zum besten.
Mit der Aufnahme von Firewire in den USB3 Standard, ist es nun möglich über DMA mit speziell dafür gebauter Hardware direkt auf alles im Rechner zuzugreifen. Sämtliche Sicherheitsmechanismen greifen da einfach nicht mehr. Vor allem, weil viele (der Sicherheitsmechanismen) aus Kostengründen in Software implementiert werden und dadurch umgangen werden können.

Aber auch das schieben wir mal zur Seite.

Wir haben Leistung (CPU) und genügend Ressourcen (RAM, HDD, SDD) zur Verfügung.

Mein aktuelles Laptop langweilt sich, während ich diesen Text hier schreibe.
Ich habe von den 16 CPU Kernen 15 abgeschaltet und habe trotz allem noch ein flüssiges KDE in Benutzung.

Was machen wir also mit den ausufernden Resourcen, die wir nicht wirklich benötigen, bloß?

Virtualisieren!

Genau. Ich kann auf meinem Laptop so viele virtuelle Instanzen verschiedener Betriebssysteme starten, wie ich möchte.
Meine CoreMedia Testinstallation zum Beispiel umfasst 9 Instanzen.
Dazu noch eine eigenständige Instanz um Container bauen zu können …
Alles kein Problem.
Und wir haben nöch immer Leistung satt.

Jedenfalls so lange, bis alle Instanzen gleichzeitig auf den Storage zugreifen wollen.

Upps ..

Die PC-Technik hat Leistung satt, verzeifelt aber - aus historischen Gründen - bei der I/O.

Wie peinlich.

Und genau hier fangen unsere eigentlichen Probleme an!

steigende Komplexität

Mit jedem Layer, den wir auf der Seite der Infrastruktur hinzufügen, steigt die Komplexität.
Mit steigender Komnplexität schwindet aber auch das Verständniss, wie das ganze Konstrukt in Summe funktioniert.

Als Basis wird immer die Hardware stehen!
Um deren Ressourcen besser zu nutzen hat man die Wahl von virtuellen Instanzen, die sich alles teilen, was die Hardware zur Verfügung stellt:

  • CPUs
  • RAM
  • I/O
  • Speichermedien
  • Netzwerk

Und spätestens I/O limitiert auch die Anzahl von Instanzen.
Natürlich, man kann den Storage auslagern (z.B. FibreChannel, iSCSI, etc.) benötigt dazu wieder spezielle Hardwarte und ist noch immer im Interrupt Gefängniss der IBM Architektur.
Das gleiche kann man auch beim Netzwerk sagen.

Irgendwann ist halt Schluß.

Aber nicht im hyperkonvexen Bullshitzirkus … denn da stülpen wir einfach noch einen Komplexitätslyer drüber.
Ach was sage ich .. einen? Warum nicht gleich zwei?

Komplexität +1

Docker sollte ursprünglich mal das Ausrollen von Applikationen erleichtern.
Ein Paketformat, was irgend einen binärblob beinhaltet, den man starten kann und der $Dinge tut.

Für alte properitäre Software, die in einem streng gekapselten System laufen muss, weil Bibliothek A in einer ranzigen Version verlangt wird, oder wenn das verlangte OS auch schon seit 5 Jahren nicht mehr gepflegt wird, kann man das gut und gerne benutzen.

Und weiter?

Ein Container beinhaltet quasi ein minimales OS mit allem Mist, den man benötigt und auch nicht benötigt, um eine Software zu starten.

Nehmen wir zum Beispiel ein python Script. 3kb groß.

Der benutzte Container ist mit einen slim-bullseye 45 MiB groß.
Der Standard bullseye Container bringt knappe 340 MiB mit.
Einen Windows Container bekommt man ab 2.5 GiB.

Um ein 3kb großes Script zu starten. Auf einem System, was schon Python installiert hat.

Großes Kino!

Komplexität +1*2

Und da Docker noch immer nicht Komplex genug ist, schraubt man einen Kubernetescluster drunter.
Der verwaltet dann auch noch, wo mein Container läuft.
Aber dann muss ich noch ein halbes dutzend Dienste extra betreiben, damit ich wieder mit meinem Container kommunizieren kann, dass dieser ggf. Netzwerkzugriffe bekommt oder übers Netzwerk erreichbar ist.

WA-RUM macht man das?

Wem erleichtert denn so ein Konstrukt die Arbeit?

I/O und Latenzen

In einem meiner letzten größeren Projekte war es meine Aufgabe einen Jenkins möglichst sauber aufzubauen und so zu konfigurieren, dass dieser einen Großteil von Plugininstallationen und Datenimports selbstständig ausführt.
Natürlich sollte er in einem Container laufen.

Der Zugriff sollte über einen nginx gehen, der ebenfalls in einen Container laufen sollte.

Kein Problem.
Aber langsam.

Das Anmelden am Jenkins war unerträglich langsam und dauerte bis zu 5 Sekunden.
Als ich den nginx auf dem Hostssystem installierte (und mit ansible provisionierte) hatte ich eine deutliche Steigerung der Geschwindigkeit.
Das Anmelden war unterhalb einer halben Sekunde in dem Zeitfenster, dass ich erwartete und auch so kannte.

Warum ich das erwähne?

Das Totschlagargument für Docker (und Kubernetes) ist ja meistens … Microservices oder Skalierbarkeit über schnell startende Anwendungen, Konfigurationsmanagement, etc.

Nun Microservices sind ein weiteres gutes Besipiel für Bullshit.

Microservices reagieren in der Regel über eine API.
Eine API, die ich über ein Netzwerk hinweg benutzen kann, oder die an einer Messagequeue hängen und sich darüber Aufgaben besorgen.

Eine Software, die via API mit einem Service kommuniziert führt in der Regel einen Handshake durch:

  • Verbindungsaufbau
  • Anmelden / Verifizieren
  • Daten übermitteln

Microservices werden allerdings in einer größeren Architektur nicht in einer 1:1 Beziehung genutzt, sondern eher ein einer 1:n … viele Services greifen auf einen anderen - manchmal auch gleichzeitig - zu.

So muß der Microservice aber auch designed und programmiert werden. Da sind Reaktionszeit im Millisekundenbereich nicht nur wünschenswert, sondern Pflicht.

Denn beim Aufbau einer Microservicekaskade können sich die Latenzen sehr schnell aufsummieren und dieses Konzept ad-absurdum führen.

Der Einsatz einer Messagequeue ist da schon deutlich effizienter, aber auch wieder komplexer. Denn diese muss dann ausfallsicher betrieben werden und ggf. Jobs persistent vorhalten. Auch muss die Software auf Sender- und Receiverseite entsprechende Mechanismen wie locking implementiert haben.

DNS

“DNS ist immer das Problem” und das ist - gerade im Dockerumfeld - nicht untertrieben!
Die größten Probleme, die mir in den letzten Jahren aufgefallen sind, waren schlechte konfigurierte Nameserver, fehlende Einträge, falsche TTLs.

Und Docker ist da sehr pingelig!
In einem Kubernetescluster kann das noch eine ganz andere Dimension bekommen.

Interessanterweise kenne ich mittlerweile einige - auch größere - Projekte, die komplett auf den Einsatz von DNS verzichten und lieber statische (IPv4) Adressen nutzen. Pflegbar wird das dann auch nicht mehr …

Redundanzen

Docker verhindert aktiv und absichtlich das parallele Benutzen von Software.

Als Beispiel nehem ich da gern mal meinen CoreMedia Stack.

CoreMedia ist ein in Java programmiertes Content-Management-System und besteht aus mehreren Services.
Bei einem Dockerdeployment bringt jetzt jeder Container sein eigenes Java mit.
Bei 15 Services mit jeweils einem 20 MiB großen jar File sind das keine 300 MiB plus zusätzliches JRE, sondern mehr als 7 GiB.

Und ich habe auf Deployment- und Operationsseite keinerlei Vorteile gewonnen, denn konfigurieren muss ich die Services noch immer. Ebenso deployen, was bei mir ein Ansible übernimmt.

Dafür habe ich jetzt einen weiteren Service (nämlich docker zu betreuen).

Und da ein CoreMedia System dafür ausgelegt ist, lange - eher ständig - zu laufen, ist hier der Einsatz eines Kubernetesclusters für mich erst Recht nicht mehr nachvollziehbar.

Erhöhte Komplexität schafft keinen Mehrwert!

Fazit

Wofür sind den jetzt Conatiner / Kubernetes Cluster gut?

Meiner Meinung nach sind sie gut für eine Buildumgebung, bei der ich viele Services schnell starten kann, die Zustandslos laufen und die ich ebenso schnell bedenkenlos wieder entsorgen kann.

Man sollte sich also den Einsatzzweck der Software genau anschauen. Gern auch mal die Entscheidung des Kunden hinterfragen, denn diese sine meistens Buzzwordgetrieben und entspringen nicht einer realen Anforderung.

Wichtig ist auch der aktuelle und der geplante Ressourcenverbrauch und - fast noch wichtiger - das Skillset der Menschen, die so etwas betreiben sollen!

Operations sollte immer den kompletten Stack, den sie betreiben müssen, verstehen können. Angefangen bei der Hardware, über Virtualisierung bis hin zu einem K8s Cluster und der dazugehörigen Automatisierung.

Meiner Erfahrung nach fangen aktuell die Defizite schon bei allen Dingen unterhalb eines K8s-Clusters an.

Die wenigstens können heute noch DNS, MTA oder gar Netzwerke konfigurieren, geschweige denn Fehler debuggen.

This post is licensed under CC BY 4.0 by the author.