Wenn Sie diese Kolumne regelmäßig verfolgen, wissen Sie, dass ich für die Erledigung vieler Aufgaben die Kommandozeile gegenüber grafischen Werkzeugen präferiere. Für mich funktionieren diese in der Regel besser und passen besser in meinen Arbeitsfluss. Gleichzeitig habe ich es in meiner Arbeit auch mit Containern und Kubernetes zu tun. Dabei lassen sich die meisten Aufgaben mit den beiden Werkzeugen docker
und kubectl
erledigen.
Aber es gibt auch eine Reihe weiterer Werkzeuge, die Fehlendes ergänzen und die Arbeit bequemer oder effizienter machen. Deshalb erlaube ich mir in dieser Kolumne, obwohl Thomas Ronzon hier im Heft ja der Experte für Tools ist, eine zusammengewürfelte Menge an Werkzeugen auf der Kommandozeile für Aufgaben rund um Container und Kubernetes vorzustellen. Unser Werkzeugkasten ist schließlich virtuell und hat damit eine quasi unendliche Größe.
Lazydocker
Heutzutage gibt es zur Verwaltung von Containern zwar Alternativen zu Docker, wie beispielsweise Podman, aus der Historie heraus bin ich jedoch bis heute beim Original geblieben und nutze Docker-Desktop. Dementsprechend sind bei mir viele der Befehle docker
oder docker compose
, ja – mittlerweile nicht mehr docker-compose
, ins Muskelgedächtnis übergegangen und ich tippe diese, ohne lange darüber nachzudenken. Und trotzdem muss ich zugeben, dass es manchmal aufwendig ist, da ich der Reihe nach diverse Befehle ausführen muss, um zu meinem Ziel zu gelangen.
Genau hier setzt Lazydocker an. Lazydocker ist zwar ein Kommandozeilenwerkzeug, bietet aber auf der Kommandozeile eine interaktive Oberfläche an, um mit docker
und docker compose
zu interagieren (s. Abb. 1).
Standardmäßig unterteilt Lazydocker die Oberfläche dabei vertikal in zwei Teile:
- Auf der linken Seite gibt es diverse Bereiche, zwischen denen wir mit der Tab-Taste wechseln können. Über diese können wir den Bereich, wie Compose, Images, Container, Volumes oder Netzwerke, mit dem wir interagieren wollen, auswählen. Innerhalb jedes Bereichs können wir wiederum mit den Pfeiltasten das Element, das uns im Speziellen interessiert, auswählen.
- Die rechte Seite stellt den Hauptbereich dar. Dieser variiert je nach Auswahl und kann mit der Enter-Taste selektiert werden. Anschließend können wir in diesem mit den Pfeiltasten auf und ab scrollen. Je nach Auswahl, wie hier bei einem laufenden Container, besitzt dieser Bereich mehrere Tabs. Diese können mittels der eckigen Klammern durchgeschaltet werden.
Neben der reinen Anzeige von Informationen können wir aber auch mit den vorhandenen Elementen interagieren, beispielsweise einen Container starten oder stoppen. Hierzu gibt es eine Reihe von Tastaturkürzeln, die man über die Zeit lernt. Kennt man diese nicht, hilft es, nach der Selektion eines Elements x
zu drücken. Anschließend öffnet sich ein Menü, das uns alle aktuell zur Verfügung stehenden Aktionen und deren Tastaturkürzel anzeigt (s. Abb. 2).
Lazydocker bietet uns somit eine zwar Kommandozeilen basierte, aber dennoch grafische und interaktive Oberfläche, um mit Containern und Compose-Projekten zu interagieren. Dies sorgt für eine erhöhte Benutzerfreundlichkeit gegenüber der Nutzung von einzelnen Befehlen, bleibt aber durch die Steuerung über die Tastatur trotzdem sehr produktiv.
Natürlich lassen sich über Konfiguration sowohl das Aussehen als auch die vielen Tastaturkürzel verändern und an die eigenen Bedürfnisse anpassen. Zudem ist Lazydocker auf allen gängigen Betriebssystemen verfügbar und somit eine super Ergänzung für den eigenen Werkzeugkasten.
k9s
Auch bei Kubernetes wird häufig eine Abfolge von kubectl
-Befehlen benötigt, um an die benötigten Informationen zu gelangen. So muss ich in der Regel erst mal mit einem get
herausfinden, wie mein Objekt heißt, bevor ich dann mittels describe
oder logs
auf weitere Informationen zugreifen kann.
Mit k9s gibt es auch hierfür ein Werkzeug, um auf der Kommandozeile zu arbeiten, aber vom Vorteil der interaktiven Bedienung zu profitieren (s. Abb. 3).
k9s unterteilt die Oberfläche dabei horizontal in zwei Bereiche:
- Im oberen Bereich werden auf der linken Seite einige Kontextinformationen zum aktuell verbundenen Cluster angezeigt. Auf der rechten Seite werden dann einige der zur Verfügung stehenden Befehle für die aktuelle Selektion angezeigt, um nicht alle Tastaturkürzel auswendig kennen zu müssen. Wird die gewünschte Funktion dort nicht angezeigt, lässt sich mit dem Druck auf die
?
-Taste auch eine Hilfe und damit Liste aller Funktionen anzeigen. - Der untere Bereich beinhaltet den interaktiven Bereich, mit welchem wir mit den Objekten im Cluster interagieren können. Hier erfolgt die Auswahl mit den Pfeiltasten, oder – wie aus vim gewohnt – mit
j
undk
. Auf dem selektierten Objekt können wir dann Aktionen ausführen. Neben den oben angezeigten Aktionen können wir auch mittels Enter-Taste in das selektierte Objekt hineinspringen.
Im Falle von Abbildung 3 bringt uns Enter zu den Containern, die innerhalb des Pods definiert sind. Wählen wir hier einen davon aus und drücken erneut Enter, landen wir wiederum in den zum Container passenden Logs (s. Abb. 4). Andersherum können wir über die Esc-Taste wieder zurück zum vorherigen Screen gelangen. Beenden lässt sich k9s übrigens, ähnlich wie vim, mit :q
.
Mit k9s ist es, im Vergleich zur manuellen Nutzung von kubectl
, einfach, innerhalb eines Clusters zu navigieren und Aktionen auszuführen. Die angezeigten Informationen und Objekte werden dabei dauerhaft, im Hintergrund, aktualisiert und zeigen somit den wirklichen aktuellen Zustand an. Und dadurch, dass k9s wie ein regulärer Client mit dem Cluster interagiert, werden auch sämtliche Zugriffsrechte beachtet. Darf ein Nutzender einen bestimmten Namespace oder Pod nicht sehen, dann ist dieser für diesen auch nicht in k9s sichtbar.
Genau wie Lazydocker verbindet k9s somit die Vorteile von Tastaturbedienung und Kommandozeile mit einer grafischen und vor allem interaktiven Oberfläche. Ich kann mir, vor allem zur Anzeige von Informationen, den Umgang mit reinem kubectl
nur noch im Notfall vorstellen.
kubectx und kube-ps1
kubectl
wurde für mich zwar durch k9s für die Informationsgewinnung in einem Kubernetes-Cluster unnötig, trotzdem benötige und benutze ich das Tool, meist in Kombination mit apply
, jedoch weiterhin. Vor allem, wenn mit mehreren Clustern oder verschiedenen Namespaces innerhalb eines Clusters interagiert werden muss, macht, zumindest mir, die Nutzung jedoch wenig Spaß. Zwar kennt kubectl
das Prinzip von Kontexten, mit denen zwischen verschiedenen Clustern gewechselt werden kann, siehe Listing 1, aber vor allem bei Namespaces bleibt einem nur übrig, noch mehr Kontexte zu erzeugen oder bei jedem Kommando mit -n NAMESPACE_ NAME
zu arbeiten. Das fühlt sich nicht nur umständlich an, sondern ist es meiner Meinung nach auch, und zu oft bin ich darüber gestolpert, dass ich dann doch im falschen Kontext oder Namespace unterwegs war.
Mit kubectx gibt es ein weiteres Projekt, das uns gebündelt zwei Werkzeuge, nämlich kubectx
und kubens
, zur Verfügung stellt. Diese vereinfachen das Wechseln von Kontexten und erlauben uns dieselbe Funktionalität für Namespaces (s. Listing 2). Werden die Tools dabei ohne Optionen und Argumente aufgerufen, wird uns eine interaktive Liste der vorhandenen Kontexte beziehungsweise Namespaces angezeigt. Diese lässt sich filtern und durch Auswählen eines Eintrags und Drücken von Enter wird auch dieser direkt gesetzt, anstatt dass wir uns erst alle auflisten lassen und dann durch ein zweites Kommando einen Namespace setzen können.
Ergänzend hierzu ist es sinnvoll, auch noch kube-ps1 einzusetzen. Dieses erlaubt es uns, den Prompt in einer Bash- oder Zsh-Shell um den gerade aktiven Kontext und Namespace zu erweitern (s. Abb. 5). kube-ps1 lässt sich dabei über eine Reihe von Umgebungsvariablen an die eigenen Ansprüche anpassen. So lassen sich neben den angezeigten Informationen auch die genutzten Farben anpassen.
Beide Werkzeuge sind für mich eine super Ergänzung, um die Aufgaben, die ich mit kubectl
erledigen muss, bequem auszuführen, und sie verbessern für mich an dieser Stelle den Komfort deutlich.
Hadolint und kube-score
Um Container-Images zu erzeugen, werden auch heute oft noch eigene Dockerfiles geschrieben. Dabei ist es schnell passiert, dass sich, aus Unwissen oder Flüchtigkeit, kleine Fehler einschleichen. Um diese zu finden und sich an gängige Best Practices zu halten, kann Hadolint helfen. Hierbei handelt es sich um einen Linter, der das angegebene Dockerfile auf eine Reihe von bekannten Fehlern prüft und uns direkt Feedback gibt, was wir ändern sollten oder müssen (s. Listing 3).
Wie fast jedes Werkzeug lässt sich Hadolint auch über eine Konfigurationsdatei oder Umgebungsvariablen an die eigenen Ansprüche anpassen. So werden beispielsweise diverse Ausgabeformate unterstützt, um das Ergebnis auch in Reports zu integrieren. Um Hadolint einfach nur einmal auszuprobieren, kann auch die Onlineversion unter https://hadolint.github.io/hadolint genutzt werden.
Was Hadolint für Dockerfiles ist, ist kube-score für Kubernetes. Hiermit lassen sich Kubernetes-Manifeste auf gewisse Regeln überprüfen (s. Listing 4). Auch hier gibt es unter https://kube-score.com eine Onlineversion, um das Werkzeug zu testen, ohne es installieren zu müssen.
Bei beiden Werkzeugen bietet es sich an, diese innerhalb der eigenen Pipeline laufen zu lassen, um Fehler und potenzielle Probleme so früh und schnell wie möglich sichtbar zu machen und anschließend zu beheben.
docker-ls
Immer mal wieder möchte ich wissen, ob es in einer Container-Registry ein neueres Tag für ein bestimmtes Image gibt. Lange bin ich dazu auf die Weboberfläche der Registry gegangen und habe mir dort die Information zusammengesucht. Aber schon der Wechsel in den Browser ist ein Kontextwechsel, den ich gerne vermeiden möchte.
Hier schafft das Werkzeug docker-ls Abhilfe. Mit diesem ist es möglich, sich auf der Kommandozeile Informationen aus einer Remote Registry zu einem Image zu holen. Dabei können sowohl alle zu einem Image vorhandenen Tags aufgelistet werden als auch Informationen, vor allem das zugehörige Digest, zu einem spezifischen Tag abgefragt werden (s. Listing 5).
Das Digest wird vor allem benötigt, wenn wir innerhalb unseres Projekts die genutzten Images nicht nur auf ein spezifisches Tag, sondern wirklich auf eine exakte Version festzurren möchten. Ein normales Tag, wie in Listing 5 7.4.0
, verweist bei Containern schließlich nicht zwangsweise immer auf den exakt gleichen Stand, da es sich hierbei um „Floating“ Tags handelt, die im Laufe der Zeit verändert werden können.
Auch docker-ls lässt sich bei Bedarf etwas konfigurieren und auch hier ist es möglich, die Art der Ausgabe, durch go-Templates, zu beeinflussen. Weiterhin ist zu beachten, dass bei offiziellen Images, wie hier beim Image für redis, ein library/
vorgestellt werden muss.
dive
Eine der Besonderheiten von Containern besteht im aus Layern bestehenden Dateisystem. Möchte man diese Änderungen, die ein solcher Layer verursacht hat, nachvollziehen, ist dive das Werkzeug meiner Wahl.
Nachdem dive mit dem Namen eines Images aufgerufen wurde, hier redis, öffnet sich eine an Lazydocker oder k9s erinnernde Oberfläche (s. Abb. 6). Hier werden auf der linken Seite, neben den Details zum Image, alle im Image vorhandenen Layer und die Informationen zum aktuell ausgewählten Layer angezeigt. Der ausgewählte Layer lässt sich dabei per Pfeiltasten auswählen.
Auf der rechten Seite ist dann die Hauptinformation zu sehen, die eigentlichen, durchgeführten Änderungen. Wir können dabei, mittels Drücken von Tab, zwischen der Auswahl von Layern und dem Dateibaum wechseln. Somit können wir innerhalb des Dateibaumes Ordner einklappen oder einen Filter definieren.
Die Leiste am unteren Rand zeigt uns schließlich die aktuell zur Verfügung stehenden Tastaturkürzel an. Mit diesen lassen sich die angezeigten Informationen verändern. Ist beispielsweise die Layer-Auswahl aktiv, können wir uns durch Strg + A
nicht nur die Änderungen, die der aktuell ausgewählte Layer erzeugt hat, anzeigen lassen, sondern auch alle Änderungen, die vorher passiert sind. Strg + L
bringt uns dann wieder in den Modus, der nur die Änderungen des Layers anzeigt.
Neben dieser grafischen Anzeige bringt dive auch noch einen zweiten Modus zur Integration in Pipelines mit und lässt sich somit in eine Art Linter verwandeln. Hierzu rufen wir dive, wie in Listing 6 zu sehen, in Kombination mit der Umgebungsvariable CI
auf, welche wir auf den Wert true
setzen. In diesem Modus berechnet dive drei Metriken, um zu beurteilen, wie gut die Layer für das Image funktionieren. Für jede dieser Metriken gibt es dann, natürlich konfigurierbare, Schwellwerte, bei denen das Tool einen Fehler meldet.
ttl.sh und Nixery
Zum Schluss kommen wir zur Unterstützung bezüglich der Registry. Bei ttl.sh und Nixery handelt es sich zwar nicht um Werkzeuge im engeren Sinne, aber sie sind trotzdem ganz nett zu kennen. Ich würde beide aber nur mit extremer Vorsicht einsetzen.
ttl.sh stellt eine anonyme Docker-Registry zur Verfügung, zu der ich Images pushen kann. Der eigentliche Clou besteht jedoch darin, dass der Tag dazu genutzt wird zu bestimmen, für wie lange das Image in dieser Registry verbleibt. So führt ein Pushen des Images ttl.sh/my_image:8h
dazu, dass es für 8 Stunden in der Registry verbleibt und anschließend entfernt wird. Neben h für Stunden sind auch m für Minuten, s für Sekunden und d für Tage erlaubt. Das Maximum beträgt dabei jedoch einen Tag. Da es sich hierbei um eine anonyme Registry handelt, sollte einem dabei stets bewusst sein, dass jeder, der den Image-Namen kennt, oder errät, Zugriff auf das Image erlangen kann. Deswegen ist dies für interne Dinge oder Images, die Geheimnisse enthalten, mit Sicherheit keine gute Idee. Um kurzfristig unkritische Images mit anderen zu teilen oder um bei Open-Source-Projekten eine kurzfristige Registry für Zwischenschritte zu haben, ist diese Registry jedoch gut zu gebrauchen.
Auch Nixery stellt eine Registry zur Verfügung. In diese können wir jedoch keine eigenen Images pushen, dafür aber quasi ad hoc zusammengestellte Images pullen. Starten wir beispielsweise das Image nixery.dev/shell/git/curl
, so erhalten wir ein Image, das mit installierter Bash, Git und curl ausgestattet ist. Wir können dabei beliebig viele Werkzeuge, durch Slash getrennt, angeben. Als Name für die Werkzeuge müssen dabei die passenden Nix-Pakete genutzt werden. Neben der öffentlich zur Verfügung gestellten Registry unter https://nixery.dev kann Nixery auch lokal installiert und betrieben werden. Gerade, um nur mal kurz etwas auszuprobieren, kann dieser Weg einfacher sein, als ein Basis-Image zu starten und die benötigten Pakete anschließend mittels Paketmanager zu installieren. Aus Sicherheitssicht bleibt jedoch zu beachten, dass ich hier etwas ausführe, was ich vorher nur sehr schwer inspizieren kann. Denn zu diesem Image gibt es schließlich nicht mal ein Dockerfile, in das man gucken könnte.