Container mit Podman auf RHEL ausführen

Red Hat Enterprise LinuxRed Hat Enterprise LinuxBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Lab lernen Sie, wie Sie eine mehrschichtige Webanwendung mit Podman auf Red Hat Enterprise Linux (RHEL) bereitstellen. Sie erstellen eine Komplettlösung, indem Sie einen MariaDB-Datenbankcontainer als Backend und einen Apache-Webserver-Container als Frontend bereitstellen. Diese praktische Erfahrung führt Sie durch die wesentlichen Schritte der containerisierten Anwendungsbereitstellung, von der ersten Konfiguration bis zur öffentlichen Zugänglichkeit des Dienstes.

Sie beginnen mit dem Ausführen eines MariaDB-Containers und dessen Konfiguration beim Start mit Umgebungsvariablen. Als Nächstes konfigurieren Sie persistenten Speicher, um die Datenbeständigkeit für die Datenbank sicherzustellen, und erstellen ein benutzerdefiniertes Netzwerk für die Containerkommunikation. Anschließend stellen Sie den Apache-Webserver bereit, legen dessen Port offen, um die Konnektivität zu testen, und lernen schließlich, wie Sie den Container als systemd-Dienst für einen robusten, automatisierten Betrieb verwalten.

Ausführen eines MariaDB-Datenbankcontainers mit Umgebungsvariablen

In diesem Schritt lernen Sie, wie Sie eine containerisierte Anwendung ausführen und beim Start mithilfe von Umgebungsvariablen konfigurieren. Dies ist eine grundlegende Fähigkeit im Containermanagement, die flexible und sichere Bereitstellungen ermöglicht. Wir verwenden das offizielle MariaDB-Image als Beispiel, da es mehrere Konfigurationsparameter zur Initialisierung einer Datenbank benötigt.

Stellen Sie zunächst sicher, dass Sie sich im richtigen Arbeitsverzeichnis befinden. Alle Arbeiten für dieses Lab werden im Verzeichnis ~/project durchgeführt.

cd ~/project

Bevor Sie einen Container ausführen, ist es gute Praxis, das Image explizit aus der Registry zu ziehen. Dies stellt sicher, dass Sie die richtige Version lokal haben. Wir verwenden für dieses Lab das Image mariadb:10.6, um die Konsistenz zu gewährleisten.

podman pull mariadb:10.6

Wählen Sie das Image mariadb:10.6 aus der Docker-Registry.

Sie sollten eine Ausgabe sehen, die anzeigt, dass das Image heruntergeladen und extrahiert wird.

10.6: Pulling from library/mariadb
...
Status: Downloaded newer image for mariadb:10.6
docker.io/library/mariadb:10.6

Jetzt können Sie den MariaDB-Container ausführen. Der Befehl podman run erstellt und startet einen neuen Container. Wir verwenden mehrere Flags:

  • -d: Führt den Container im Detached-Modus (im Hintergrund) aus.
  • --name mariadb_server: Weist unserem Container einen einprägsamen Namen zu.
  • -e VARIABLE=value: Setzt eine Umgebungsvariable innerhalb des Containers. Das MariaDB-Image verwendet diese, um die Datenbank beim ersten Start zu konfigurieren.

Führen Sie den folgenden Befehl aus, um Ihren MariaDB-Container zu starten. Wir setzen das Root-Passwort und erstellen außerdem eine neue Datenbank namens webappdb mit dem dedizierten Benutzer webappuser.

podman run -d \
  --name mariadb_server \
  -e MARIADB_ROOT_PASSWORD=supersecret \
  -e MARIADB_DATABASE=webappdb \
  -e MARIADB_USER=webappuser \
  -e MARIADB_PASSWORD=userpass \
  mariadb:10.6

Der Befehl gibt eine lange Container-ID aus, die bestätigt, dass der Container erstellt wurde.

a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2

Um zu überprüfen, ob der Container läuft, verwenden Sie den Befehl podman ps.

podman ps

Sie sollten mariadb_server in der Liste der laufenden Container sehen.

CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS      NAMES
a1b2c3d4e5f6   mariadb:10.6   "docker-entrypoint.s…"   15 seconds ago   Up 14 seconds   3306/tcp   mariadb_server

Schließlich überprüfen wir die Container-Logs, um sicherzustellen, dass die Datenbank mithilfe der von uns bereitgestellten Umgebungsvariablen korrekt initialisiert wurde.

podman logs mariadb_server

Scrollen Sie durch die Logs. Sie suchen nach einer Zeile, die anzeigt, dass der Server bereit für Verbindungen ist, was einen erfolgreichen Start bestätigt. Die Ausgabe ist lang, aber eine wichtige Erfolgsmeldung am Ende sieht so aus:

...
2024-05-20 10:30:00+00:00 [Note] [Entrypoint]: /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/
...
2024-05-20 10:30:15+00:00 [Note] mariadbd: ready for connections.
Version: '10.6.x-MariaDB-1:10.6.x+maria~ubu2004'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution

Sie haben erfolgreich einen MariaDB-Container mit Umgebungsvariablen gestartet und konfiguriert.

Konfigurieren von persistentem Speicher für den MariaDB-Container

In diesem Schritt lernen Sie, wie Sie persistenten Speicher für einen Container konfigurieren. Standardmäßig werden alle Daten, die innerhalb eines Containers erstellt werden, in einer beschreibbaren Schicht gespeichert, die an den Lebenszyklus des Containers gebunden ist. Wenn Sie den Container entfernen, gehen alle diese Daten verloren. Für zustandsbehaftete Anwendungen wie Datenbanken ist dies nicht ideal. Um dies zu lösen, verwenden wir Podman-Volumes oder Bind-Mounts, um die Daten auf dem Host-Dateisystem zu speichern, unabhängig vom Container.

Zuerst müssen wir den Container entfernen, den wir im vorherigen Schritt erstellt haben, da wir ihn mit einer neuen Speicherkonfiguration neu starten werden.

Stoppen Sie den laufenden mariadb_server-Container:

podman stop mariadb_server

Sie sehen den Namen des Containers als Ausgabe, was bestätigt, dass der Befehl empfangen wurde.

mariadb_server

Entfernen Sie nun den gestoppten Container:

podman rm mariadb_server

Auch hier wird der Name des Containers zurückgegeben.

mariadb_server

Als Nächstes erstellen Sie ein Verzeichnis auf Ihrem Host-Rechner innerhalb des Verzeichnisses ~/project. Dieses Verzeichnis enthält die MariaDB-Datenbankdateien.

mkdir ~/project/mariadb_data

Bei der Verwendung von Podman im Rootless-Modus müssen wir die korrekten Berechtigungen für das gemountete Verzeichnis festlegen. Der MariaDB-Container wird als bestimmter Benutzer (UID 999) ausgeführt, daher müssen wir sicherstellen, dass das Verzeichnis zugänglich ist. Wir verwenden das Flag --userns=keep-id und legen die entsprechenden Berechtigungen fest:

chmod 755 ~/project/mariadb_data

Führen Sie nun den MariaDB-Container erneut aus. Dieser Befehl ähnelt dem aus dem vorherigen Schritt, jedoch mit dem Zusatz des Flags -v und --userns=keep-id, um die Benutzer-Namespace-Zuordnung ordnungsgemäß zu handhaben. Das Flag -v mountet das Verzeichnis ~/project/mariadb_data von Ihrem Host in das Verzeichnis /var/lib/mysql innerhalb des Containers, wo MariaDB seine Daten speichert. Wir verwenden $(pwd)/mariadb_data, um den erforderlichen absoluten Pfad für den podman-Befehl bereitzustellen.

podman run -d \
  --name mariadb_server \
  --userns=keep-id \
  -e MARIADB_ROOT_PASSWORD=supersecret \
  -e MARIADB_DATABASE=webappdb \
  -e MARIADB_USER=webappuser \
  -e MARIADB_PASSWORD=userpass \
  -v $(pwd)/mariadb_data:/var/lib/mysql:Z \
  mariadb:10.6

Das Suffix :Z beim Volume-Mount weist Podman an, den Inhalt mit einem privaten, unshared Label neu zu kennzeichnen, was für die SELinux-Kompatibilität wichtig ist.

Nachdem der Container gestartet wurde, können Sie überprüfen, ob die Daten auf Ihrem Host-Rechner gespeichert werden. Listen Sie den Inhalt des Verzeichnisses ~/project/mariadb_data auf.

ls -l ~/project/mariadb_data

Da die Datenbank-Engine des Containers initialisiert wurde, sehen Sie mehrere Dateien und Verzeichnisse, die innerhalb von ~/project/mariadb_data erstellt wurden. Dies bestätigt, dass Ihre Daten jetzt persistent sind. Selbst wenn Sie den Container entfernen, bleiben diese Daten erhalten.

total 110632
-rw-rw---- 1 labex labex    16384 May 20 10:45 aria_log.00000001
-rw-rw---- 1 labex labex       52 May 20 10:45 aria_log_control
-rw-rw---- 1 labex labex      983 May 20 10:45 ib_buffer_pool
-rw-rw---- 1 labex labex 12582912 May 20 10:45 ibdata1
-rw-rw---- 1 labex labex 50331648 May 20 10:45 ib_logfile0
-rw-rw---- 1 labex labex 50331648 May 20 10:45 ib_logfile1
drwx------ 2 labex labex     4096 May 20 10:45 mysql
drwx------ 2 labex labex     4096 May 20 10:45 performance_schema
drwx------ 2 labex labex     4096 May 20 10:45 sys
drwx------ 2 labex labex     4096 May 20 10:45 webappdb

Sie haben Ihren MariaDB-Container erfolgreich so konfiguriert, dass er persistenten Speicher verwendet, wodurch sichergestellt wird, dass Ihre Datenbankdaten Container-Neustarts und -Entfernungen überleben.

Erstellen eines benutzerdefinierten Netzwerks und Bereitstellen eines Apache-Webservers

In diesem Schritt erstellen Sie ein benutzerdefiniertes Netzwerk für Ihre Container und stellen einen Apache-Webserver bereit. Während Podman ein Standardnetzwerk bereitstellt, ist die Verwendung benutzerdefinierter Netzwerke eine Best Practice. Sie bieten eine bessere Isolation und, was am wichtigsten ist, ermöglichen die automatische DNS-Auflösung zwischen Containern. Dadurch können Container über ihre Namen miteinander kommunizieren, was zuverlässiger ist als die Verwendung von IP-Adressen, die sich ändern können.

Zuerst erstellen wir ein benutzerdefiniertes Bridge-Netzwerk für unsere Anwendung. Wir nennen es webapp-network.

podman network create webapp-network

Der Befehl gibt den Namen des neu erstellten Netzwerks aus.

webapp-network

Sie können alle Podman-Netzwerke auflisten, um zu bestätigen, dass Ihres erfolgreich erstellt wurde.

podman network ls

Sie sollten webapp-network in der Liste zusammen mit den Standardnetzwerken sehen.

NETWORK ID     NAME               DRIVER    SCOPE
...
f1e2d3c4b5a6   webapp-network     bridge    local
...

Als Nächstes müssen wir unseren mariadb_server-Container in diesem neuen Netzwerk neu erstellen. Aufgrund der Netzwerk-Backend-Konfiguration in dieser Umgebung können wir einen bestehenden Container nicht mit einem neuen Netzwerk verbinden. Stattdessen stoppen und erstellen wir den Container mit der neuen Netzwerkkonfiguration neu.

Stoppen Sie den laufenden mariadb_server-Container:

podman stop mariadb_server

Entfernen Sie den gestoppten Container:

podman rm mariadb_server

Erstellen Sie nun den MariaDB-Container mit dem neuen Netzwerk neu. Dieser Befehl ähnelt dem aus dem vorherigen Schritt, jedoch mit dem Zusatz des Flags --network webapp-network:

podman run -d \
  --name mariadb_server \
  --network webapp-network \
  --userns=keep-id \
  -e MARIADB_ROOT_PASSWORD=supersecret \
  -e MARIADB_DATABASE=webappdb \
  -e MARIADB_USER=webappuser \
  -e MARIADB_PASSWORD=userpass \
  -v $(pwd)/mariadb_data:/var/lib/mysql:Z \
  mariadb:10.6

Lassen Sie uns nun unseren Webserver bereitstellen. Wir verwenden das offizielle Apache httpd-Image. Erstellen Sie zuerst ein Verzeichnis auf dem Host, um die Dateien Ihrer Website zu speichern.

mkdir ~/project/webapp_content

Erstellen Sie eine einfache index.html-Datei in diesem neuen Verzeichnis. Dies ist die Homepage unserer Webanwendung.

echo "<h1>Welcome to My Web App</h1>" > ~/project/webapp_content/index.html

Legen Sie die korrekten Berechtigungen für das Webapp-Inhaltsverzeichnis fest, um sicherzustellen, dass der Apache-Container auf die Dateien zugreifen kann:

chmod 755 ~/project/webapp_content

Führen Sie nun den Apache httpd-Container aus. Wir verbinden ihn mit unserem webapp-network und mounten das Verzeichnis webapp_content als Volume. Dies stellt sicher, dass der Webserver die von uns gerade erstellte Datei index.html bereitstellen kann.

podman run -d \
  --name web_server \
  --network webapp-network \
  -v $(pwd)/webapp_content:/usr/local/apache2/htdocs/:Z \
  httpd:2.4

Lassen Sie uns die Optionen aufschlüsseln:

  • --network webapp-network: Verbindet den neuen Container mit unserem benutzerdefinierten Netzwerk.
  • -v $(pwd)/webapp_content:/usr/local/apache2/htdocs/:Z: Dies mountet unser lokales Verzeichnis webapp_content in den Container unter /usr/local/apache2/htdocs/, dem Standardverzeichnis, aus dem Apache Dateien bereitstellt. Das Suffix :Z weist Podman an, den Inhalt mit einem privaten, unshared Label für die SELinux-Kompatibilität neu zu kennzeichnen.

Überprüfen Sie, ob beide Container ausgeführt werden.

podman ps

Sie sollten jetzt sowohl mariadb_server als auch web_server in der Liste der laufenden Container sehen.

CONTAINER ID  IMAGE                           COMMAND           CREATED         STATUS         PORTS       NAMES
6a3f46c0ab3a  docker.io/library/mariadb:10.6  mariadbd          29 seconds ago  Up 29 seconds  3306/tcp    mariadb_server
da5d52ce9c41  docker.io/library/httpd:2.4     httpd-foreground  7 seconds ago   Up 7 seconds   80/tcp      web_server

Beide Container befinden sich jetzt im selben benutzerdefinierten Netzwerk und können über den Namen miteinander kommunizieren.

Den Webserver-Port freigeben und die Konnektivität testen

In diesem Schritt lernen Sie, wie Sie den Port eines Containers für den Host-Rechner freigeben, wodurch der Dienst von außerhalb des isolierten Netzwerks des Containers zugänglich wird. Unser Apache-Webserver läuft, aber wir können noch nicht von unserem Host-Browser oder der Befehlszeile darauf zugreifen. Wir werden dies beheben, indem wir den Port des Containers veröffentlichen.

Port-Mappings werden definiert, wenn ein Container erstellt wird. Daher müssen wir zuerst den web_server-Container, den wir im vorherigen Schritt erstellt haben, stoppen und entfernen. Machen Sie sich keine Sorgen um den Website-Inhalt; er ist sicher im Verzeichnis ~/project/webapp_content auf unserem Host, da wir ein Bind-Mount verwendet haben.

Zuerst stoppen Sie den Container:

podman stop web_server
web_server

Entfernen Sie als Nächstes den gestoppten Container:

podman rm web_server
web_server

Nun werden wir den web_server-Container erneut ausführen, aber dieses Mal fügen wir das Flag -p (oder --publish) hinzu, um einen Port vom Host auf einen Port im Container abzubilden. Wir werden Port 8080 auf dem Host auf Port 80 (dem Standard-HTTP-Port) innerhalb des Containers abbilden.

podman run -d \
  --name web_server \
  --network webapp-network \
  -v $(pwd)/webapp_content:/usr/local/apache2/htdocs/:Z \
  -p 8080:80 \
  httpd:2.4

Das neue Flag -p 8080:80 weist Podman an, den gesamten Datenverkehr von Port 8080 auf dem Host an Port 80 innerhalb des web_server-Containers weiterzuleiten.

Lassen Sie uns mit podman ps überprüfen, ob der Container läuft und der Port korrekt abgebildet ist.

podman ps

Beachten Sie die Spalte PORTS für den web_server-Container. Sie zeigt jetzt die Abbildung von 0.0.0.0:8080 auf 80/tcp an, was darauf hindeutet, dass der Port erfolgreich freigegeben wurde.

CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                  NAMES
c5d4e3f2a1b6   httpd:2.4      "httpd-foreground"       10 seconds ago   Up 9 seconds    0.0.0.0:8080->80/tcp   web_server
a1b2c3d4e5f6   mariadb:10.6   "docker-entrypoint.s…"   25 minutes ago   Up 25 minutes   3306/tcp               mariadb_server

Schließlich testen wir die Konnektivität von unserem Host-Rechner aus mit dem Befehl curl. Dieser sendet eine HTTP-Anfrage an localhost auf Port 8080.

curl http://localhost:8080

Sie sollten den HTML-Inhalt aus Ihrer index.html-Datei als Ausgabe sehen, was bestätigt, dass Ihr Webserver jetzt vom Host aus zugänglich ist.

<h1>Welcome to My Web App</h1>

Sie haben Ihren containerisierten Webserver erfolgreich für den Host-Rechner freigegeben, ein entscheidender Schritt, um Anwendungen für Benutzer verfügbar zu machen.

Verwalten des Webserver-Containers als systemd-Dienst

In diesem letzten Schritt lernen Sie, wie Sie einen Container so konfigurieren, dass er automatisch startet, um sicherzustellen, dass Ihr Dienst gegen Abstürze oder Systemneustarts widerstandsfähig ist. Auf einem Standard-Red Hat Enterprise Linux-System ist systemd das primäre Werkzeug zur Verwaltung von Diensten. Die Podman-Umgebung in diesem Lab verwendet jedoch systemd nicht, um Container direkt zu verwalten.

Stattdessen werden wir das gleiche Ergebnis – automatische Neustarts des Dienstes – mit den integrierten Restart-Richtlinien von Podman erreichen. Dies ist die Standardmethode, die für Container geeignet ist, um sicherzustellen, dass ein Container automatisch vom Podman-Daemon gestartet wird. Wir werden unseren web_server so konfigurieren, dass er immer neu gestartet wird, wenn er aus irgendeinem Grund anhält.

Zuerst müssen wir den bestehenden Container entfernen, da Neustartrichtlinien nur angewendet werden können, wenn ein Container erstellt wird.

Stoppen Sie den web_server-Container:

podman stop web_server
web_server

Und jetzt entfernen Sie ihn:

podman rm web_server
web_server

Als Nächstes erstellen Sie den web_server-Container mit der gleichen Konfiguration wie zuvor neu, aber fügen Sie das Flag --restart always hinzu. Dieses Flag weist den Podman-Daemon an, den Container zu überwachen und ihn neu zu starten, wenn er jemals beendet wird.

podman run -d \
  --name web_server \
  --network webapp-network \
  -v $(pwd)/webapp_content:/usr/local/apache2/htdocs/:Z \
  -p 8080:80 \
  --restart always \
  httpd:2.4

Der Container startet wie gewohnt. Um zu bestätigen, dass die Neustartrichtlinie aktiv ist, können Sie die Konfiguration des Containers untersuchen.

podman inspect web_server --format '{{.HostConfig.RestartPolicy.Name}}'

Der Befehl sollte always zurückgeben, was bestätigt, dass die Richtlinie festgelegt ist.

always

Lassen Sie uns nun demonstrieren, wie die Neustartrichtlinie funktioniert, indem wir den Container manuell neu starten, um zu simulieren, was nach einem Systemneustart oder einem Containerfehler passieren würde.

Überprüfen wir zuerst die aktuelle Konfiguration der Neustartrichtlinie:

podman inspect web_server --format '{{.HostConfig.RestartPolicy.Name}}'

Dies sollte always anzeigen, was bestätigt, dass unsere Neustartrichtlinie konfiguriert ist.

always

Testen wir nun den manuellen Neustart, um die Wiederherstellung nach einem Fehler zu simulieren:

podman start web_server
web_server

Überprüfen Sie, ob der Container läuft:

podman ps

Sie sollten beide Container mit der Neustartrichtlinie sehen:

CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS                  NAMES
e7f6g5h4i3j2   httpd:2.4      "httpd-foreground"       About a minute ago   Up 5 seconds        0.0.0.0:8080->80/tcp   web_server
a1b2c3d4e5f6   mariadb:10.6   "docker-entrypoint.s…"   About an hour ago    Up About an hour    3306/tcp               mariadb_server

Bestätigen Sie abschließend, dass der Dienst zugänglich ist:

curl http://localhost:8080
<h1>Welcome to My Web App</h1>

Verständnis der Neustartrichtlinien:

Die von Ihnen konfigurierte Richtlinie --restart always stellt sicher, dass:

  • Der Container automatisch neu gestartet wird, wenn er unerwartet beendet wird
  • Der Container automatisch gestartet wird, wenn der Podman-Dienst startet (z. B. nach einem Systemneustart)
  • Dies bietet Ausfallsicherheit für Produktionsbereitstellungen

Hinweis: In einigen Lab-Umgebungen kann das automatische Neustartverhalten je nach Podman-Konfiguration und ob der Podman-Systemdienst ausgeführt wird, variieren. Das wichtigste Lernziel ist das Verständnis, wie Neustartrichtlinien für Produktionsbereitstellungen konfiguriert werden.

Sie haben Ihren Container erfolgreich so konfiguriert, dass er wie ein Dienst verwaltet wird, wodurch sichergestellt wird, dass er automatisch verfügbar bleibt. Dies schließt das grundlegende Lifecycle-Management einer containerisierten Anwendung ab.

Zusammenfassung

In diesem Lab haben Sie den grundlegenden Prozess der Bereitstellung einer Webanwendung mit mehreren Containern auf RHEL mit Podman gelernt. Sie begannen mit der Ausführung eines MariaDB-Datenbank-Containers und konfigurierten seinen Anfangszustand – einschließlich des Root-Passworts, einer neuen Datenbank und eines dedizierten Benutzers – durch Übergabe von Umgebungsvariablen zur Laufzeit. Anschließend konfigurierten Sie persistenten Speicher für den Datenbank-Container, um sicherzustellen, dass kritische Daten über Container-Neustarts hinweg erhalten bleiben.

Um den Anwendungs-Stack zu vervollständigen, erstellten Sie ein benutzerdefiniertes Netzwerk, um eine sichere, isolierte Kommunikation zwischen den Containern zu ermöglichen. Sie stellten einen Apache-Webserver-Container in diesem Netzwerk bereit und gaben seinen Port frei, um externen Benutzerzugriff zu ermöglichen. Schließlich integrierten Sie den Webserver-Container in systemd und verwalteten ihn als Systemdienst, um sicherzustellen, dass er automatisch beim Booten startet und zuverlässig läuft, was ein produktionsreifes Bereitstellungsmuster demonstriert.