Die Linux-Gemeinschaft lässt sich grob in drei Lager unterteilen. Dabei nimmt ein Lager den Extremwert „stabil wie ein Fels“ mit z.B. Debian oldstable ein, während der andere Extremwert „bleeding edge“ durch Anhänger z. B. von Arch Linux besetzt wird. Das dritte Lager besetzt die Mitte, in der sich unzählige weitere Distributionen tummeln, die mehr zu dem einen oder dem anderen Extremwert hin tendieren.
Warum das so ist und welche Distribution einen, wie ich finde, ganz interessanten Mittelweg eingeschlagen hat, möchte ich in diesem Artikel beleuchten. Bierernst bin ich dabei allerdings nicht. Die ein oder andere Ausführung ist durchaus mit einem Augenzwinkern zu verstehen. ;-)
Stabil wie ein Fels
So soll eine Linux-Distribution aus Sicht vieler Systemadministratoren sein. Gut getestet, alle Komponenten perfekt aufeinander abgestimmt und über ihren Lebenszyklus nur wenigen — am besten gar keinen — Änderungen unterworfen. Einzig Sicherheitsaktualisierungen dürfen und sollen zeitnah geliefert werden.
Distributionen, die sich diesem Paradigma unterwerfen, versprechen geringe Wartungsaufwände und sind des Sysadmins Freund. In meinen Augen dürfen Debian, RHEL, SLES, etc. dieser Kategorie zugeordnet werden.
Doch bergen diese Distributionen paradigmenbedingt auch einige Nachteile. Da Kernel und Bibliotheken meist schon etwas älter sind — manche sagen dazu steinalt, andere gut abgehangen — wird neue Hardware evtl. nicht in vollem Umfang unterstützt. Oder die mitgelieferten Bibliotheken und Laufzeitumgebungen sind schlicht zu alt, um mit aktuellen Versionen verfügbarer Software noch kompatibel zu sein.
Um den Nachteilen zu begegnen, bleibt Sysadmins häufig nichts anderes übrig, als das wohlige Heim der Distribution zu verlassen und Laufzeitumgebungen aus Upstream- oder Drittanbieter-Repos zu installieren, Software selbst zu übersetzen oder sich Container in die heilige Halle zu stellen. Die Distributionen versuchen dem zu begegnen, in dem sie unter Umständen zu Minor-Releases neuere Software-Versionen als sogenannte Rebases oder Backports nachliefern. Das dies passiert ist jedoch keineswegs garantiert und stellt im Zweifel ein Risiko für die Stabilität dar.
Wenn die Distribution dann aber doch eine neue Softwareversion ausliefert, hat der Sysadmin meist keine Wahl. Entweder er bleibt auf der alten Version und erhält voraussichtlich keinerlei Sicherheitsupdates mehr für diese oder installiert die aktuelle Version und lernt die Neuerungen lieben bzw. damit zu leben.
Bleeding Edge
Mit diesem Beinamen werden häufig Distributionen bezeichnet, welche dem Rolling-Release-Modell folgen und Software mitliefern, die sehr nah am aktuellen Stand der Upstream-Entwicklung ist (the latest and greatest). In dieser Ecke findet man z. B. Distributionen wie Arch Linux, Manjaro, Fedora Rawhide, etc. wobei diese Liste keinen Anspruch auf Vollständigkeit erhebt.
Der Betrieb dieser Distributionen ist geprägt von häufigen Updates. Die stetige Weiterentwicklung birgt das Risiko, dass auch mal etwas kaputt geht und plötzlich nicht mehr funktioniert. Doch versprechen die Distributionen meist, dass gerade durch den schnellen Entwicklungszyklus gefundene Fehler auch schnell behoben werden. Wohingegen die Nutzer stabiler Version häufig Monate, wenn nicht Jahre oder gar vergebens auf einen Bugfix warten müssen.
Blöd wird es, wenn man Software betreiben muss, die nur für eine bestimmte Version einer Laufzeitumgebung, oder bestimmter Bibliotheken freigegeben ist und unterstützt wird. Wer solche Software betreibt, sollte sich jedoch von vornherein fragen, ob er bei rollenden Releases richtig aufgehoben ist.
Dann sind da auch noch jene unter uns, die für den Betrieb auf gewisse Zertifizierungen ihrer Betriebssysteme angewiesen sind. Hier sind die Zertifizierungsverfahren häufig länger, als die Lebensspanne eines Bleeding-Edge-Release.
Das Mittelfeld
Dieses Feld ist weitgespannt. Hier tummeln sich Distributionen wie Fedora, Ubuntu sowie viele weitere. Ihnen allen unterstelle ich, dass sie den besten Kompromiss suchen, um so stabil wie möglich und so aktuell wie nötig zu sein.
So habe auch ich in der Vergangenheit auf Ubuntu LTS gesetzt, da ich es für den besten Kompromiss hielt. Leider waren unsere Entwickler mit den mitgelieferten Software-Versionen nicht lange zufrieden und ließen sich nicht bis zum nächsten Release hinhalten. Also wurden auch hier wieder {Dritanbieter,Upstream}-Repos eingebunden und die Software von dort installiert. Eine Erfahrung die ich bisher unter jeder Distribution machen durfte.
Genauso gut kenne ich den umgekehrten Fall, wo Paket XY auf gar keinen Fall aktualisiert werden darf, da sonst ein Dienst unrettbar kaputt geht. Lasst euch gesagt sein, man hat es schon nicht leicht in der Systemadministration. ;-)
Appstreams und Module
Mit RHEL 8 hat Red Hat eine interessante Neuerung eingeführt, die sog. Module im Appstream-Repository. Nun ein Listing sagt vermutlich mehr, als viele Sätze:
$ sudo dnf module list nginx php postgresql
Updating Subscription Management repositories.
Last metadata expiration check: 0:27:21 ago on Mi 21 Apr 2021 05:41:58 CEST.
Extra Packages for Enterprise Linux Modular 8 - x86_64
Name Stream Profiles Summary
nginx mainline common nginx webserver
Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs)
Name Stream Profiles Summary
nginx 1.14 [d] common [d] nginx webserver
nginx 1.16 common [d] nginx webserver
nginx 1.18 common [d] nginx webserver
php 7.2 [d] common [d], devel, minimal PHP scripting language
php 7.3 common [d], devel, minimal PHP scripting language
php 7.4 common [d], devel, minimal PHP scripting language
postgresql 9.6 client, server [d] PostgreSQL server and client module
postgresql 10 [d] client, server [d] PostgreSQL server and client module
postgresql 12 client, server [d] PostgreSQL server and client module
Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled
Wie ihr sehen könnt, hat man damit die Auswahl aus mehreren Versionen ein und der selben Anwendung. Das kannte ich so bisher noch nicht, ohne zusätzliche Repos einbinden zu müssen, oder mich gar mit den berüchtigten Red Hat Software Collections beschäftigen zu müssen.
Als Sysadmin habe ich damit etwas Flexibilität dazugewonnen. Ich kann z. B. eine Altlast mit NGINX 1.14, PHP 7.2 und PostgreSQL 9.6 auf einem Host und eine aktuelle Anwendung mit NGINX 1.18, PHP 7.4 und PostgreSQL 12 auf einem anderen Host betreiben, dabei aber das gleiche stabile Release RHEL 8 nutzen.
Allerdings kann man nicht zwei verschiedene Versionen von z. B. PHP oder PostgreSQL parallel auf dem gleichen Host betreiben. Wer dies wünscht, kann die entsprechenden Anwendungen lokal in Podman-Containern ausführen. Auch hier stehen Images für die verschiedenen Versionen bereit.
Red Hat verspricht, neue Versionen von Anwendungen, Sprachen und Werkzeugen auf diesem Weg verfügbar zu machen. So sind in der Beta des kommenden RHEL 8.4 zum Beispiel PostgreSQL 13, Python 3.9 und Podman 3.0.1 enthalten. Zu beachten ist jedoch, dass die jeweiligen Streams ihre eigenen Life-Cycles besitzen, die es im Auge zu behalten gilt. Hier hilft ein Blick in die offizielle Dokumentation weiter:
Ob diese Neuerung und die damit einhergehenden Vorteile in der Praxis von Relevanz sein werden, kann ich heute noch nicht sagen. Dafür fehlt mir noch etwas Erfahrung mit diesem neuen Konzept.
Ich persönlich glaube, dass sich Application Streams und das Konzept zur Verwendung von Containern nicht gegenseitig ausschließen, sondern sinnvoll ergänzen können. In meinen Augen gelingt es Red Hat mit Appstreams, seine stabile Distribution etwas in Richtung Aktualität zu schieben, ohne dabei Stabilität aufgeben zu müssen.
Dies ist der letzte Artikel in meiner kleinen Reihe, über meinen Ausflug ins Container-Land, zur Bereitstellung der Anwendung Kanboard.
Wie meine Reise ins Container-Land begonnen hat, kann in „Kanboard im Container…“ nachgelesen werden. Wie man einen Reverse-Proxy vor einem Pod betreibt sowie mit dem Thema Backup und Restore habe ich mich inzwischen ebenso beschäftigt. Letzteres habe ich zum Glück implementiert und getestet, bevor ich mit der Dokumentation Datenverlust erlitten habe. Damit die Anwendung nach einem Neustart automatisch startet und für ein bisschen Komfort, habe ich Systemd-Service-Units generiert. In diesem Teil geht es nun um die Aktualisierung dieser Umgebung.
Umgebung
Aktuell läuft Kanboard 1.2.18 auf einer RHEL 8 VM. Zur Ausführung sind folgende Werkzeuge und Container-Images beteiligt.
$ podman --version
podman version 2.2.1
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.redhat.io/rhel8/postgresql-96 latest 4ce7daa6dc1d 7 weeks ago 451 MB
docker.io/kanboard/kanboard v1.2.18 e7ee6403944b 3 months ago 58.6 MB
k8s.gcr.io/pause 3.2 80d28bedfe5d 14 months ago 688 kB
Um mir die Erstellung eines Pods und das Einhängen von Podman-Volumes zu erleichtern, nutze ich folgendes kleines Skript:
Mein Pod und die drei dazugehörigen Container werden während der folgenden Schritte noch normal ausgeführt.
Die Container selbst sind dabei zustandslos. Die persistent zu speichernden Daten werden in Podman-Volumes im lokalen Dateisystem der VM abgelegt.
Vorgehensweise
Ich verzichte in diesem Fall bewusst auf podman-auto-update(1), da ich mir erstmal einen Überblick verschaffen möchte, was denn generell zu tun ist und wie die einzelnen Schritte aussehen können. Die grundsätzliche Reihenfolge für ein Update sieht dabei wie folgt aus:
Aktuelle Container-Images aus einer Registry holen (podman-pull(1))
Laufende Pod-Instanz stoppen und entfernen (podman-pod(1))
Neue Pod-Instanz mit angepasstem Wrapper-Skript erstellen
Systemd-Service-Units erneut generieren (podman-generate-systemd(1))
Pod-Instanz stoppen
Generierte Systemd-Service-Unit starten
An dieser Stelle möchte ich vorweg nehmen, dass es genau so einfach war, wie es sich anhört. Die neuen Container-Images habe ich mit folgenden Kommandos heruntergeladen.
Mit den folgenden Befehlen werden Informationen zum laufenden Pod angezeigt, der Service wird gestoppt und der Pod inkl. seiner Container entfernt.
$ podman pod ls
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
2f3aa7d07e6e kanboardpod Running 4 weeks ago 34e8479a2847 3
$ systemctl --user stop pod-kanboardpod.service
$ podman pod ls
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
2f3aa7d07e6e kanboardpod Exited 4 weeks ago 34e8479a2847 3
$ podman pod rm kanboardpod
2f3aa7d07e6eb7d4c3a0c9927dac222be52b8992f95929c12af8ce4afafd4eb1
In mein Wrapper-Skript (siehe Abschnitt Umgebung) trage ich die neuen Versionsnummern bei den entsprechenden Aufrufen ein:
Nachdem das obige Wrapper-Skript ausgeführt wurde, prüfe ich, ob die neue Pod-Instanz läuft, erstelle die Service-Units und aktiviere diese:
$ podman pod ls
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
85273ee9bb82 kanboardpod Running About a minute ago 82f45a722dff 3
$ podman container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6becc68a9c20 registry.redhat.io/rhel8/postgresql-96:1-127 run-postgresql About a minute ago Up About a minute ago 127.0.0.1:8080->80/tcp pgsql_db
82f45a722dff k8s.gcr.io/pause:3.2 About a minute ago Up About a minute ago 127.0.0.1:8080->80/tcp 85273ee9bb82-infra
e72ca46110be docker.io/kanboard/kanboard:v1.2.19 About a minute ago Up About a minute ago 127.0.0.1:8080->80/tcp kanboard
$ podman generate systemd --files --name kanboardpod
/home/bob/pod-kanboardpod.service
/home/bob/container-kanboard.service
/home/bob/container-pgsql_db.service
$ mv *.service .config/systemd/user/
$ podman pod stop kanboardpod
85273ee9bb82e49e236ae37d9320fd95af1eb186d7d965d72b9e2a270ca5cedf
$ systemctl --user daemon-reload
$ systemctl --user start pod-kanboardpod.service
Fazit
Das war einfacher als gedacht. Oder anders formuliert, es hat tatsächlich so funktioniert, wie ich es erwartet habe.
Mein kleines Wochenend-Projekt skaliert sicher nicht gut und ist als Beispiel für Produktionsumgebungen vermutlich weniger geeignet. Doch um Software als rootless-Container auszuführen und in kleinem Umfang zu testen, scheint dieser Weg durchaus geeignet zu sein.
Vielleicht schiebe ich in Zukunft noch einen Artikel unter Verwendung von podman-auto-update(1) nach.
Vergangenes Jahr habe ich meinen Tower-PC generalüberholt und mit frischer Hardware bestückt. Dieses Jahr möchte ich meine beiden ThinkPads (T410 und X201) durch aktuelle Hardware ablösen.
Das neue Gerät soll folgende Anforderungen erfüllen:
100% Linux-Kompatibilität – Ich möchte auf dem Gerät Debian, RHEL, Fedora, Ubuntu LTS oder evtl. auch mal ganz was neues betreiben. Da möchte ich natürlich nicht für Hardware bezahlen, die ich anschließend nicht nutzen kann.
Lange Akkulaufzeit>7 Std. – Damit ich mit dem Gerät auf dem Sofa, im Garten, im Büro oder auch mal im Auto arbeiten kann, ohne nach wenigen Stunden an eine Steckdose gefesselt zu sein.
Gute Tastatur – Dies ist ein sehr subjektiver Punkt. Ich liebe die ThinkPad-Tastaturen. Die alten mehr, als die neuen. Ich hasse hingegen die Tastaturen aus der Dell Latitude Reihe.
Leise Lüfter – Wenn mehrere Prozesse schwere Arbeit verrichten, muss die Hardware selbstverständlich gekühlt werden. Wenn mich das Gerät allerdings bei der Internetrecherche und dem Schreiben von Texten bereits permanent anbläst und die Lüfter heulen lässt, nervt mich dies extrem.
Virtualisierung – Ich arbeite viel mit virtuellen Maschinen und zukünftig auch vermehrt mit Containern. Das neue Gerät soll nicht meinen Hypervisor ersetzen, aber für Testzwecke schon mal 2-3 VMs parallel starten können. Daher sind 8 Threads und mindestens 32 GB RAM Pflicht.
1 TB Festplattenspeicher – Denn darunter wird der Platz nur wieder erschreckend schnell knapp.
Bisher habe ich mich in den Online-Shops von TUXEDO Computers und Lenovo umgesehen und die beiden folgenden Geräte ins Auge gefasst
Das ist in meinen Augen bereits eine gute Ausstattung zu einem fairen Preis. Nur bin ich skeptisch, ob mir die Tastatur gefallen wird und ich mich daran gewöhnen kann, keinen TrackPoint mehr zu haben.
Ist unter euch evtl. ein ehemaliger ThinkPad-User, welcher nun ein TUXEDO sein Eigen nennt und etwas zur Tastatur und dem Touchpad sagen mag? Und auch wenn ihr kein ThinkPad-User seid, freue ich mich über euer Feedback.
Sonstiges: Das System ist Red Hat Linux zertifiziert und das Gehäuse ist spritzwassergeschützt
Preis: ca. 1459 EUR
Die Akkulaufzeit beträgt nach MobileMark 2014 bis zu 13,25 Std. und nach MobileMark 2018 bis zu 10,5 Std. Das sagt mir persönlich erstmal gar nichts, da ich beide Benchmarks nicht kenne. Davon ab mag sich die reale Laufzeit im Wirkbetrieb, gerade unter Linux, völlig anders darstellen. Wie sind eure Erfahrungen mit der Akkulaufzeit von aktuellen ThinkPads unter Linux? Weicht diese stark von den Angaben ab?
Wer die Wahl hat, hat die Qual
Da sitze ich nun vor meinem altgedienten T410 und kann mich nicht entscheiden. Die Preise beider Geräte liegen sehr nahe beieinander. Bei TUXEDO bekomme ich die doppelte Menge RAM fürs Geld. Bei Lenovo bekomme ich eine gute Tastatur und meinen geliebten TrackPoint.
Bevor ich mich entscheide, werde ich das Web wohl noch nach ein paar Testberichten umgraben. Falls ihr welche kennt, freue ich mich über eure Hinweise.
Für welches Gerät würdet ihr euch denn entscheiden? Und warum?
Wenn ihr Geräte von anderen Herstellern kennt, die obige Anforderungen erfüllen und eine vergleichbare Ausstattung bieten, freue ich mich ebenfalls, wenn ihr Hinweise darauf in den Kommentaren verlinkt.
Mit „Kanboard im Container…“ hat mein Ausflug ins Containerland begonnen. Mittlerweile läuft mein Pod bereits eine Weile und ich nutze die Anwendung regelmäßig. Jedoch musste ich nach jedem Neustart des Hosts den Pod kanboardpod manuell starten. Ich hatte mir daher vorgenommen, hierfür eine Systemd-Service-Unit zu erstellen, welche diesen Task automatisiert. Doch habe ich mit Freude festgestellt, dass podman-generate-systemd(1) mir diese Arbeit abnehmen kann.
Also starte ich einen ersten Versuch und erzeuge entsprechende Service-Unit-Dateien in meinem HOME-Verzeichnis. Die Option „--name“ sorgt dafür, dass in den Service-Unit-Dateien die Namen des Pods bzw. der Container verwendet werden, anstatt der UUIDs. Die Option „--files“ sorgt dafür, dass die Ausgabe in Dateien und nicht auf die Standard-Ausgabe geschrieben wird.
Um die generierten Service-Units zu installieren und zukünftig als derjenige User auszuführen, welcher den Pod und die Container erzeugt hat, verschiebe ich sie in das zu erstellende Verzeichnis ~/.config/systemd/user. Anschließend werden die neuen Units in die Systemd-Konfiguration eingelesen und aktiviert.
Nachdem ich die Service-Units an die richtige Stelle verschoben und aktiviert hatte, habe ich meine laufende Pod-Instanz gestoppt und über die entsprechende Service-Unit gestartet.
Ich wähnte mich nun bereits am Ziel. Doch nach einem Neustart des Hosts war die Anwendung wieder nicht verfügbar. Die Service-Unit war nicht gestartet worden. Podman kann hier nichts dafür, denn es ist systemd, welcher dafür sorgt, dass im User-Kontext laufende Services beendet werden, wenn sich der entsprechende User ausloggt und diese erst startet, wenn der User sich einloggt.
Valentin Rothberg von Red Hat gab mir den entscheidenden Tipp, um dieses Problem zu lösen. Die Lösung versteckt sich in der Manpage zu podman-generate-systemd(1):
The systemd user instance is killed after the last session for the user is closed. The systemd user instance can be kept running ever after the user logs out by enabling lingering using
$ loginctl enable-linger <username>
Manual page podman-generate-systemd(1)
@Valentin: Thanks a lot, that solved my issue!
Fazit
Ich bin ehrlich gesagt hoch erfreut, dass die Entwickler hier eine Möglichkeit vorgesehen haben, um aus bestehenden Pods bzw. Container-Instanzen Systemd-Service-Units generieren zu können. Dies ermöglicht es, Container-Instanzen und Pods mit den gewohnten Werkzeugen zu starten, zu stoppen und deren Status zu kontrollieren.
So besteht die Möglichkeit, die rootless-Podman-Container auch als unprivilegierte Dienste laufen zu lassen. Das gefällt mir.
Dies ist ein Gastbeitrag von meinem geschätzten Kollegen Jörn Clausen. Der Beitrag wurde in englischer Sprache verfasst und behandelt die Installation von NetBSD auf dem VMware ESXi on ARM Fling.
In October 2020, VMware released a preview of their hypervisor ESXi for the ARM architecture. It is free to download (registration needed, though) and will run for 180 days, and one of the supported platforms is the Raspberry Pi 4B. So it’s quite easy to give it a try. To install the ESXi ARM Fling, use the instructions you’ll find at the download page. The ESXi installation is not covered by this article.
A lot of Linux distributions and FreeBSD are working as guest OSes, and luckily NetBSD’s motto holds up: „Of course it runs NetBSD!“. Thanks to the work of Jared McNeill, the ARM port of NetBSD will run on ESXi for ARM.
As his instructions for creating a running NetBSD VM are a bit terse, I’d like to elaborate a little bit.
Prerequisites
You will need the following things:
ESXi on Arm Fling up and running (duh!)
SSH access to the ESXi host (activate either from the console or the web interface)
qemu-img, for example by installing emulators/qemu from pkgsrc
And of course you will need NetBSD. Download the latest installation image either from Jared’s site „http://www.armbsd.org/arm/“ (be sure to download „Generic 64-bit“ from the tab „NetBSD -current“), or use the latest HEAD release.
Creating a NetBSD VMDK file
Unpack the image:
$ gunzip arm64.img.gz
Increase the image to the size the hard disk should have. In this case, we grow it to just 2 GB:
$ qemu-img resize -f raw arm64.img 2g
Image resized.
Transfer the last file arm64.vmdk to the datastore on the ESXi host, either using scp or by uploading it via the web interface.
Creating a NetBSD VM
Log on to the ESXi host using ssh. Navigate to the directory where you uploaded the VMDK file. If you used a basic setup with all the defaults, this will be /vmfs/volumes/datastore1/.
Convert the VMDK file to a proper virtual hard disk:
# vmkfstools -i arm64.vmdk -d thin arm64-hd.vmdk
Destination disk format: VMFS thin-provisioned
Cloning disk 'arm64.vmdk'...
Clone: 100% done.
Switch to the web interface of ESXi and create a new VM. Use „Other“ as Guest OS family and „Other (64-bit)“ as Guest OS version.
Remove the hard disk that is automatically added to the VM. Instead, select „Add hard disk“ and „Existing hard disk“. Choose the VMDK you created in the last step (be sure to use arm64-hd.vmdk and not arm64.vmdk).
You can use the default network adapter (E1000e) or you can replace it with the paravirtualized one (VMXNET3).
Running the NetBSD VM
Now start the VM and open the console. The virtual machine should boot straight into the NetBSD boot loader and then into NetBSD. On the first boot, NetBSD will grow the filesystem to use the complete hard disk and reboot. After that, you should be able to login as root.
Now you have a complete NetBSD system. You can even run an X server on the console.
Wie ihr sicher gemerkt habt, beschäftige ich mich im Rahmen eines Wochenend-Projekts mit „Kanboard im Container…“ im Speziellen und Linux-Containern im Allgemeinen. Die Einrichtung von „Backup und Restore im Kanboard-Container-Land“ liegt bereits hinter mir. Und das ist gut so, habe ich doch nun den ersten Datenverlust erlitten und musste meine Daten wiederherstellen.
Die etwas unglückliche Verkettung von Umständen, welche zum Datenverlust führten, möchte ich in diesem Artikel festhalten, so dass euch diese Erfahrung erspart bleiben kann.
Die Vorgeschichte
Da Container zustandslose Gebilde sind, nutze ich podman volumes, um die anfallenden Daten persistent zu speichern.
Als Einsteiger in die Thematik habe ich mich an der offiziellen Container-Dokumentation von Red Hat entlang gehangelt und bin den Anweisungen in Kapitel 3.4. Sharing files between two containers (die Dokumentation wurde überarbeitet; das Kapitel existiert so nicht mehr) gefolgt. Dort wird beschrieben, wie man den Volume-Pfad einer Variablen zuweist, welche später verwendet wird, um das Volume über den Pfad in den Container einzuhängen.
Da ich es nicht besser wusste, bin ich der Anleitung Schritt-für-Schritt gefolgt. Dies führte zu einer funktionierenden Konfiguration, in der meine Daten persistent gespeichert wurden.
Kommando ‚podman volume prune‘ und die Daten waren weg
Am Ende meiner Spielerei wollte ich das Spielfeld bereinigen. Dabei bin ich auf das Kommando podman volume prune gestoßen, welches laut podman-volume-prune(1) alle Volumens entfernt, die sich nicht in Verwendung befinden. Dies klang nach genau dem Befehl, nach dem ich gesucht habe.
TL;DR: Nach der Ausführung des Kommandos waren meine Volumes weg. Auch jene, die aktiv in laufenden Container-Instanzen eingehängt waren.
Die Analyse
Nach ein paar Tests und einer Internetrecherche stand die Ursache für das Verhalten fest. Diese ist im GitHub Issue #7862 dokumentiert und besagt, dass podman volume prune in Verwendung befindliche Volumes löscht, wenn diese über ihren Pfad und nicht über ihren Namen eingehängt wurden. Da ich wie oben beschrieben der Dokumentation von Red Hat strikt gefolgt bin, welche aber genau den Pfad und eben nicht den Namen verwendet, waren Ursache und Erklärung für den Datenverlust gefunden.
Die Folge
In Folge meiner Erfahrungen habe ich zwei Anfragen zur Produktverbesserung (englisch: Request For Enhancement oder kurz RFE) gestellt:
Bug 1914096 – Needs improvement: Building, running, and managing containers: 3.4. Sharing files between two containers
Die erste Anfrage ist an Red Hat adressiert, mit der Bitte, in der Dokumentation den Volume-Namen an Stelle des in einer Variablen gespeicherten Volume-Pfades zu benutzen. Damit sollte verhindert werden, dass andere, die der Dokumentation folgen, die gleichen Erfahrungen wie ich machen müssen.
Als Ziel wird die Veröffentlichung von RHEL 8.4 anvisiert. Dieses Release sollte im Mai bzw. Juni 2021 erscheinen. Ich bin gespannt. Ich würde mich über eine frühere Aktualisierung der Dokumentation freuen. Update 2021-01-25: Bereits am 20. Januar wurde eine neue Version der Dokumentation veröffentlicht. In dieser war nur noch ein kleiner Tippfehler enthalten. Der Bug wurde mit dem heutigen Datum (25.01.2021) geschlossen. So ist sichergestellt, dass hier niemand mehr in die Falle tappt. Vielen Dank ans RHEL-Docs-Team im Allgemeinen und Gabriela im Speziellen.
Die zweite Anfrage richtet sich an das Upstream-Projekt. Sie beinhaltet den Vorschlag, podman volume prune (um eine Option) zu erweitern, so dass die Liste der zu löschenden Volumes angezeigt wird, bevor man die Entfernung bestätigt. Stand 17.01.2021 existiert bereits ein Pull-Request, welcher dieses Thema adressiert.
Meinen Artikel „Kanboard im Container…“ habe ich entsprechend angepasst, so dass auch dort die Volumen-Namen zum Einhängen verwendet werden und nicht die Volume-Pfade.
Alte Erkenntnis bestätigt
Dieses Beispiel zeigt wieder einmal sehr deutlich, wie wichtig eine funktionierende Datensicherung ist. Denn sie ist die zwingende Voraussetzung, um im Fehlerfall Daten auch wiederherstellen zu können. Daher kann ich nur jedem raten, ein entsprechendes Datensicherungs- und Wiederherstellungs-Konzept zu implementieren, bevor man Daten in eine Anwendung tut, die einem am Herzen liegen oder von denen die Zukunft des Unternehmens abhängt.
Zum Stöbern führe ich im Folgenden einige Artikel aus diesem Blog auf, welche sich mit dem Thema Backup befassen:
Eine Lösung für den Upstream-Issue „RFE: Let `podman volume prune` show the volumes that are going to be removed“ wurde bereits am 27.01.2021 gemerged. Unter dem gleichen Namen hatte ich am 15.02.2021 einen RFE im Red Hat Bugzilla unter der Nummer 1928936 geöffnet. Dieser wechselte heute in den Status „Release Pending“ und kündigt an, dass der Fix in der Paketversion podman-3.3.0-0.4.el8 für RHEL 8 enthalten sein wird.
Ich erwarte das Paket im kommenden Release von RHEL 8.5.
Als Reverse-Proxy nutze ich nginx, welchen ich mittels sudo dnf -y install nginx installiert habe. Die Konfigurationsdatei /etc/nginx/nginx.conf habe ich wie folgt ergänzt:
Damit nimmt der NGINX Anfragen auf den TCP-Ports 80 und 443 an, wobei ein Redirect von Port 80 auf 443 erfolgt. Diese Anfragen leitet der NGINX an den TCP-Port 8080 des Kanboard-Pods weiter.
In „Kanboard im Container“ habe ich einen Pod ins Leben gerufen, welcher die Anwendung Kanboard und eine dazugehörige Postgresql-Datenbank mittels Container bereitstellt. Backup und Restore zu konfigurieren und zu testen, habe ich letztes Wochenende nicht mehr geschafft. Dies hole ich in diesem Artikel nach.
Da die Container selbst zustandslos sind, interessieren mich nur die persistent gespeicherten Daten, welche außerhalb der Container im Dateisystem des Hosts gespeichert werden.
Umgebung
Auf einer virtuellen Maschine mit dem Gastbetriebssystem RHEL 8 läuft ein podman-Pod namens kanboardpod. Dieser Pod beinhaltet neben dem Infrastruktur-Container, einen Kanboard-Container namens kanboard und einen Postgresql-Container namens pgsql_db.
Die persistenten Daten des Kanboard-Containers werden in den Volumes kanboard_data und kanboard_plugins gespeichert. Die Datenbank-Dateien der Postgresql-DB liegen im Volume pgsql_data.
Die Namen des Pods und der Container sind hilfreich, da die Container darüber referenziert werden können. So muss man nicht mit den sperrigen IDs hantieren.
Backup
Kein Restore ohne Backup! Kein Backup, kein Mitleid!
Ich habe im Folgenden beschriebe Ansätze für ein Backup. Wenn ihr noch weitere habt, freue ich mich über eure Eingaben.
Ansatz 1: Backup auf Dateiebene — verworfen
Dieser Ansatz liegt nahe und ist einfach umzusetzen.
Container stoppen
Verzeichnisse im Dateisystem sichern
Container wieder starten
Für meinen konkreten Anwendungsfall wäre dies auch ausreichend. Einen Dienst für die Dauer einer Datensicherung komplett stoppen zu müssen, ist jedoch nicht ideal. Daher schaue ich nach weiteren Möglichkeiten.
Ansatz 2: DB-Dump und Datei-Backup — Praktikabel aber möglicherweise inkonsistent.
Bei diesem Ansatz bleibt die Anwendung während der Datensicherung verfügbar. Während das Volume kanboard_data auf Dateiebene mittels tar gesichert wird, wird die Datenbank mittels pg_dump aus dem Container heraus gesichert. Das Backup-Skript sieht wie folgt aus:
Hinweis: Obiger Code-Schnipsel stammt aus der Kategorie Schnell-und-Schmutzig und sollte nicht in produktiven Umgebungen verwendet werden.
Der DB-Dump wird dabei direkt aus dem Container in mein Home-Verzeichnis geschrieben. Am Ende habe ich zwei unabhängige Dateien, die nun außerhalb der Container-Umgebung liegen. Da diese jedoch immer noch auf dem gleichen Host liegen, handelt es sich um kein richtiges Backup. Doch ist es nun nicht mehr schwer, sie auf ein anderes, entferntes Medium zu übertragen.
Der größte Nachteil dieses Ansatzes besteht darin, dass die Konsistenz der Sicherung nicht garantiert ist. Die Datenbank enthält Referenzen in das Dateisystem. Referenzen in der Datenbank und Inhalt des gesicherten Dateisystems müssen nicht in jedem Fall zueinander passen, da während der Sicherung weiter in der Anwendung gearbeitet werden kann.
Nun kann man natürlich vor der Sicherung den Container kanboard stoppen und anschließend wieder starten. Damit erhält man eine konsistente Sicherung zu dem Preis, dass die Anwendung temporär nicht verfügbar ist. Damit unterscheidet sich der Ansatz gegenüber Ansatz 1 nur noch darin, dass der Container pgsql_db online bleibt und man die DB mit pg_dump sichert, statt eine Sicherung auf Dateisystemebene zu machen.
Schön ist das nicht, doch mache ich es meiner Umgebung genau so.
Ansatz 3: Backup auf Basis eines konsistenten Dateisystem-Snapshots
Dies ist in meinen Augen der vernünftigste Ansatz.
Die persistenten Daten der Container liegen in einem Dateisystem. Unterstützt dieses Dateisystem Snapshots, können diese genutzt werden, um die Dateisysteminhalte zum Zeitpunkt des Snapshots auf das Backup-Medium zu übertragen und den Snapshot anschließend wieder zu entfernen. Anwendung und Datenbank können bei diesem Verfahren während der Sicherung weiterlaufen.
Das so erstellte Datenbank-Backup befindet sich allerdings in einem Zustand, als wäre die Datenbank unsauber beendet worden. Nach einem Restore werden demnach die WAL-Logs benötigt (siehe PostgreSQL 9.6.20 Documentation: 25.2. File System Level Backup).
Ich habe mich gegen diesen Ansatz entschieden, da mir in meiner Test-Umgebung noch die Erfahrung mit Dateisystem-Snapshots fehlt. Dies werde ich evtl. zu einem späteren Zeitpunkt unter die Lupe nehmen.
Restore
Ich habe mich für den Ansatz 2 entschieden. Damit habe ich folgende zwei Dateien:
kanboard.tgz – Enthält die persistenten Daten des Kanboards
kanboard.sql.gz – Enthält den Dump der Kanboard-Datenbank
Das tar-Archiv wird extrahiert und fertig. Um den DB-Dump mit dem Werkzeug pg_restore wieder einspielen zu können, muss dieser zuvor in ein Volume kopiert werden, das innerhalb des Postgresql-Containers zur Verfügung steht. Anschließend kann die Datenbank mit folgendem Befehl wiederhergestellt werden:
# pg_restore -C -d kanboard kanboard.sql
Fazit
Grundsätzlich habe ich Ziel Nummer 5 „Backup und Restore“ ebenfalls erreicht.
Der Restore erfordert noch einiges an Handarbeit und ist etwas fummelig. Soetwas möchte man in einer angespannten Situation nicht gerne haben. Hier ist noch etwas Feinschliff nötig.
Darüber hinaus kann ich mir vorstellen auch noch einen automatisierten Restore-Test zu etablieren, welcher prüft, ob sich ein erstellter DB-Dump auch wieder herstellen lässt. Das ist dann aber sicher ein eigenes Wochenendprojekt. Und nächstes Wochenende mache ich mal frei.
… aber das sind ja gleich zwei Dinge auf einmal. Richtig. Denn hier versuche ich, etwas nützliches (Kanboard) mit der Möglichkeit, etwas zu lernen (Container), zu kombinieren.
Inspiriert durch Dirks Artikel und einem darauf folgenden, regen E-Mail-Verkehr, widme ich mich mal wieder dem Thema Linux-Container. Zuletzt hatte ich mich ca. 2016/2017 damit befasst und es mit der Erkenntnis zu den Akten gelegt, dass es noch ein Hype und für den produktiven Einsatz wenig geeignet war. Mittlerweile hat sich die Lage etwas geändert. Einige Unternehmen haben sich des Themas angenommen und arbeiten daran, Linux-Container Enterprise-Ready zu gestalten. So nehme ich wahr, dass in meinem beruflichen Netzwerk seit ca. Anfang 2019 OpenShift-Cluster wie Pilze aus dem Boden schießen. Man könnte den Eindruck gewinnen, dass Red Hat diese Subskriptionen wie geschnitten Brot verkauft. Andere Hersteller scheinen den relativ jungen Markt nicht allein den roten Hüten überlassen zu wollen. So hat VMware mit vSphere 7 und Tanzu hier ebenfalls eine Lösung im Portfolio und auch SUSE scheint sich mit dem Kauf von Rancher in diesem Segment stärker zu engagieren.
Ich selbst möchte mein Wissen rund um dieses Thema auffrischen und habe mir daher folgendes Wochenendprojekt überlegt. Um Projekte, Aufgaben oder schlicht den Alltag besser zu organisieren, möchte ich zukünftig die Anwendung Kanboard nutzen. Diese Anwendung unterstützt die Aufgaben- bzw. Projekt-Organisation nach der Kanban-Methode. Sie macht einen minimalistischen Eindruck, kommt ohne viel Schnick-Schnack daher und scheint daher gut zu mir zu passen. Um gleichzeitig praktische Erfahrungen im Umgang mit Linux-Containern zu sammeln, werde ich Kanboard mit einer Postgresql-Datenbank mit Hilfe von zwei Containern betreiben.
In meinen Augen wird Docker in den nächsten Jahren sowohl als Firma wie auch als Werkzeug stetig an Bedeutung verlieren. Daher setze ich bei der Umsetzung meines Wochenend-Projekts auf die Werkzeuge podman, skopeo und buildah.
Ich gehe in diesem Text nicht auf die Konzepte, die Architektur, sowie die Vor- und Nachteile von Linux-Containern ein. Hierzu wurde in den letzten Jahren bereits genug an anderer Stelle geschrieben. Informationen zu diesen Themen finden sich in der — im Aufbau befindlichen — Linksammlung und am Ende dieses Artikels.
Umfeld
Als Basis für dieses Projekt dient mir eine virtuelle Maschine in meinem heimischen Labor. Als Betriebssystem nutze ich ein aktuelles RHEL 8 mit der kostenlosen Developer-Subskription. Diese VM dient mir als Host zum Ausführen diverser Linux-Container. Um die Container aus dem Netzwerk erreichbar zu machen, installiere ich NGINX aus den Paketquellen von RHEL 8. Dieser kümmert sich als Reverse-Proxy um die Portweiterleitung zu den Containern.
Ziele
Mit diesem Wochenendprojekt möchte ich folgende Ziele erreichen:
Bereitstellung der Anwendung Kanboard mittels Linux-Container
Nutzung von Postgresql mittels Container als Kanboard-Datenbank-Backend
Persistente Speicherung der Kanboard-Inhalte im Dateisystem des Hosts
Während Entwickler viel Schweiß und Tränen investiert haben, damit Dienste wie Apache oder NGINX nach ihrem Start die root-Rechte ablegen können, liefen die ersten Linux-Container durchgängig mit root-Rechten. Dies ist aus Sicht der IT-Sicherheit nicht wünschenswert. Daher ist es in meinen Augen erfreulich, dass es mittlerweile auch ohne root-Rechte geht; Kernel User Namespaces sei Dank.
Ich folge der Red Hat Dokumentation (Kapitel 1.4, [1]), um den User Alice für die Nutzung von rootless-Containern einzurichten.
Anschließend installiere ich wie in Kap. 1.3 [1] beschrieben die Container-Tools.
# yum module install -y container-tools
$ podman --version
podman version 2.0.5
Der Werkzeugkasten ist bestückt. Weiter zu Schritt 2.
Schritt 2: Container-Images suchen, inspizieren und herunterladen
Mit dem Kommando podman mache ich mich auf die Suche nach Containern für Kanboard.
$ podman search kanboard
INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
docker.io docker.io/kanboard/kanboard Official Docker image for Kanboard 34
docker.io docker.io/webhippie/kanboard Docker images for Kanboard 2 [OK]
docker.io docker.io/larueli/kanboard-nonroot Safe image for Kanboard as Non Root / Suitab... 0
docker.io docker.io/masker/kanboard use alpine linux build kanboard server 0
docker.io docker.io/xoxys/kanboard Deprecated 0
docker.io docker.io/dotriver/kanboard Kanboard on Alpine Linux + S6 Overlay 0
docker.io docker.io/thegeeklab/kanboard Custom image for Kanboard Kanban project man... 0
docker.io docker.io/jonats/kanboard-pi Raspberry Pi image for Kanboard 0
docker.io docker.io/bastilian/kanboard 0
docker.io docker.io/oriaks/kanboard Kanboard 0 [OK]
docker.io docker.io/kanboard/tests 0
docker.io docker.io/blufor/kanboard Kanboard with Postgres, SMTP and GitLab inte... 0 [OK]
docker.io docker.io/boomer/kanboard Kanboard is a simple visual task board web a... 0
docker.io docker.io/joshuacox/kanboard-redmine kanboard redmine importer 0 [OK]
docker.io docker.io/janost/kanboard-unit Kanboard + nginx unit, running rootless with... 0
docker.io docker.io/benoit/kanboard 0 [OK]
docker.io docker.io/lidstah/kanboard Kanboard armv71 debian (nginx/php7-fpm) base... 0
docker.io docker.io/doc75/kanboard 0
docker.io docker.io/witsec/kanboard Kanboard, with the option to filter (hide) s... 0 [OK]
docker.io docker.io/ionutalexandru97/kanboard-openshift Kanboard ready to be deployed on OpenShift 0
docker.io docker.io/hihouhou/kanboard simple kanboard 0 [OK]
docker.io docker.io/alxsdhm/kanboard kanboard image 0
docker.io docker.io/papango/kanboard 0
docker.io docker.io/mrtheduke/kanboard kanboard 0
docker.io docker.io/kvorobyev/kanboard_app
Herzlichen Glückwunsch. Die Trefferliste stellt für mich als SysAdmin einen Alptraum dar. Sämtliche Treffer stammen vom Docker-Hub, einem riesigen Misthaufen für Software (welcher durchaus ein paar Perlen enthalten kann). Von den 26 Treffern ist keiner als OFFICIAL markiert, lediglich die Anzahl STARS bietet einen Anhaltspunkt, welcher Container den meisten Zuspruch findet. In einer Produktiv-Umgebung sollte man sich jedoch nicht allein auf diese Sterne verlassen. Ich inspiziere das Container-Image mit den meisten Sternen mit skopeo:
$ skopeo inspect docker://docker.io/kanboard/kanboard | less
Die vollständige Ausgabe spare ich hier aus. Sie ist wenig hilfreich. Mit ein wenig Internet-Recherche ([2], [3] und [4]) bin ich hinreichend sicher, das „offizielle“ Container-Image des Projekts gefunden zu haben.
Als nächstes mache ich mich auf die Suche nach Postgresql:
$ podman search postgresql | wc -l
64
Naja, zumindest an Auswahl scheint es auch diesmal nicht zu mangeln. Hier komme ich so jedoch nicht weiter. Also nehme ich einen Webbrowser zur Hand und recherchiere ein geeignetes Container-Image unter der URL: https://catalog.redhat.com/software/containers/explore
Da ich Red Hat bereits zutraue, eine stabile und hinreichend sichere Enterprise Linux Distribution zu bauen, traue ich ihnen auch zu, ordentliche Container-Images für Postgresql zu bauen. Daher fasse ich folgende drei Kandidaten ins Auge:
Zu diesem Zeitpunkt (2020-12-27) fehlt Nr. 3 eine ordentliche Beschreibung. Dafür kommt dieses Image mit 6 offenen Sicherheitslücken daher. Nr. 2 besitzt nur 3 Schwachstellen und eine deutliche bessere Dokumentation zu dessen Verwendung. Und Nr. 1 ist zwar das Älteste, jedoch auch das mit einer guten Dokumentation und ohne Schwachstellen.
Kanboard erfordert Postgresql >= 9.4. Damit ist Nummer 1 mein Gewinner. Mit den beiden folgenden Kommandos hole ich mir die Kanboard- und Postgresql-Container-Images auf meinen Host.
Damit ist dieser Schritt abgeschlossen. In Schritt drei erstelle ich sogenannte Volumes, um Daten außerhalb der Container persistent im Dateisystem des Hosts speichern zu können.
Schritt 3: Persistenten Speicher für Container erzeugen
Nach dem Container-Mantra haben diese zustandslos zu sein. Dies bedeutet, dass in ihnen gespeicherte Daten verloren gehen, wenn der Container entfernt wird. Nun hat es die Elektronische Datenverarbeitung (EDV) so an sich, dass das Ergebnis der Verarbeitung häufig persistent zu speichern ist. Dies kann im Container-Universum mit sogenannten Volumes erledigt werden. Hierbei wird ein Verzeichnis vom Host in den Container eingehängt.
Für mein Projekt erstelle ich nach Kapitel 3.4 [1] folgende Volumes:
kanboard_data
kanboard_plugins
kanboard_ssl
pgsql_db
$ podman volume create VOLUMENAME
Um im Folgenden etwas leichter mit diesen Volumes arbeiten zu können, speichere ich den Einhängepfad in Variablen à la:
Die obige Streichung erfolgte, da dieser Schritt nicht notwendig ist und im weiteren Artikel nicht mit entsprechenden Variablen gearbeitet wird.
Schritt 4: Kanboard konfigurieren
Um eine angepasste, persistente config.php-Datei für den Kanboard-Container zu schreiben, ist etwas Vorarbeit notwendig. Der Kanboard-Container wird gestartet und das Volume „kanboard_data“ wird dabei in den Pfad /var/www/app/data gemountet. Anschließend starte ich eine Shell im Container und kopiere die Datei /var/www/app/config.default.php nach /var/www/app/data/config.php.
$ podman run -d --name kanboard -v kanboard_data:/var/www/app/data:Z kanboard/kanboard
93e6d7e3847fb94639b8fce89ddb93a3879a80522f95ed13dff91f6558594ac6
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
93e6d7e3847f docker.io/kanboard/kanboard:latest 5 seconds ago Up 5 seconds ago kanboard
$ podman exec -it 93e6d7e3847f /bin/bash
bash-5.0# cp /var/www/app/config.default.php /var/www/app/data/config.php
bash-5.0# exit
exit
$ podman stop 93e6d7e3847f && podman rm 93e6d7e3847f
$ vi $kanboard_data/config.php
Um Postgresql als Datenbank-Backend zu nutzen, werden folgende Werte in der config.php gesetzt:
// Run automatically database migrations
// If set to false, you will have to run manually the SQL migrations from the CLI during the next Kanboard upgrade
// Do not run the migrations from multiple processes at the same time (example: web page + background worker)
define('DB_RUN_MIGRATIONS', true);
// Database driver: sqlite, mysql or postgres (sqlite by default)
define('DB_DRIVER', 'postgres');
// Mysql/Postgres username
define('DB_USERNAME', 'root');
// Mysql/Postgres password
define('DB_PASSWORD', 'SuperSicheresPasswort');
// Mysql/Postgres hostname
define('DB_HOSTNAME', 'localhost');
// Mysql/Postgres database name
define('DB_NAME', 'kanboard');
// Mysql/Postgres custom port (null = default port)
define('DB_PORT', null);
Normalerweise würde man eine Anwendung niemals mit dem Datenbank-Root-User auf eine Datenbank zugreifen lassen. In dieser Umgebung ist es hingegen verschmerzbar, da nur die Daten des Kanboards in diesem Postgresql-Container gespeichert werden. Im Falle einer Kompromittierung verliere ich nur die zur Anwendung gehörende Datenbank.
Schritt 5: Pod erstellen und Container hinzufügen
Mit diesem Schritt habe ich etwas Mühe. Zuerst wollte ich einen Pod erstellen, den Kanboard- und Postgresql-Container zu diesem hinzufügen, um sie stets gemeinsam starten und stoppen zu können. Dies ist laut [1] und [7] der einfachste Weg. Allerdings habe ich dann in [5] und [7] gelesen, dass sich die Container eines Pods dessen IP, MAC und Port-Bindings teilen. Dies bedeutet, dass Portfreigaben für Kanboard (80 und 443 TCP) auch für den Postgresql-Container gültig sind. Dies möchte ich eigentlich nicht. Doch ist mir bisher nichts besseres eingefallen. Falls ihr Anregungen oder konkrete Beschreibungen habt, wie ich dies besser umsetzen kann, immer her damit.
Frickelpit hat mich in seinem Kommentar darauf hingewiesen, dass man den Zugriff auf den Port des Pods noch weiter beschränken kann, indem man diesen an 127.0.0.1 bindet. Ich habe unten stehenden Code-Block entsprechend aktualisiert.
Ich erstelle nun gemäß [7] einen neuen Pod, welcher den Kanboard-Container beinhaltet und für diesen Port-Bindings besitzt:
$ podman run -d --pod new:kanboardpod --name kanboard -p 127.0.0.1:8080:80 -v kanboard_data:/var/www/app/data:Z -v kanboard_plugins:/var/www/app/plugins:Z kanboard/kanboard
e62c7fa2ecf771f4085e788e9f0f7d24b7f87d487e9951a403847d8a7a2a6471
$ podman pod ps
POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID
d7afa6821382 kanboardpod Running 8 seconds ago 2 6b065fe7ecc7
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6b065fe7ecc7 k8s.gcr.io/pause:3.2 10 seconds ago Up 10 seconds ago 0.0.0.0:8080->80/tcp d7afa6821382-infra
e62c7fa2ecf7 docker.io/kanboard/kanboard:latest 10 seconds ago Up 10 seconds ago 0.0.0.0:8080->80/tcp kanboard
Im zweiten Schritt füge ich den Postgresql-Container hinzu:
$ podman run -d --pod kanboardpod --name pgsql_db -e POSTGRESQL_USER=root -e POSTGRESQL_PASSWORD=SuperGeheimesPasswort -e POSTGRESQL_DATABASE=kanboard -v pgsql_data:/var/lib/pgsql/data:Z rhel8/postgresql-96
c242a4b9b57d53a822585c9eb83d081d5abbd40cb2b5952aee4457fee041e128
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6b065fe7ecc7 k8s.gcr.io/pause:3.2 2 minutes ago Up 2 minutes ago 0.0.0.0:8080->80/tcp d7afa6821382-infra
c242a4b9b57d registry.redhat.io/rhel8/postgresql-96:latest run-postgresql 3 seconds ago Up 3 seconds ago 0.0.0.0:8080->80/tcp pgsql_db
e62c7fa2ecf7 docker.io/kanboard/kanboard:latest 2 minutes ago Up 2 minutes ago 0.0.0.0:8080->80/tcp kanboard
Nun läuft ein Pod mit drei Containern (Infra-, Kanboard- und Postgresql-Container). Rufe ich http://IP-DES-HOSTS:8080 in einem Webbrowser auf, begrüßt mich bereits die Kanboard-Anmeldemaske (Bild 1).
Bild 1: Kanboard-Anmeldemaske
Schritt 6: Nacharbeiten
Zwar konnte ich mich bereits an der Kanboard-Anwendung anmelden, neue Nutzer erstellen und Profileinstellungen verwalten, doch beim Dateiupload klemmte es noch. Hier musste ich in der config.php-Datei des Kanboard-Containers den folgenen Standardwert, wie im Codeblock gezeigt, angepassen:
// Folder for uploaded files (must be writeable by the web server user)
// Folgende Zeilen wurden auskommentiert
// define('FILES_DIR', DATA_DIR.DIRECTORY_SEPARATOR.'files');
// Folgender Eintrag wurde hinzugefuegt
define('FILES_DIR', 'data/files');
Abschließend habe ich den Kanboard-Container mittels podman restart kanboard neugestartet.
Fazit
Bei der Internet-Recherche nach guter Dokumentation und der Arbeit mit einigen Container-Registries erinnere ich mich an ein Zitat:
Das Internet ist ein großer Misthaufen, in dem man allerdings auch kleine Schätze und Perlen finden kann.
Joseph Weizenbaum, Vortrag in Hamburg am 2. Mai 2001, heise.de
Bisher wurden die Ziele 1-3 erreicht. Die dabei verwendeten Befehlszeilen besitzen eine beachtliche Länge. Hier bietet es sich an, die Befehle in kurze Shell-Wrapper zu verpacken.
Die Ziele 4 und 5 werde ich in einem Folgeartikel, an einem anderen Wochenende, in Angriff nehmen. Und auch der Frage, wie man diesen Verhau am besten aktualisiert und Updates implementiert, werde ich noch nachgehen.
Ihr habt bis hierhin durchgehalten? Dann danke ich euch für euer Interesse. Was haltet ihr von diesem Wochend-Projekt? Wieviel Sinn bzw. Unsinn steckt darin? Bitte lasst es mich in den Kommentaren oder auch gern per E-Mail wissen.
Das Jahr 2020 war schon ein paar Wochen alt, als ich verkündete, was euch 2020 hier erwartet. Ich glaube, ich habe mich an den Ausblick gehalten.
Das Jahr fing ruhig an, bevor es unser aller Leben radikal veränderte. War mein Berufsleben2019 noch vom Pendeln zur Dienststelle und zurück geprägt, hat die Pandemie auch meinen Arbeitsplatz radikal verändert. Seit Mitte März arbeite ich konsequent im heimischen Arbeitszimmer. Seither habe ich screen in den Ruhestand entlassen und arbeite konsequent mit tmux und xpanes.
Auch die berufliche Kommunikation hat sich stark verändert; in meinen Augen jedoch weder zum Positiven noch zum Negativen. Bisher bin ich im Home-Office sehr zufrieden. Eine Rückkehr in die Dienststelle kann ich mir aktuell hingegen nicht vorstellen.
Mitte des Jahres durfte ich mit einem Team rund um Mohit Goyal (Senior Principal Product Manager, Red Hat) zusammen arbeiten und habe Red Hat Insights unter die Lupe genommen. Dabei herausgekommen ist unter anderem folgende Artikelserie:
Zusammen mit einem Kollegen habe ich noch ein Tutorial zur Nutzung des DNS-Alias-Modus mit dem acme.sh-Client geschrieben. Wir haben einiges an positiven Rückmeldungen dafür bekommen, was mich persönlich sehr gefreut hat.
Wie an den Artikeln zu erkennen ist, lag der Fokus in diesem Jahr auf Technologien und Produkten von Red Hat. Dies wird sich in 2021 vermutlich in Teilen fortsetzen. Vermutlich wird hier dann vermehrt etwas zu Linux-Containern zu lesen sein, mit denen ich mich etwas ausführlicher beschäftigen möchte.
Darüber hinaus plane ich die Einführung einer neuen Kategorie, deren Name noch nicht feststeht. In dieser möchte ich technische Sachverhalte möglichst einfach erklären, so dass auch Menschen ohne IT-Ausbildung verstehen können, wie das Internet und unsere digitale Welt funktionieren.
Ich wünsche euch allen einen guten Rutsch ins Jahr 2021!