== pods ==

Pods sind ein bedeutender Unterschied zwischen den beiden Container-Varianten [Docker] und [Podman]. Ein Pod fasst einige der Ressourcen, die für verschiedene Container vom Betriebssystem aufgeteilt und dupliziert werden, zusammen. Insbesondere ist das der Netzwerkstack, so das die verschiedenen Container sich nicht über offene Ports auf dem Hostsystem (und damit über ein Bridge-Device und jeweils einen Connector für das Portmapping) unterhalten, sondern innerhalb eines Pods können die Container sich mit einem simplen Zugriff auf localhost erreichen.

Das bedeutet also, das die Container innerhalb etwas effizienter sind und das nach aussen keine Ports offen sind, die am Ende gar nicht exportiert werden sollen. So kann z.B. der Davical auf einem Apache (unverschlüsselt, also ohne ssl) auf Port 8001 innerhalb des Pods laufen, wo dann der Nginx als Reverse Proxy die Daten unverschlüsselt abholt und dann seinerseits per ssl auf Port 443 zur Verfügung stellt. Nur der Port 443 ist von außen sichtbar, weil nur dieser vom Pod propagiert wird.

== Beispiel-Aufgabe ==

Ich wollte mit diesem Feature experimentieren und habe dazu einen Server gespiegelt. Der Plan war, auf diesem drei Container laufen zu lassen, mit denen ich bereits etwas Erfahrung hatte. Es soll ein [Davical] sowie ein [WebDav im Container] als Server laufen. Außerdem möchte ich, das ein Nginx als [Reverse Proxy im Container] läuft, der die Verbindung zur Außenwelt managt und dabei für SSL-Verschlüsselung sorgt. Die beiden Nutzlast-Container sollen also von aussen gar nicht direkt erreichbar sein.

== pod erzeugen ==

Ich erzeuge einen pod mit:

  podman pod create --name webserverpod -p 80:80 -p 443:443

Hierbei ist anzumerken, das an dieser Stelle bereits festgelegt werden muss, welche Ports nach außen erreichbar sein sollen (welche Ports propagiert werden, um im Podman-Sprech zu bleiben).

== erster Container: Reverse Proxy mit Nginx ==

Nach dem manuellen Erzeugen des Pods wie oben startet man den Container mit "--pod werbserverpod" und ohne die -p - Optionen.

Oder, noch kürzer: Man lässt den Befehl oben ganz weg und startet direkt den ersten Container (also z.B. den reverse Proxy, der ja auch die Ports nach aussen betreibt), beschreibt dort die Port mit -p und schreibt dann "--pod new:webserverpod". Das "new:" sorgt dafür, das ein neuer pod erzeugt wird, der die angegebenen Ports propagiert.

  podman run -d --name nginx --pod webserverpod \
  -v /var/nginx/data/live/:/etc/letsencrypt/live \
  -v /var/nginx/config/options-ssl-nginx.conf:/etc/letsencrypt/options-ssl-nginx.conf \
  -v /var/nginx/config/meine_sites.conf:/etc/nginx/sites-enabled/default \
  -e TZ=Europe/Berlin ubuntu/nginx 

''(Wer genau wissen will, wie dieser Container aufgesetzt ist, findet unter [Reverse Proxy im Container] mehr dazu)''

== zweiter Container: Davical ==

Die erste echte Nutzlast kann man dann mit dem [Davical] starten.

Im Gegensatz zur meiner vorherigen Konfiguration läuft der Davical nun auf Port 8001, weil innerhalb des pods alle Server in einem einzigen Netzwerkstack laufen. Also darf er nicht die 80 und die 443 benutzen, die der Nginx bereits benutzt. Da die Konfiguration des Apache im Davical-Container etwas störrisch war, habe ich hier noch zwei Dateien mit -v überlagern müssen.

  podman run -d --name davical --pod webserverpod \
  -v /var/davical/data:/var/lib/postgresql/data -v /var/davical/config/:/config \
  -v /var/davical/config/httpd.conf:/etc/apache2/httpd.conf \
  -v /var/davical/config/emptyfile:/etc/apache2/conf.d/ssl.conf \
  -v /var/davical/config/ldap.conf:/etc/openldap/ldap.conf \
  -e HOST_NAME="caldav.thomasbayen.de" -e TIME_ZONE='Europe/Berlin' \
  datze/davical_https 

''(Wer genau wissen will, wie dieser Container aufgesetzt ist, findet unter [Davical] mehr dazu)''

Die Datei httpd.conf, die ich hier einbinde, ist eine genaue Kopie des Originals, in der ich die Zeile "Listen 80" durch "Listen 8001" ersetzt habe. Ebenso musst ich die Datei ssl.conf stillegen, da sie automatisch für einen Default Server einen Port auf 443 öffnete.

Fazit: Herauszufinden, wie man den Port entsprechend von 80 und 443 auf 8001 verlegt, war nicht ganz trivial, weil man dazu die internen Zusammenhänge des Containers und der Apache-Konfiguration verstehen musste. Eigentlich ist das genau die Art Probleme, der ich aus dem Weg gehen wollte, als ich mir gedacht habe, die SSL-Verwaltung durch den Reverse Proxy an einer Stelle zusammenzufassen.

Fazit 2: Dinge, die der Erbauer des Containers nicht bereits bedacht hat (wie die Änderung des Ports) können unangenehm kompliziert werden, bis man sie konfiguriert hat. Möchte man sowas machen, freut man sich, wenn das Container-Image kein superschlankes ohne alles ist (die auf dem für diesen Zweck klein-optimierten Alpine-Linux laufenden Images enthalten oft nicht mal eine bash, geschweige denn einen editor oder less usw., was beim debuggen recht lästig werden kann)


== dritter Container: [WebDAV] ==

  podman run -d --name webdav \
  -v /var/webdav/data:/var/lib/dav/ \
  -e AUTH_TYPE=Basic -e USERNAME=davuser -e 'PASSWORD=geheimesPasswort!' \
  -d bytemark/webdav 

''(Wer genau wissen will, wie dieser Container aufgesetzt ist, findet unter [WebDav im Container] mehr dazu)''

=== besonderer Spaß bei der Änderung des Ports ===

Hier gibt es ein Problem, das erst noch gelöst werden muss. Der Webdav-Container ist wieder nicht dafür eingerichtet, das man den Port konfigurieren kann, auf dem er sich der Welt zeigt. Allerdings startet das ganze Image nicht, so das ich weder "podman exec" noch "podman cp" benutzen konnte, um die Dateien aus dem Image herauszukopieren, damit ich sie verändern konnte (um sie später mit -v wieder einzubinden).

Also habe ich einen anderen Weg beschritten und die Dateien direkt im Image verändert. Man kann dann mit diesem Image arbeiten und sich diese Befehle merken, falls man es mal neu starten will. So habe ich es hier im Beispiel gezeigt.

Es gibt aber auch bessere Methoden: Man kann ein dockerfile schreiben und so Befehle angeben, mit denen ein neues Image aus dem originalen erzeugt werden kann. Das ist dann im Zweifel auch nach dem nächsten Update des Basisimages wieder mit aktuell.

Ich habe den abenteuerlichen Weg beschritten und das Image gemountet und dann manuell (bzw. per sed) manipuliert.

  podman mount webdav
  cd ... (wie angezeigt)
  sed -e 's|Listen 80|Listen 8002|' usr/local/apache2/conf/httpd.conf
  sed -e 's|:80>|:8002>|' -i usr/local/apache2/conf/sites-available/default.conf
  podman umount webdav
  podman start webdav 

== Zusammenspiel und Fazit ==

Bei mir liefen am Ende alle drei Container und das Zusammenspiel funktionierte gut. Ich konnte die beiden Dienste-Server unter unterschiedlichen Namen ansprechen und beide reagierten wie gewohnt.

Da alle Container einen gemeinsamen Netwerkstack benutzen, können nicht alle auf Port 80 laufen, wie die Konfigurationen es voraussetzen. Das bedeutet relativ mühevolle Anpassung. Eigentlich wollten wir uns ja genau sowas ersparen mit all dem Container-Kram, dachte ich mir.

Ich vermute, das der direkte Zugriff über den gemeinsamen Netzwerkstack performanter ist als wenn die beiden Container völlig unterschiedliche Umgebungen haben, aus denen die Daten erstmal herausgebraucht und in den nächsten wieder reingebracht werden müssen. Ich habe allerdings keine genauere Untersuchung hierzu gesehen. Schön ist auch, das die Ports der Nutzlast-Server nicht nach außen, also noch nicht mal aus dem Host-Betriebssystem, erreichbar sind. Natürlich wäre dieses Problem aber auch mit einer einfachen Firewall-Regel lösbar geworden.

Eine denkbare Zwischenlösung ist auch noch, das man ein eigenes podman Netzwerk einrichtet. Das bedeutet, das es eine Bridge zwischen den Containern gibt, die nicht von außen her zugänglich ist, die es aber dennoch erlaubt, das die Container sich untereinander verbinden. Der grosse Vorteil wäre, das hier jeder Container eine eigene IP-Adresse hat und sich somit dann auch siene Ports selber aussuchen kann. Es könnten also alle Nutzlast-Server auf Port 80 laufen und der Reverse Proxy würde diese dann über die IP-Adresse in der Podman Netzwerkbridge ansprechen. Diesen Weg habe ich persönlich bisher noch nicht ausprobiert.

== Links ==

* https://developers.redhat.com/blog/2019/01/15/podman-managing-containers-pods#the_cli__podman_pod - Eine ganz gute Anleitung zum Thema von Redhat

[{Tag ServerDienste Cloud EigeneWolke Container}]