One place for hosting & domains

      Erstellen eines redundanten Speicherpools mit GlusterFS unter Ubuntu 20.04


      Eine frühere Version dieses Tutorials wurde von Justin Ellingwood verfasst.

      Einführung

      Single Points of Failure stellen bei der Speicherung kritischer Daten ein beträchtliches Risiko dar. Während sich mit vielen Datenbanken und anderer Software Daten im Kontext einer einzelnen Anwendung verteilen lassen, arbeiten andere Systeme auf der Ebene des Dateisystems, um sicherzustellen, dass Daten beim Schreiben auf Festplatte jedes Mal auch an einen anderen Ort kopiert werden.

      GlusterFS ist ein Network-Attached-Storage-Dateisystem (NAS), mit dem Sie Speicherressourcen verschiedener Geräte bündeln können. So lassen sich mehrere Speichergeräte, die auf unterschiedliche Computer verteilt sind, als eine leistungsfähigere Einheit nutzen. Außerdem bietet Ihnen GlusterFS die Möglichkeit, verschiedenartige Speicherkonfigurationen einzurichten, von denen viele funktionell RAID-Leveln ähneln. Zum Beispiel können Sie Daten auf verschiedenen Knoten im Cluster stripen oder für eine höhere Datenverfügbarkeit Redundanz implementieren.

      Ziele

      In diesem Leitfaden erstellen Sie ein redundantes geclustertes Speicherarray, auch als verteiltes Dateisystem oder (wie in der GlusterFS-Dokumentation) als Trusted Storage Pool bezeichnet. Damit erhalten Sie Funktionen, die einer über das Netzwerk gespiegelten RAID-Konfiguration ähneln: Jeder unabhängige Server enthält eine eigene Kopie der Daten, sodass Ihre Anwendungen auf eine beliebige Kopie zugreifen können. Dadurch lässt sich die Leselast besser verteilen.

      Dieser redundante GlusterFS-Cluster wird aus zwei Ubuntu 20.04-Servern bestehen. Er wird sich ähnlich wie ein NAS-Server mit gespiegeltem RAID verhalten. Dann werden Sie auf den Cluster über einen dritten Ubuntu 20.04-Server zugreifen, der als GlusterFS-Client konfiguriert ist.

      Anmerkung zur sicheren Ausführung von GlusterFS

      Wenn Sie einem GlusterFS-Volume Daten hinzufügen, werden diese Daten mit jedem Gerät im Speicherpool, in dem das Volumen gehostet wird, synchronisiert. Dieser Datenverkehr zwischen Knoten wird standardmäßig nicht verschlüsselt, d. h. es besteht das Risiko, dass er von bösartigen Akteuren abgefangen wird.

      Wenn Sie GlusterFS in der Produktion verwenden möchten, wird daher empfohlen, das Dateisystem in einem isolierten Netzwerk auszuführen. Sie könnten GlusterFS beispielsweise so einrichten, dass es in einer Virtual Private Cloud (VPC) oder mit einem VPN zwischen den einzelnen Knoten ausgeführt wird.

      Wenn Sie GlusterFS in DigitalOcean bereitstellen möchten, können Sie es in einem isolierten Netzwerk einrichten, indem Sie Ihre Serverinfrastruktur einer DigitalOcean Virtual Private Cloud hinzufügen. Details zur entsprechenden Einrichtung finden Sie in unserer VPC-Produktdokumentation.

      Voraussetzungen

      Um diesem Tutorial zu folgen, benötigen Sie drei Server, auf denen Ubuntu 20.04 ausgeführt wird. Jeder dieser Server sollte über einen Nicht-root-Benutzer mit Administratorberechtigungen und eine mit UFW konfigurierte Firewall verfügen. Folgen Sie dazu unserem Leitfaden für die Ersteinrichtung des Servers für Ubuntu 20.04.

      Anmerkung: Wie im Abschnitt „Ziele“ erwähnt, wird dieses Tutorial Sie durch die Konfiguration von zwei Ubuntu-Servern als Server in einem Speicherpool und dem dritten Server als Client begleiten; diesen werden Sie für Zugriff auf die beiden Speicherknoten verwenden.

      Aus Gründen der Einfachheit wird sich das Tutorial auf diese Computer mit folgenden Hostnamen beziehen:

      Hostname Rolle im Speicherpool
      gluster0 Server
      gluster1 Server
      gluster2 Client

      Befehle, die entweder auf gluster0 oder gluster1 ausgeführt werden müssen, weisen einen blauen bzw. roten Hintergrund auf:

      Befehle, die nur auf dem Client (gluster2) ausgeführt werden müssen, haben einen grünen Hintergrund:

      Befehle, die auf mehr als einem Computer ausgeführt werden können oder müssen, weisen einen grauen Hintergrund auf:

      Schritt 1 — Konfigurieren der DNS-Auflösung auf jedem Computer

      Das Erstellen einer Auflösung von Hostnamen zwischen den einzelnen Computern kann Ihnen bei der Verwaltung Ihres Gluster-Speicherpools helfen. Wenn Sie in diesem Tutorial später in einem gluster-Befehl auf einen Ihrer Computer verweisen, können Sie dies dann mit einem leicht zu merkenden Domänennamen oder sogar einem Spitznamen anstelle der jeweiligen IP-Adresse tun.

      Wenn Sie keinen freien Domänennamen haben oder einfach nur eine schnelle Einrichtung vornehmen möchten, können Sie stattdessen die Datei /etc/hosts auf den einzelnen Computern bearbeiten. Dies ist eine spezielle Datei auf Linux-Computern, in der Sie das System statisch konfigurieren können, um alle in der Datei enthaltenen Hostnamen in Form statischer IP-Adressen aufzulösen.

      Anmerkung: Wenn Sie Ihre Server zur Authentifizierung mit einer Domäne konfigurieren möchten, die Ihnen gehört, müssen Sie sich zunächst einen Domänennamen von einer Domänenregistrierungstelle wie Namecheap oder Enom verschaffen und dann die entsprechenden DNS-Einträge konfigurieren.

      Sobald Sie für jeden Server einen A-Eintrag konfiguriert haben, können Sie mit Schritt 2 fortfahren. Stellen Sie sicher, dass Sie glusterN.example.com und glusterN durch den Domänennamen ersetzen, der auf den jeweiligen im Beispielbefehl verwiesenen Server auflöst.

      Wenn Sie Ihre Infrastruktur von DigitalOcean erhalten haben, könnten Sie Ihren Domänennamen DigitalOcean hinzufügen und für jeden Ihrer Server einen eindeutigen A-Eintrag erstellen.

      Öffnen Sie die Datei mit root-Berechtigungen mit einem Texteditor Ihrer Wahl auf jedem Ihrer Computer. Wir verwenden hier nano:

      Standardmäßig wird die Datei in etwa so aussehen (mit entfernten Kommentaren):

      /etc/hosts

      127.0.1.1 hostname hostname
      127.0.0.1 localhost
      
      ::1 ip6-localhost ip6-loopback
      fe00::0 ip6-localnet
      ff00::0 ip6-mcastprefix
      ff02::1 ip6-allnodes
      ff02::2 ip6-allrouters
      ff02::3 ip6-allhosts
      

      Fügen Sie auf einem Ihrer Ubuntu-Server unter der lokalen Hostdefinition die IP-Adresse der einzelnen Server hinzu, gefolgt von allen Namen, die Sie verwenden möchten, um auf sie in Befehlen verweisen zu können.

      Im folgenden Beispiel erhält jeder Server einen langen Hostnamen, der auf glusterN.example.com abgestimmt ist, und einen kurzen Hostnamen, der auf glusterN abgestimmt ist. Sie können die Abschnitte glusterN.example.com und glusterN jeder Zeile in einen beliebigen Namen – oder durch einzelne Leerzeichen getrennte Namen – ändern, die Sie für den Zugriff auf einzelne Server verwenden möchten. Beachten Sie jedoch, dass in diesem Tutorial durchgehend die folgenden Beispiele verwenden werden:

      Anmerkung: Wenn Ihre Server Teil eines Infrastrukturpools vom Typ Virtual Private Cloud sind, sollten Sie in der Datei /etc/hosts die privaten IP-Adressen der einzelnen Server anstelle ihrer öffentlichen IP-Adressen verwenden.

      /etc/hosts

      . . .
      127.0.0.1       localhost
      first_ip_address gluster0.example.com gluster0
      second_ip_address gluster1.example.com gluster1
      third_ip_address gluster2.example.com gluster2
      
      . . .
      

      Wenn Sie fertig damit sind, der Datei /etc/hosts eines Computers diese neuen Zeilen hinzuzufügen, kopieren Sie die Zeilen und fügen Sie sie den /etc/hosts-Dateien auf Ihren anderen Computern hinzu. Jede /etc/hosts-Datei sollte dieselben Zeilen enthalten und die IP-Adressen Ihrer Server mit den ausgewählten Namen verknüpfen.

      Speichern und schließen Sie dann die Datei. Wenn Sie nano verwendet haben, drücken Sie STRG+X, Y und dann ENTER​​​.

      Nachdem Sie die Auflösung der Hostnamen zwischen den einzelnen Servern konfiguriert haben, können Sie Befehle leichter ausführen, wenn Sie später einen Speicherpool und ein Volume einrichten. Als Nächstes führen Sie einen weiteren Schritt aus, der auf jedem Ihrer Server abgeschlossen werden muss. Und zwar fügen Sie jedem Ihrer drei Ubuntu-Server das offizielle Personal Package Archive (PPA) des Gluster-Projekts hinzu, um dafür zu sorgen, dass Sie die neueste Version von GlusterFS installieren können.

      Schritt 2 — Einrichten von Softwarequellen auf jedem Computer

      Zwar enthalten die standardmäßigen Ubuntu 20.04-APT-Repositorys GlusterFS-Pakete, doch handelt es sich dabei zum Zeitpunkt der Verfassung dieses Dokuments nicht um die aktuellsten Versionen. Eine Möglichkeit, die neueste stabile Version von GlusterFS (zum Zeitpunkt der Verfassung dieses Dokuments Version 7.6) zu installieren, besteht darin, jedem Ihrer drei Ubuntu-Server das offizielle PPA des Gluster-Projekts hinzuzufügen.

      Fügen Sie das PPA für die GlusterFS-Pakete hinzu, indem Sie auf jedem Server folgenden Befehl ausführen:

      • sudo add-apt-repository ppa:gluster/glusterfs-7

      Drücken Sie ENTER, wenn Sie dazu aufgefordert werden, um zu bestätigen, dass Sie das PPA tatsächlich hinzufügen möchten.

      Aktualisieren Sie nach dem Hinzufügen des PPA den lokalen Paketindex der einzelnen Server. Dadurch wird sich jeder Server der neu verfügbaren Pakete bewusst:

      Nachdem Sie das offizielle PPA des Gluster-Projekts den einzelnen Servern hinzugefügt und den lokalen Paketindex aktualisiert haben, können Sie die erforderlichen GlusterFS-Pakete installieren. Da zwei Ihrer drei Computer als Gluster-Server und der dritte Computer als Client fungieren werden, müssen Sie jedoch zwei separate Installations- und Konfigurationsverfahren befolgen. Zuerst installieren und richten Sie die Serverkomponenten ein.

      Schritt 3 — Installieren von Serverkomponenten und Erstellen eines Trusted Storage Pool

      Ein Speicherpool ist eine beliebige Menge an Speicherkapazität, die aus mehr als einer Speicherquelle aggregiert wird. In diesem Schritt konfigurieren Sie zwei Ihrer Server — gluster0 und gluster1 — als Clusterkomponenten.

      Installieren Sie sowohl auf gluster0 als auch gluster1 das Paket für GlusterFS-Server, indem Sie Folgendes eingeben:

      • sudo apt install glusterfs-server

      Drücken Sie auf Aufforderung Y und dann ENTER, um die Installation zu bestätigen.

      Der Installationsprozess konfiguriert GlusterFS automatisch so, dass eine Ausführung als systemd-Dienst erfolgt. Er sorgt jedoch nicht für einen automatischen Start des Diensts oder das Aktivieren zum Ausführen zur Startzeit.

      Um glusterd (den GlusterFS-Dienst) zu starten, führen Sie den Befehl systemctl start sowohl auf gluster0 als auch gluster1 aus:

      • sudo systemctl start glusterd.service

      Führen Sie dann folgenden Befehl auf beiden Servern aus. Dadurch wird der Dienst jedes Mal gestartet, wenn der Server gestartet wird:

      • sudo systemctl enable glusterd.service

      Anschließend können Sie den Status des Diensts auf einem oder beiden Servern überprüfen:

      • sudo systemctl status glusterd.service

      Wenn der Dienst erfolgreich ausgeführt wird, erhalten Sie eine Ausgabe, die wie folgt aussieht:

      Output

      ● glusterd.service - GlusterFS, a clustered file-system server Loaded: loaded (/lib/systemd/system/glusterd.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2020-06-02 21:32:21 UTC; 32s ago Docs: man:glusterd(8) Main PID: 14742 (glusterd) Tasks: 9 (limit: 2362) CGroup: /system.slice/glusterd.service └─14742 /usr/sbin/glusterd -p /var/run/glusterd.pid --log-level INFO

      Wenn Sie dem Leitfaden zur Ersteinrichtung des Servers gefolgt sind, haben Sie auf jedem Ihrer Computer eine Firewall mit UFW eingerichtet. Aus diesem Grund müssen Sie die Firewall für jeden Knoten öffnen, bevor Sie eine Verbindung zwischen ihnen herstellen und einen Speicherpool einrichten können.

      Der Gluster-Daemon nutzt Port 24007, sodass Sie jedem Knoten über die Firewall der einzelnen Knoten in Ihrem Speicherpool Zugriff auf den Port gewähren müssen. Führen Sie dazu folgenden Befehl auf gluster0 aus. Denken Sie daran, gluster1_ip_address in die IP-Adresse von gluster1 zu ändern:

      • sudo ufw allow from gluster1_ip_address to any port 24007

      Führen Sie dann folgenden Befehl auf gluster1 aus. Vergessen Sie auch hier nicht, gluster0_ip_address in die IP-Adresse von gluster0 zu ändern:

      • sudo ufw allow from gluster0_ip_address to any port 24007

      Außerdem müssen Sie Ihrem Clientcomputer (gluster2) Zugriff auf diesen Port gewähren. Andernfalls werden Sie später Probleme haben, wenn Sie versuchen, das Volumen bereitzustellen. Führen Sie sowohl auf gluster0 als auch gluster1 folgenden Befehl aus, um diesen Port für Ihren Clientcomputer zu öffnen:

      • sudo ufw allow from gluster2_ip_address to any port 24007

      Um sicherzustellen, dass keine anderen Computer auf einem der Server auf den Port von Gluster zugreifen können, fügen Sie dann die folgende Rahmenregel deny sowohl gluster0 als auch gluster1 hinzu:

      Sie können nun eine Verbindung zwischen gluster0 und gluster1 herstellen. Dazu müssen Sie auf einem Ihrer Knoten den Befehl gluster peer probe ausführen. Es spielt dabei keine Rolle, welchen Knoten Sie verwenden. Das folgende Beispiel veranschaulicht die Ausführung des Befehls auf gluster0:

      • sudo gluster peer probe gluster1

      Dieser Befehl weist gluster0 im Wesentlichen an, gluster1 zu vertrauen und als Teil seines Speicherpools zu registrieren. Wenn der Test erfolgreich war, wird folgende Ausgabe zurückgegeben:

      Output

      peer probe: success

      Sie können jederzeit überprüfen, ob die Knoten miteinander kommunizieren, indem Sie auf einem der Knoten den Befehl gluster peer status ausführen. In diesem Beispiel wird er auf gluster1 ausgeführt:

      Wenn Sie diesen Befehl auf gluster1 ausführen, wird eine Ausgabe angezeigt, die wie folgt aussieht:

      Output

      Number of Peers: 1 Hostname: gluster0.example.com Uuid: a3fae496-c4eb-4b20-9ed2-7840230407be State: Peer in Cluster (Connected)

      An diesem Punkt kommunizieren Ihre beiden Server miteinander und sind bereit, gemeinsam Speichervolumes zu erstellen.

      Schritt 4 — Einrichten eines Speichervolumes

      Denken Sie daran, dass das primäre Ziel dieses Tutorials in der Einrichtung eines redundanten Speicherpools besteht. Dazu richten Sie ein Volume mit Replikatfunktion ein, damit Sie mehrere Kopien Ihrer Daten speichern und verhindern können, dass Ihr Cluster einen Single Point of Failure aufweist.

      Um ein Volume zu erstellen, verwenden Sie den Befehl gluster volume create mit dieser allgemeinen Syntax:

      sudo gluster volume create volume_name replica number_of_servers domain1.com:/path/to/data/directory domain2.com:/path/to/data/directory force
      

      Das bedeuten die Argumente und Optionen des Befehls gluster volume create:

      • volume_name: Das ist der Name, mit dem Sie nach der Erstellung auf das Volume verweisen. Der folgende Beispielbefehl sorgt für die Erstellung eines Volumes namens volume1.
      • replica number_of_servers: Nach dem Namen des Volumes können Sie festlegen, welche Art von Volume Sie erstellen möchten. Denken Sie daran, dass das Ziel dieses Tutorials darin besteht, einen redundanten Speicherpool einzurichten, sodass wir den Volume-Typ replica wählen. Dies erfordert ein Argument, mit dem angegeben wird, auf wie viele Server die Daten des Volumes repliziert werden sollen (in diesem Tutorial 2).
      • domain1.com:/… und domain2.com:/…: Diese definieren die Computer und den Speicherort des Verzeichnisses der Bricks (eine GlusterFS-Bezeichnung für die grundlegende Speichereinheit des Systems), was alle Verzeichnisse auf allen Computern umfasst, die als Teil oder Kopie eines größeren Volumes dienen. So entsteht volume1. Im folgenden Beispiel wird im root-Verzeichnis beider Server ein Verzeichnis namens gluster-storage erstellt.
      • force: Diese Option sorgt für das Überschreiben aller Warnungen oder Optionen, die sonst auftreten und die Erstellung des Volumes unterbrechen würden.

      Anhand der in diesem Tutorial zuvor aufgeführten Konventionen können Sie diesen Befehl zur Erstellung eines Volumes ausführen. Beachten Sie, dass Sie den Befehl entweder auf gluster0 oder gluster1 ausführen können:

      • sudo gluster volume create volume1 replica 2 gluster0.example.com:/gluster-storage gluster1.example.com:/gluster-storage force

      Wenn das Volume erfolgreich erstellt wurde, erhalten Sie folgende Ausgabe:

      Output

      volume create: volume1: success: please start the volume to access data

      An diesem Punkt wurde Ihr Volume bereits erstellt, ist aber noch nicht aktiv. Sie können das Volume starten und zur Verwendung bereitstellen, indem Sie folgenden Befehl ausführen (erneut auf einem Ihrer beiden Gluster-Server):

      • sudo gluster volume start volume1

      Wenn das Volume korrekt gestartet wurde, erhalten Sie folgende Ausgabe:

      Output

      volume start: volume1: success

      Überprüfen Sie als Nächstes, ob das Volume online ist. Führen Sie auf einem Ihrer Knoten folgenden Befehl aus:

      • sudo gluster volume status

      Dadurch wird eine Ausgabe zurückgegeben, die der folgenden ähnelt:

      Output

      Status of volume: volume1 Gluster process TCP Port RDMA Port Online Pid ------------------------------------------------------------------------------ Brick gluster0.example.com:/gluster-storage 49152 0 Y 18801 Brick gluster1.example.com:/gluster-storage 49152 0 Y 19028 Self-heal Daemon on localhost N/A N/A Y 19049 Self-heal Daemon on gluster0.example.com N/A N/A Y 18822 Task Status of Volume volume1 ------------------------------------------------------------------------------ There are no active volume tasks

      Laut dieser Ausgabe sind die Bricks auf beiden Servern online.

      Als letzter Schritt zur Konfiguration Ihres Volumes müssen Sie die Firewall auf beiden Servern öffnen, damit Ihr Clientcomputer in der Lage ist, sich mit dem Volume zu verbinden und das Volume bereitzustellen. Gemäß der Beispielausgabe des vorherigen Befehls wird volume1 auf beiden Computern an Port 49152 ausgeführt. Dies ist der Standardport von GlusterFS für das erste Volumen. Weitere Volumes werden also Port 49153, dann 49154 usw. verwenden.

      Führen Sie sowohl auf gluster0 als auch gluster1 folgenden Befehl aus, um gluster2 über die jeweilige Firewall Zugriff auf diesen Port zu gewähren:

      • sudo ufw allow from gluster2_ip_address to any port 49152

      Fügen Sie dann für zusätzliche Sicherheit eine weitere deny-Rahmenregel für den Port des Volumes hinzu – sowohl auf gluster0 als auch gluster1. Dadurch wird sichergestellt, dass auf beiden Servern keine anderen Computer außer Ihrem Client auf das Volume zugreifen können:

      Nachdem Ihr Volume nun ausgeführt wird, können Sie Ihren Clientcomputer einrichten und remote nutzen.

      Schritt 5 — Installieren und Konfigurieren von Clientkomponenten

      Ihr Volume ist nun konfiguriert und zur Verwendung durch Ihren Clientcomputer verfügbar. Bevor Sie beginnen, müssen Sie jedoch das Paket glusterfs-client aus dem PPA installieren, das Sie in Schritt 1 auf Ihrem Clientcomputer eingerichtet haben. Die Abhängigkeiten dieses Pakets umfassen einige gemeinsame Bibliotheken und Übersetzermodule von GlusterFS sowie die für die Arbeit erforderlichen FUSE-Tools.

      Führen Sie folgenden Befehl auf gluster2 aus:

      • sudo apt install glusterfs-client

      Sie werden Ihr Remote-Speichervolume in Kürze auf Ihrem Clientcomputer bereitstellen. Bevor Sie dies tun können, müssen Sie einen Bereitstellungspunkt erstellen. Traditionell befindet sich dieser im Verzeichnis /mnt, doch kann jeder beliebige Ort verwendet werden.

      Erstellen Sie aus Gründen der Einfachheit auf Ihrem Clientcomputer ein Verzeichnis namens /storage-pool als Bereitstellungspunkt. Dieser Verzeichnisname beginnt mit einem Schrägstrich (/), der es im root-Verzeichnis platziert. Daher müssen Sie das Verzeichnis mit sudo-Berechtigungen erstellen:

      Jetzt können Sie das Remotevolume bereitstellen. Werfen Sie zuvor einen Blick auf die Syntax des Befehls mount, den Sie dazu verwenden werden:

      sudo mount -t glusterfs domain1.com:volume_name /path/to/mount/point
      

      mount ist ein Dienstprogramm in vielen Unix-ähnlichen Betriebssystemen. Es dient dazu, Dateisysteme (ob externe Speichergeräte wie SD-Karten bzw. USB-Sticks oder NAS-Systeme wie im Fall dieses Tutorials) im vorhandenen Dateisystem des Computers in Verzeichnissen bereitzustellen. Die von Ihnen verwendete mount-Befehlssyntax umfasst die Option -t, die drei Argumente erfordert: den Typ des Dateisystems, der bereitgestellt werden soll, das Gerät, auf dem sich das bereitzustellende Dateisystem befindet, und das Verzeichnis auf dem Client, in dem Sie das Volume bereitstellen möchten.

      Beachten Sie, dass das Geräteargument in dieser Beispielsyntax auf einen Hostnamen verweist, gefolgt von einem Doppelpunkt und dann dem Namen des Volumes. GlusterFS abstrahiert die tatsächlichen Speicherverzeichnisse auf jedem Host, was bedeutet, dass dieser Befehl nicht das Verzeichnis /gluster-storage, sondern vielmehr das Volume volume1 bereitstellt.

      Beachten Sie außerdem, dass Sie nur ein Mitglied des Speicherclusters angeben müssen. Dies kann einer der beiden Knoten sein, da der GlusterFS-Dienst sie als einen Computer behandelt.

      Führen Sie auf Ihrem Clientcomputer (gluster2) folgenden Befehl aus, um das Volume im von Ihnen erstellten Verzeichnis /storage-pool bereitzustellen:

      • sudo mount -t glusterfs gluster0.example.com:/volume1 /storage-pool

      Führen Sie danach den Befehl df aus. Dadurch wird für Dateisysteme, auf die der aufrufende Benutzer Zugriff hat, der verfügbare Speicherplatz angezeigt:

      Dieser Befehl zeigt an, dass das GlusterFS-Volume am richtigen Ort bereitgestellt wurde:

      Output

      Filesystem 1K-blocks Used Available Use% Mounted on . . . gluster0.example.com:/volume1 50633164 1938032 48695132 4% /storage-pool

      Jetzt können Sie mit der Prüfung fortfahren, ob alle Daten, die Sie in das Volume auf Ihrem Client schreiben, wie erwartet auf Ihren Serverknoten repliziert werden.

      Schritt 6 — Testen von Redundanzfunktionen

      Nachdem Sie Ihren Client zur Verwendung des Speicherpools und Volumes eingerichtet haben, können Sie seine Funktionalität testen.

      Navigieren Sie auf Ihrem Clientcomputer (gluster2) zum im vorherigen Schritt definierten Bereitstellungspunkt:

      Erstellen Sie dann einige Testdateien. Der folgende Befehl erstellt in Ihrem Speicherpool zehn separate leere Dateien:

      • sudo touch file_{0..9}.test

      Wenn Sie sich die zuvor auf den einzelnen Speicherhosts definierten Speicherverzeichnisse ansehen, werden Sie feststellen, dass alle diese Dateien in jedem System vorhanden sind.

      Auf gluster0:

      Output

      file_0.test file_2.test file_4.test file_6.test file_8.test file_1.test file_3.test file_5.test file_7.test file_9.test

      Und auch auf gluster1:

      Output

      file_0.test file_2.test file_4.test file_6.test file_8.test file_1.test file_3.test file_5.test file_7.test file_9.test

      Wie diese Ausgaben zeigen, wurden auch die Testdateien, die Sie dem Client hinzugefügt haben, in beide Knoten geschrieben.

      Sollte jemals einer der Knoten in Ihrem Speichercluster ausfallen, kann es vorkommen, dass er nicht mehr mit dem Speicherpool synchron ist, wenn Änderungen am Dateisystem vorgenommen werden. Wenn der Knoten wieder online ist, können Sie durch Ausführung eines Lesevorgangs am Bereitstellungspunkt des Clients den Knoten auf fehlende Dateien aufmerksam machen:

      Nachdem Sie verifiziert haben, dass Ihr Speichervolumen korrekt bereitgestellt wurde und Sie Daten an beiden Computer im Cluster replizieren können, können Sie den Zugriff auf den Speicherpool sperren.

      Schritt 7 — Beschränken der Redundanzfunktionen

      Gegenwärtig kann sich jeder Computer ganz ohne Einschränkungen mit Ihrem Speichervolume verbinden. Sie können das ändern, indem Sie die Option auth.allow festlegen, um die IP-Adressen der einzelnen Clients zu definieren, die Zugriff auf das Volume haben sollen.

      Wenn Sie die Konfiguration /etc/hosts verwenden, werden die Namen, die Sie für die Server festgelegt haben, nicht korrekt geroutet. Sie müssen stattdessen eine statische IP-Adresse verwenden. Wenn Sie jedoch DNS-Einträge verwenden, wird hier der Domänenname, den Sie konfiguriert haben, funktionieren.

      Führen Sie auf einem Ihrer beiden Speicherknoten (gluster0 oder gluster1) folgenden Befehl aus:

      • sudo gluster volume set volume1 auth.allow gluster2_ip_address

      Wenn der Befehl erfolgreich abgeschlossen wird, gibt er folgende Ausgabe zurück:

      Output

      volume set: success

      Wenn Sie die Einschränkung irgendwann entfernen möchten, können Sie Folgendes eingeben:

      • sudo gluster volume set volume1 auth.allow *

      Dadurch werden wieder Verbindungen von beliebigen Computern aus möglich. Dies ist nicht sicher, kann aber für die Fehlerbehebung nützlich sein.

      Wenn Sie über mehrere Clients verfügen, können Sie ihre IP-Adressen oder Domänennamen gleichzeitig angeben (je nachdem, ob Sie /etc/hosts oder die Auflösung von DNS-Hostnamen verwenden), getrennt durch Kommas:

      • sudo gluster volume set volume1 auth.allow gluster_client1_ip,gluster_client2_ip

      Ihr Speicherpool ist nun konfiguriert, gesichert und einsatzbereit. Als Nächstes werden Sie einige Befehle kennen lernen, die Ihnen helfen, Informationen über den Status Ihres Speicherpools zu erhalten.

      Schritt 8 — Abrufen von Informationen über den Speicherpool mit GlusterFS-Befehlen

      Wenn Sie bestimmte Einstellungen für Ihren GlusterFS-Speicher ändern, können Sie den Überblick darüber verlieren, welche Optionen Sie zur Verfügung haben, welche Volumes live sind und welche Knoten mit einzelnen Volumes verknüpft sind.

      Es gibt verschiedene Befehle, die auf Ihren Knoten verfügbar sind, mit denen Sie diese Daten abrufen und mit Ihrem Speicherpool interagieren können.

      Wenn Sie Informationen über die einzelnen Volumes wünschen, führen Sie den Befehl gluster volume info aus:

      Output

      Volume Name: volume1 Type: Replicate Volume ID: a1e03075-a223-43ab-a0f6-612585940b0c Status: Started Snapshot Count: 0 Number of Bricks: 1 x 2 = 2 Transport-type: tcp Bricks: Brick1: gluster0.example.com:/gluster-storage Brick2: gluster1.example.com:/gluster-storage Options Reconfigured: auth.allow: gluster2_ip_address transport.address-family: inet storage.fips-mode-rchecksum: on nfs.disable: on performance.client-io-threads: off

      Um Informationen über Peers zu erhalten, mit denen dieser Knoten verbunden ist, können Sie Folgendes eingeben:

      Number of Peers: 1
      
      Hostname: gluster0.example.com
      Uuid: cb00a2fc-2384-41ac-b2a8-e7a1793bb5a9
      State: Peer in Cluster (Connected)
      

      Wenn Sie genaue Informationen zur Ausführung einzelner Knoten wünschen, können Sie ein Profil für ein Volume erstellen, indem Sie Folgendes eingeben:

      • sudo gluster volume profile volume_name start

      Nach erfolgreicher Ausführung dieses Befehls können Sie die gesammelten Informationen abrufen, indem Sie Folgendes eingeben:

      • sudo gluster volume profile volume_name info

      Output

      Brick: gluster0.example.com:/gluster-storage -------------------------------------------- Cumulative Stats: %-latency Avg-latency Min-Latency Max-Latency No. of calls Fop --------- ----------- ----------- ----------- ------------ ---- 0.00 0.00 us 0.00 us 0.00 us 30 FORGET 0.00 0.00 us 0.00 us 0.00 us 36 RELEASE 0.00 0.00 us 0.00 us 0.00 us 38 RELEASEDIR Duration: 5445 seconds Data Read: 0 bytes Data Written: 0 bytes Interval 0 Stats: %-latency Avg-latency Min-Latency Max-Latency No. of calls Fop --------- ----------- ----------- ----------- ------------ ---- 0.00 0.00 us 0.00 us 0.00 us 30 FORGET 0.00 0.00 us 0.00 us 0.00 us 36 RELEASE 0.00 0.00 us 0.00 us 0.00 us 38 RELEASEDIR Duration: 5445 seconds Data Read: 0 bytes Data Written: 0 bytes . . .

      Führen Sie wie zuvor gezeigt den Befehl gluster volume status aus, um eine Liste aller zu GlusterFS zugehörigen Komponenten zu erhalten, die auf den einzelnen Knoten ausgeführt werden:

      • sudo gluster volume status

      Output

      Status of volume: volume1 Gluster process TCP Port RDMA Port Online Pid ------------------------------------------------------------------------------ Brick gluster0.example.com:/gluster-storage 49152 0 Y 19003 Brick gluster1.example.com:/gluster-storage 49152 0 Y 19040 Self-heal Daemon on localhost N/A N/A Y 19061 Self-heal Daemon on gluster0.example.com N/A N/A Y 19836 Task Status of Volume volume1 ------------------------------------------------------------------------------ There are no active volume tasks

      Wenn Sie Ihre GlusterFS-Speichervolumes verwalten möchten, kann es eine gute Idee sein, die GlusterFS-Konsole zu nutzen. Dadurch können Sie mit Ihrer GlusterFS-Umgebung interagieren, ohne zunächst sudo gluster eingeben zu müssen:

      Daraufhin wird eine Eingabeaufforderung angezeigt, in der Sie Ihre Befehle eingeben können. help (Hilfe) ist eine gute Methode, um sich einen Überblick zu verschaffen:

      Output

      peer help - display help for peer commands volume help - display help for volume commands volume bitrot help - display help for volume bitrot commands volume quota help - display help for volume quota commands snapshot help - display help for snapshot commands global help - list global commands

      Führen Sie anschließend exit aus, um die Gluster-Konsole zu verlassen:

      Nun können Sie damit beginnen, GlusterFS mit der nächsten Anwendung zu integrieren.

      Zusammenfassung

      Durch Absolvieren dieses Tutorials haben Sie ein redundantes Speichersystem eingerichtet, mit dem Sie gleichzeitig auf zwei separate Server schreiben können. Das kann für verschiedene Anwendungen nützlich sein und dafür sorgen, dass Ihre Daten verfügbar bleiben, auch wenn ein Server ausfällt.



      Source link

      Installieren und Einrichten von Laravel mit Docker Compose unter Ubuntu 20.4


      Einführung

      Die Containerisierung einer Anwendung bezeichnet den Anpassungsprozess einer Anwendung und ihrer Komponenten, um sie in einfachen Umgebungen ausführen zu können, die als Container bekannt sind. Derartige Umgebungen sind isoliert und können gelöscht werden. Sie lassen sich zur Entwicklung, zum Testen und zur Bereitstellung von Anwendungen zu Produktionszwecken nutzen.

      In diesem Leitfaden verwenden wir Docker Compose, um eine Laravel-Anwendung für die Entwicklung zu containerisieren. Wenn Sie fertig sind, haben Sie eine Testversion der Laravel-Anwendung, die auf drei separaten Dienst-Containern ausgeführt wird:

      • einen app-Dienst, der PHP7.4-FPM ausführt;
      • einen db-Dienst, der MySQL 5.7 ausführt;
      • einen nginx-Dienst, der den app-Dienst verwendet, um den PHP-Code zu parsen, bevor die Laravel-Anwendung dem Endbenutzer bereitgestellt wird.

      Um einen gestrafften Entwicklungsprozess zu ermöglichen und das Debugging der Anwendung zu ermöglichen, halten wir Anwendungsdateien durch den Einsatz von gemeinsam genutzten Volumes synchron. Auch zeigen wir, wie Sie docker-compose exec-Befehle verwenden, um Composer und Artisan auf dem app-Container auszuführen.

      Voraussetzungen

      Schritt 1 – Erhalt der Demo-Anwendung

      Zu Beginn rufen wir die Demoversion der Laravel-Anwendung aus dem Github Repository ab. Wir sind an dem tutorial-01-Zweig interessiert, der die Laravel-Standardanwendung enthält, die wir im ersten Leitfaden dieser Serie erstellt haben.

      Um den mit diesem Tutorial kompatiblen Anwendungscode zu bekommen, laden Sie wie folgt tutorial-1.0.1 in Ihr Stammverzeichnis herunter:

      • cd ~
      • curl -L https://github.com/do-community/travellist-laravel-demo/archive/tutorial-1.0.1.zip -o travellist.zip

      Den unzip-Befehl brauchen wir, um den Anwendungscode zu dekomprimieren. Wenn Sie dieses Paket noch nicht installiert haben, sollten Sie es jetzt wie folgt tun:

      • sudo apt update
      • sudo apt install unzip

      Dekomprimieren Sie nun den Inhalt der Anwendung und benennen Sie das entpackte Verzeichnis für leichteren Zugriff um:

      • unzip travellist.zip
      • mv travellist-laravel-demo-tutorial-1.0.1 travellist-demo

      Navigieren Sie zum Verzeichnis travellist-demo:

      Im nächsten Schritt erstellen wir eine .env-Konfigurationsdatei, um die Anwendung einzurichten.

      Schritt 2 – Einrichten der .env-Datei der Anwendung

      Die Laravel-Konfigurationsdateien befinden sich im Verzeichnis config, das Sie im Stammverzeichnis der Anwendung finden. Zusätzlich wird eine .env-Datei verwendet, um eine umgebungsabhängige Konfiguration einzurichten, wie z. B. Anmeldedaten und Informationen, die sich zwischen Bereitstellungen ändern können. Diese Datei ist nicht Teil der Revisionskontrolle.

      Warnung: Die Umgebungs-Konfigurationsdatei enthält sensible Informationen über Ihren Server, einschließlich Anmeldedaten zur Datenbank und Sicherheitsschlüssel. Aus diesem Grund sollten Sie diese Datei nie öffentlich teilen.

      Die Werte in der .env-Datei haben Vorrang vor den Werten, die in regelmäßigen Konfigurationsdateien festgelegt sind, die sich im Verzeichnis config befinden. Jede Installation in einer neuen Umgebung erfordert eine maßgeschneiderte Umgebungsdatei, um Dinge wie Datenbank-Verbindungseinstellungen, Debug-Optionen, Anwendungs-URL und andere Objekte festzulegen, die je nach den Umgebungsbedingungen variieren können.

      Jetzt erstellen wir eine neue .env-Datei, um die Konfigurationsoptionen für die Entwicklungsumgebung anzupassen, die wir einrichten. Laravel wird mit einer .env-Musterdatei geliefert, die wir zur Erstellung unserer eigenen kopieren können:

      Öffnen Sie diese Datei mit nano oder dem Texteditor Ihrer Wahl:

      Die aktuelle .env-Datei aus der travellist Demo-Anwendung enthält Einstellungen zum Einsatz einer lokalen MySQL-Datenbank, wobei 127.0.0.1 der Datenbank-Host ist. Wir müssen die Variable DB_HOST aktualisieren, damit sie auf den Datenbankdienst verweist, den wir in unserer Docker-Umgebung erstellen. In diesem Leitfaden nennen wir unseren Datenbankdienst db. Ersetzen Sie also den aufgelisteten Wert von DB_HOST durch den Datenbankdienstnamen:

      .env

      APP_NAME=Travellist
      APP_ENV=dev
      APP_KEY=
      APP_DEBUG=true
      APP_URL=http://localhost:8000
      
      LOG_CHANNEL=stack
      
      DB_CONNECTION=mysql
      DB_HOST=db
      DB_PORT=3306
      DB_DATABASE=travellist
      DB_USERNAME=travellist_user
      DB_PASSWORD=password
      ...
      

      Sie können den Datenbanknamen, den Benutzernamen und das Passwort auch nach Bedarf ändern. Diese Variablen werden in einem späteren Schritt genutzt, wo wir die Datei docker-compose.yml einrichten, um unsere Dienste zu konfigurieren.

      Speichern Sie die Datei, wenn die Bearbeitung abgeschlossen ist. Wenn Sie nano verwendet haben, können Sie zur Bestätigung Strg+x, dann Y und die Eingabetaste drücken.

      Schritt 3 – Einrichten des Dockerfiles der Anwendung

      Obwohl unsere MySQL- und Nginx Dienste auf Standardimages basieren, die wir aus dem Docker Hub erhalten, müssen wir trotzdem ein benutzerdefiniertes Image für den Anwendungs-Container erstellen. Dafür erstellen wir ein neues Dockerfile.

      Unser travellist-Image basiert auf dem offiziellen PHP-Image php:7.4-fpm von Docker Hub. Über diese PHP-FPM-Umgebung hinaus installieren wir ein paar PHP-Extramodule und das Composer Abhängigkeitsmanagement-Tool.

      Außerdem erstellen wir einen neuen Systembenutzer; dies ist notwendig, um artisan– und composer– Befehle während der Entwicklung der Anwendung auszuführen. Die uid-Einstellung stellt sicher, dass der Benutzer im Container dieselbe UID wie der Systembenutzer auf Ihrem Host-Computer hat, auf dem Docker läuft. Auf diese Weise werden alle von diesen Befehlen erstellten Dateien mit den richtigen Berechtigungen im Host repliziert. Es bedeutet auch, dass Sie auf dem Host-Rechner den Code-Editor Ihrer Wahl verwenden können, um die Anwendung für die Container zu entwickeln.

      Erstellen Sie ein neues Dockerfile mit:

      Kopieren Sie den folgenden Inhalt in Ihr Dockerfile:

      Dockerfile

      FROM php:7.4-fpm
      
      # Arguments defined in docker-compose.yml
      ARG user
      ARG uid
      
      # Install system dependencies
      RUN apt-get update && apt-get install -y 
          git 
          curl 
          libpng-dev 
          libonig-dev 
          libxml2-dev 
          zip 
          unzip
      
      # Clear cache
      RUN apt-get clean && rm -rf /var/lib/apt/lists/*
      
      # Install PHP extensions
      RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
      
      # Get latest Composer
      COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
      
      # Create system user to run Composer and Artisan Commands
      RUN useradd -G www-data,root -u $uid -d /home/$user $user
      RUN mkdir -p /home/$user/.composer && 
          chown -R $user:$user /home/$user
      
      # Set working directory
      WORKDIR /var/www
      
      USER $user
      
      

      Vergessen Sie nicht, die Datei zu speichern, wenn Sie fertig sind.

      Unser Dockerfile beginnt, indem Sie das Basisimage definieren, das wir verwenden: php:7.4-fpm.

      Nach Installation von Systempaketen und PHP-Erweiterungen installieren wir Composer, indem wir den ausführbaren composer aus dem letzten offiziellen Image in unser eigenes Anwendungsimage kopieren.

      Dann wird mit den Argumenten user und uid ein neuer Systembenutzer erstellt und eingerichtet. Diese Argumente wurden zu Beginn des Dockerfiles deklariert. Diese Werte werden von Docker Compose zur Buildzeit injiziert.

      Schließlich legen wir das Standardarbeitsverzeichnis als /var/www fest und wechseln auf den neu erstellten Benutzer. Somit gewährleisten Sie, dass Sie sich als regelmäßiger Benutzer verbinden und im richtigen Verzeichnis sind, wenn Sie composer– und artisan-Befehle im Anwendungs-Container ausführen.

      Schritt 4 – Einrichten der Nginx-Konfiguration und der Datenbank-Dump-Dateien

      Wenn Sie Entwicklungsumgebungen mit Docker Compose erstellen, müssen Sie die Konfigurations- oder Initialisierungsdateien häufig mit Dienst-Containern teilen, um diese Dienste einzurichten oder im Bootstrap-Verfahren zu laden. Diese Vorgehensweise ermöglicht die Änderung der Konfigurationsdateien, um Ihre Umgebung während der Anwendungsentwicklung genau einzustellen.

      Jetzt erstellen wir einen Ordner mit Dateien, die zur Konfiguration und Initialisierung unserer Dienst-Container verwendet werden.

      Um Nginx einzurichten, teilen wir eine travellist.conf Datei, die festlegt, wie die Anwendung bereitgestellt wird. Erstellen Sie den Ordner docker-compose/nginx wie folgt:

      • mkdir -p docker-compose/nginx

      Öffnen Sie eine neue Datei namens travellist.conf in diesem Verzeichnis:

      • nano docker-compose/nginx/travellist.conf

      Kopieren Sie die folgende Nginx-Konfiguration in diese Datei:

      docker-compose/nginx/travellist.conf

      
      server {
          listen 80;
          index index.php index.html;
          error_log  /var/log/nginx/error.log;
          access_log /var/log/nginx/access.log;
          root /var/www/public;
          location ~ .php$ {
              try_files $uri =404;
              fastcgi_split_path_info ^(.+.php)(/.+)$;
              fastcgi_pass app:9000;
              fastcgi_index index.php;
              include fastcgi_params;
              fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
              fastcgi_param PATH_INFO $fastcgi_path_info;
          }
          location / {
              try_files $uri $uri/ /index.php?$query_string;
              gzip_static on;
          }
      }
      

      Mit dieser Datei wird Nginx konfiguriert, um auf Port 80 zu lauschen und index.php als standardmäßige Index-Seite zu verwenden. Damit wird der Dokumentenstamm auf /var/www/public festgelegt und dann Nginx so konfiguriert, dass er den app-Dienst auf Port 9000 verwendet, um *.php-Dateien zu verarbeiten.

      Speichern und schließen Sie die Datei, wenn die Bearbeitung abgeschlossen ist.

      Um die MySQL-Datenbank einzurichten, teilen wir einen Datenbank-Dump, der bei Initialisierung des Containers importiert wird. Dies ist eine Eigenschaft, die vom MySQL 5.7-Image bereitgestellt wird, das wir in dem Container verwenden.

      Erstellen Sie einen neuen Ordner für Ihre MySQL-Initialisierung im Ordner docker-compose:

      • mkdir docker-compose/mysql

      Öffnen Sie eine neue .sql-Datei:

      • nano docker-compose/mysql/init_db.sql

      Der folgende MySQL-Dump basiert auf der Datenbank, die wir in unserem Leitfaden zu Laravel mit LEMP eingerichtet haben. Damit wird eine neue Tabelle namens places erstellt. Dann füllt er die Tabelle mit einem Satz von Musterstellen.

      Fügen Sie den folgenden Code zur Datei hinzu:

      docker-compose/mysql/db_init.sql

      DROP TABLE IF EXISTS `places`;
      
      CREATE TABLE `places` (
        `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
        `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
        `visited` tinyint(1) NOT NULL DEFAULT '0',
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      
      INSERT INTO `places` (name, visited) VALUES ('Berlin',0),('Budapest',0),('Cincinnati',1),('Denver',0),('Helsinki',0),('Lisbon',0),('Moscow',1),('Nairobi',0),('Oslo',1),('Rio',0),('Tokyo',0);
      

      Die Tabelle places enthält drei Felder: id, name und visited. Das Feld visited ist ein Flag, das als Identifizierung der Stellen dient, die noch ausstehen. Stellen Sie diese Musterstellen nach Belieben um oder setzen Sie neue hinzu. Speichern und schließen Sie die Datei, wenn Sie fertig sind.

      Damit ist die Einrichtung des Dockerfiles der Anwendung und der Konfigurationsdateien des Dienstes abgeschlossen. Als Nächstes richten wir Docker Compose ein, damit es bei der Erstellung unserer Dienste diese Dateien verwendet.

      Schritt 5 – Erstellen einer Multi-Container-Umgebung mit Docker Compose

      Docker Compose ermöglicht es Ihnen, Multi-Container-Umgebungen für auf Docker laufende Anwendungen zu erstellen. Er verwendet Dienst-Definitionen zum Aufbau voll anpassbarer Umgebungen mit mehreren Containern, die Netzwerke und Datenvolumes teilen können. Damit wird eine nahtlose Integration zwischen Anwendungskomponenten möglich.

      Um unsere Dienst-Definitionen einzurichten, erstellen wir eine neue Datei namens docker-compose.yml. Normalerweise befindet sich diese Datei im Stamm des Anwendungsordners und definiert die containerisierte Umgebung, einschließlich der Standardimages, die Sie zum Aufbau Ihrer Container verwenden, und der Art und Weise, wie Ihre Dienste interagieren.

      Wir definieren drei verschiedene Dienste in unserer docker-compose.yml-Datei: app, db und nginx.

      Der app-Dienst stellt ein Image mit der Bezeichnung travellist auf Basis des zuvor erstellten Dockerfiles zusammen. Der durch diesen Dienst definierte Container führt einen php-fpm-Server aus, um PHP-Code zu parsen und die Ergebnisse an den nginx-Dienst zurückzusenden, der in einem separaten Container läuft. Der mysql-Dienst definiert einen Container, der einen MySQL 5.7-Server ausführt. Unsere Dienste teilen ein Brückennetzwerk namens travellist.

      Die Anwendungsdateien werden in sowohl den app– als auch den nginx-Diensten über Bind-Bereitstellungen synchronisiert. Bind-Bereitstellungen sind in Entwicklungsumgebungen nützlich, weil sie eine performante zweispurige Synchronisierung zwischen Host-Rechner und Containern ermöglichen.

      Erstellen Sie eine neue docker-compose.yml-Datei im Stammverzeichnis der Anwendung:

      Eine typische docker-compose.yml-Datei beginnt mit einer Versionsdefinition gefolgt von einem services-Knoten, in dem alle Dienste definiert sind. Die geteilten Netzwerke werden normalerweise unten in der Datei definiert.

      Kopieren Sie zu Beginn diesen Standardcode in Ihre docker-compose.yml-Datei:

      docker-compose.yml

      version: "3.7"
      services:
      
      
      networks:
        travellist:
          driver: bridge
      

      Jetzt bearbeiten wir den services-Knoten, um die app-, db– und nginx-Dienste aufzunehmen.

      Der app-Dienst

      Der app-Dienst richtet einen Container namens travellist-app ein. Basierend auf einem Dockerfile mit dem gleichen Pfad wie die docker-compose.yml-Datei baut er ein neues Docker-Image auf. Das neue Image wird lokal unter dem Namen travellist gespeichert.

      Obwohl sich der als Anwendung dienende Dokumentenstamm im nginx-Container befindet, sollten auch die Anwendungsdateien irgendwo im app-Container vorhanden sein, damit wir Befehlszeilenvorgänge mit dem Laravel Artisan-Tool ausführen können.

      Kopieren Sie die folgende Dienst-Definition in Ihrem services-Knoten aus der docker-compose.yml-Datei:

      docker-compose.yml

        app:
          build:
            args:
              user: sammy
              uid: 1000
            context: ./
            dockerfile: Dockerfile
          image: travellist
          container_name: travellist-app
          restart: unless-stopped
          working_dir: /var/www/
          volumes:
            - ./:/var/www
          networks:
            - travellist
      

      Diese Einstellungen bewirken Folgendes:

      • build: Diese Konfiguration weist Docker Compose an, ein lokales Image für den app-Dienst zu erstellen, wobei es den angegebenen Pfad (context) und das Dockerfile für Anweisungen verwendet. Die Argumente user und uid werden in das Dockerfile injiziert, um die Befehle zur Benutzereinrichtung zur Buildzeit anzupassen.
      • image: Der Name, der für das zusammengestellte Image verwendet wird.
      • container_name: Richtet den Container-Namen für diesen Dienst ein.
      • restart: Es wird immer ein Neustart durchgeführt, es sei denn, der Dienst wird angehalten.
      • working_dir: Richtet das Standardverzeichnis für diesen Dienst als /var/www ein.
      • volumes: Erstellt ein gemeinsam genutztes Volume, das den Inhalt des aktuellen Verzeichnisses auf /var/www im Container synchronisiert. Beachten Sie, dass es sich nicht um Ihren Dokumentenstamm handelt, da dieser sich im nginx-Container befinden wird.
      • networks: Richtet diesen Dienst auf Nutzung eines Netzwerks namens travellist ein.

      Der db-Dienst

      Der db-Dienst verwendet ein vorab zusammengestelltes MySQL 5.7-Image von Docker Hub. Da Docker Compose die .env-Variablendateien automatisch lädt, die sich im gleichen Verzeichnis wie die docker-compose.yml-Datei befinden, erhalten wir unsere Datenbankeinstellungen aus der Laravel .env-Datei, die wir im vorherigen Schritt erstellt haben.

      Setzen Sie die folgende Dienst-Definition in Ihrem services-Knoten direkt hinter den app-Dienst:

      docker-compose.yml

        db:
          image: mysql:5.7
          container_name: travellist-db
          restart: unless-stopped
          environment:
            MYSQL_DATABASE: ${DB_DATABASE}
            MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
            MYSQL_PASSWORD: ${DB_PASSWORD}
            MYSQL_USER: ${DB_USERNAME}
            SERVICE_TAGS: dev
            SERVICE_NAME: mysql
          volumes:
            - ./docker-compose/mysql:/docker-entrypoint-initdb.d
          networks:
            - travellist
      

      Diese Einstellungen bewirken Folgendes:

      • image: Definiert das Docker-Image, das für diesen Container verwendet werden sollte. In diesem Fall verwenden wir ein MySQL 5.7-Image von Docker Hub.
      • container_name: Richtet den Container-Namen für diesen Dienst ein: travellist-db.
      • restart: Dieser Dienst wird immer neu gestartet, es sei denn, er wurde ausdrücklich angehalten.
      • environment: Definiert Umgebungsvariablen im neuen Container. Wir verwenden Werte aus der Laravel .env-Datei, um unseren MySQL-Dienst einzurichten. Damit werden automatisch, basierend auf den bereitgestellten Umgebungsvariablen, eine neue Datenbank und ein Benutzer erstellt.
      • volumes: Erstellt ein Volume, um einen .sql-Datenbank-Dump zu teilen, der zur Initialisierung der Anwendungsdatenbank verwendet wird. Das MySQL-Image importiert automatisch .sql-Dateien, die im Verzeichnis /docker-entrypoint-initdb.d im Container abgelegt werden.
      • networks: Richtet diesen Dienst auf Nutzung eines Netzwerks namens travellist ein.

      Der nginx-Dienst

      Der nginx-Dienst verwendet ein vorab zusammengestelltes Nginx-Image auf Alpine, einer einfachen Linux-Distribution. Damit wird ein Container namens travellist-nginx erstellt und die ports-Definition verwendet, um eine Umleitung von Port 8000 im Host-System auf Port 80 im Container zu schaffen.

      Setzen Sie die folgende Dienst-Definition in Ihrem services-Knoten direkt hinter den db-Dienst:

      docker-compose.yml

        nginx:
          image: nginx:1.17-alpine
          container_name: travellist-nginx
          restart: unless-stopped
          ports:
            - 8000:80
          volumes:
            - ./:/var/www
            - ./docker-compose/nginx:/etc/nginx/conf.d
          networks:
            - travellist
      

      Diese Einstellungen bewirken Folgendes:

      • image: Definiert das Docker-Image, das für diesen Container verwendet werden sollte. In diesem Fall verwenden wir das Alpine Nginx 1.17-Image.
      • container_name: Richtet den Container-Namen für diesen Dienst ein: travellist-nginx.
      • restart: Dieser Dienst wird immer neu gestartet, es sei denn, er wurde ausdrücklich angehalten.
      • ports: Richtet eine Port-Umleitung ein, die den externen Zugriff über Port 8000 auf den Web-Server ermöglicht, der auf Port 80 im Container läuft.
      • volumes: Erstellt zwei gemeinsam genutzte Volumes. Das erste wird den Inhalt aus dem aktuellen Verzeichnis in /var/www im Container synchronisieren. Auf diese Weise werden bei lokalen Änderungen an den Anwendungsdateien diese schnell in der Anwendung widergespiegelt, die von Nginx im Container bereitgestellt wird. Das zweite Volume stellt sicher, dass unsere Nginx-Konfigurationsdatei, die sich auf docker-compose/nginx/travellist.conf befindet, in den Nginx-Konfigurationsordner des Containers kopiert wird.
      • networks: Richtet diesen Dienst auf Nutzung eines Netzwerks namens travellist ein.

      Fertiggestellte docker-compose.yml-Datei

      So sieht unsere fertiggestellte docker-compose.yml-Datei aus:

      docker-compose.yml

      version: "3.7"
      services:
        app:
          build:
            args:
              user: sammy
              uid: 1000
            context: ./
            dockerfile: Dockerfile
          image: travellist
          container_name: travellist-app
          restart: unless-stopped
          working_dir: /var/www/
          volumes:
            - ./:/var/www
          networks:
            - travellist
      
        db:
          image: mysql:5.7
          container_name: travellist-db
          restart: unless-stopped
          environment:
            MYSQL_DATABASE: ${DB_DATABASE}
            MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
            MYSQL_PASSWORD: ${DB_PASSWORD}
            MYSQL_USER: ${DB_USERNAME}
            SERVICE_TAGS: dev
            SERVICE_NAME: mysql
          volumes:
            - ./docker-compose/mysql:/docker-entrypoint-initdb.d
          networks:
            - travellist
      
        nginx:
          image: nginx:alpine
          container_name: travellist-nginx
          restart: unless-stopped
          ports:
            - 8000:80
          volumes:
            - ./:/var/www
            - ./docker-compose/nginx:/etc/nginx/conf.d/
          networks:
            - travellist
      
      networks:
        travellist:
          driver: bridge
      

      Denken Sie daran, die Datei zu speichern, wenn Sie Ihre Bearbeitung abgeschlossen haben.

      Schritt 6 – Ausführung der Anwendung mit Docker Compose

      Jetzt verwenden wir docker-compose-Befehle, um das Anwendungsimage zu erstellen und die Dienste auszuführen, die wir in unserem Setup festgelegt haben.

      Erstellen Sie das app-Image mit dem folgenden Befehl:

      Dies kann einige Minuten dauern. Sie sehen eine Ausgabe, die dieser ähnelt:

      Output

      Building app Step 1/11 : FROM php:7.4-fpm ---> fa37bd6db22a Step 2/11 : ARG user ---> Running in f71eb33b7459 Removing intermediate container f71eb33b7459 ---> 533c30216f34 Step 3/11 : ARG uid ---> Running in 60d2d2a84cda Removing intermediate container 60d2d2a84cda ---> 497fbf904605 Step 4/11 : RUN apt-get update && apt-get install -y git curl libpng-dev libonig-dev ... Step 7/11 : COPY --from=composer:latest /usr/bin/composer /usr/bin/composer ---> e499f74896e3 Step 8/11 : RUN useradd -G www-data,root -u $uid -d /home/$user $user ---> Running in 232ef9c7dbd1 Removing intermediate container 232ef9c7dbd1 ---> 870fa3220ffa Step 9/11 : RUN mkdir -p /home/$user/.composer && chown -R $user:$user /home/$user ---> Running in 7ca8c0cb7f09 Removing intermediate container 7ca8c0cb7f09 ---> 3d2ef9519a8e Step 10/11 : WORKDIR /var/www ---> Running in 4a964f91edfa Removing intermediate container 4a964f91edfa ---> 00ada639da21 Step 11/11 : USER $user ---> Running in 9f8e874fede9 Removing intermediate container 9f8e874fede9 ---> fe176ff4702b Successfully built fe176ff4702b Successfully tagged travellist:latest

      Wenn der Build abgeschlossen ist, können Sie die Umgebung im Hintergrundmodus ausführen:

      Output

      Creating travellist-db ... done Creating travellist-app ... done Creating travellist-nginx ... done

      Damit werden Ihre Container im Hintergrund ausgeführt. Um Informationen über den Zustand Ihrer aktiven Dienste anzuzeigen, führen Sie Folgendes aus:

      Die Ausgabe sieht dann so aus:

      Output

      Name Command State Ports -------------------------------------------------------------------------------- travellist-app docker-php-entrypoint php-fpm Up 9000/tcp travellist-db docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp travellist-nginx /docker-entrypoint.sh ngin ... Up 0.0.0.0:8000->80/tcp

      Jetzt ist Ihre Umgebung einsatzbereit, aber wir müssen noch ein paar Befehle ausführen, um das Setup der Anwendung abzuschließen. Sie können den Befehl docker-compose exec verwenden, um Befehle in den Dienst-Containern auszuführen, wie z. B. ls -l, der detaillierte Informationen über Dateien im Anwendungsverzeichnis anzeigt:

      • docker-compose exec app ls -l

      Output

      total 260 -rw-rw-r-- 1 sammy sammy 737 Jun 9 11:19 Dockerfile -rw-rw-r-- 1 sammy sammy 101 Jan 7 08:05 README.md drwxrwxr-x 6 sammy sammy 4096 Jan 7 08:05 app -rwxr-xr-x 1 sammy sammy 1686 Jan 7 08:05 artisan drwxrwxr-x 3 sammy sammy 4096 Jan 7 08:05 bootstrap -rw-rw-r-- 1 sammy sammy 1501 Jan 7 08:05 composer.json -rw-rw-r-- 1 sammy sammy 179071 Jan 7 08:05 composer.lock drwxrwxr-x 2 sammy sammy 4096 Jan 7 08:05 config drwxrwxr-x 5 sammy sammy 4096 Jan 7 08:05 database drwxrwxr-x 4 sammy sammy 4096 Jun 9 11:19 docker-compose -rw-rw-r-- 1 sammy sammy 965 Jun 9 11:27 docker-compose.yml -rw-rw-r-- 1 sammy sammy 1013 Jan 7 08:05 package.json -rw-rw-r-- 1 sammy sammy 1405 Jan 7 08:05 phpunit.xml drwxrwxr-x 2 sammy sammy 4096 Jan 7 08:05 public -rw-rw-r-- 1 sammy sammy 273 Jan 7 08:05 readme.md drwxrwxr-x 6 sammy sammy 4096 Jan 7 08:05 resources drwxrwxr-x 2 sammy sammy 4096 Jan 7 08:05 routes -rw-rw-r-- 1 sammy sammy 563 Jan 7 08:05 server.php drwxrwxr-x 5 sammy sammy 4096 Jan 7 08:05 storage drwxrwxr-x 4 sammy sammy 4096 Jan 7 08:05 tests drwxrwxr-x 41 sammy sammy 4096 Jun 9 11:32 vendor -rw-rw-r-- 1 sammy sammy 538 Jan 7 08:05 webpack.mix.js

      Jetzt führen wir composer install aus, um die Anwendungsabhängigkeiten zu installieren:

      • docker-compose exec app composer install

      Die Ausgabe sieht dann so aus:

      Output

      Loading composer repositories with package information Installing dependencies (including require-dev) from lock file Package operations: 85 installs, 0 updates, 0 removals - Installing doctrine/inflector (1.3.1): Downloading (100%) - Installing doctrine/lexer (1.2.0): Downloading (100%) - Installing dragonmantank/cron-expression (v2.3.0): Downloading (100%) - Installing erusev/parsedown (1.7.4): Downloading (100%) - Installing symfony/polyfill-ctype (v1.13.1): Downloading (100%) - Installing phpoption/phpoption (1.7.2): Downloading (100%) - Installing vlucas/phpdotenv (v3.6.0): Downloading (100%) - Installing symfony/css-selector (v5.0.2): Downloading (100%) … Generating optimized autoload files > IlluminateFoundationComposerScripts::postAutoloadDump > @php artisan package:discover --ansi Discovered Package: facade/ignition Discovered Package: fideloper/proxy Discovered Package: laravel/tinker Discovered Package: nesbot/carbon Discovered Package: nunomaduro/collision Package manifest generated successfully.

      Als Letztes vor dem Anwendungstest verbleibt die Generierung eines eindeutigen Anwendungsschlüssels mit dem artisan Laravel-Tool auf Befehlszeilenebene. Dieser Schlüssel wird verwendet, um die Benutzersitzungen und andere sensible Daten zu verschlüsseln:

      • docker-compose exec app php artisan key:generate

      Output

      Application key set successfully.

      Gehen Sie jetzt in Ihren Browser und greifen Sie über Port 8000 auf den Domänenamen oder die IP-Adresse Ihres Servers zu:

      http://server_domain_or_IP:8000
      

      Anmerkung: Wenn Sie diese Demo auf Ihrem lokalen Rechner ausführen, verwenden Sie http://localhost:8000, um von Ihrem Browser aus auf die Anwendung zuzugreifen.

      Sie sehen in etwa folgende Seite:

      Demoversion der Laravel-Anwendung

      Sie können den Befehl logs verwenden, um die von den Diensten generierten Protokolle zu überprüfen:

      • docker-compose logs nginx
      Attaching to travellist-nginx
      …
      travellist-nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
      travellist-nginx | /docker-entrypoint.sh: Configuration complete; ready for start up
      travellist-nginx | 192.168.0.1 - - [09/Jun/2020:11:46:34 +0000] "GET / HTTP/1.1" 200 627 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"
      travellist-nginx | 192.168.0.1 - - [09/Jun/2020:11:46:35 +0000] "GET / HTTP/1.1" 200 627 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"
      

      Wenn Sie Ihre Docker-Compose-Umgebung unter Beibehaltung des Zustandes aller Dienste anhalten möchten, führen Sie Folgendes aus:

      Output

      Pausing travellist-db ... done Pausing travellist-nginx ... done Pausing travellist-app ... done

      So können Sie dann Ihre Dienste wiederaufnehmen:

      Output

      Unpausing travellist-app ... done Unpausing travellist-nginx ... done Unpausing travellist-db ... done

      Um Ihre Docker-Compose-Umgebung herunterzufahren und alle Container, Netzwerke und Volumes zu entfernen, führen Sie Folgendes aus:

      Output

      Stopping travellist-nginx ... done Stopping travellist-db ... done Stopping travellist-app ... done Removing travellist-nginx ... done Removing travellist-db ... done Removing travellist-app ... done Removing network travellist-laravel-demo_travellist

      Eine Übersicht aller Docker-Compose-Befehle finden Sie in der Docker Compose Befehlszeilenreferenz.

      Zusammenfassung

      In diesem Leitfaden haben wir mit Docker Compose eine Docker-Umgebung mit drei Containern eingerichtet, um eine Infrastruktur in einer YAML-Datei festzulegen.

      Ab jetzt können Sie in Ihrer Laravel-Anwendung arbeiten, ohne einen lokalen Webserver für die Entwicklung und Tests installieren und einrichten zu müssen. Außerdem arbeiten Sie mit einer löschbaren Testumgebung, die leicht repliziert und verteilt werden kann, was bei der Anwendungsentwicklung und auch beim Wechsel in eine Produktivumgebung hilfreich sein kann.



      Source link

      Fernzugriff auf GUI-Anwendungen mit Docker und Caddy unter Ubuntu 18.04


      Der Autor wählte den Free and Open Source Fund, um eine Spende im Rahmen des Programms Write for DOnations zu erhalten.

      Einführung

      Trotz der wachsenden Beliebtheit von Cloud-Diensten besteht nach wie vor die Notwendigkeit, native Anwendungen auszuführen.

      Durch die Verwendung von noVNC und TigerVNC können Sie native Anwendungen innerhalb eines Docker-Containers ausführen und über einen Webbrowser aus der Ferne auf sie zugreifen. Darüber hinaus können Sie Ihre Anwendung auf einem Server mit mehr Systemressourcen ausführen, als Ihnen vor Ort zur Verfügung stehen, was die Flexibilität bei der Ausführung großer Anwendungen steigern kann.

      In diesem Tutorial containerisieren Sie mit Docker Mozilla Thunderbird, einen E-Mail-Client. Anschließend sichern Sie sie Ihn und bieten Fernzugriff über den Caddy Webserver.

      Nach Abschluss können Sie von jedem Gerät aus mit einem Webbrowser auf Thunderbird zugreifen. Optional können Sie auch lokal auf die Dateien zugreifen, indem Sie WebDAV verwenden. Außerdem erhalten Sie ein völlig eigenständiges Docker-Image, das Sie überall ausführen können.

      Voraussetzungen

      Bevor Sie diesen Leitfaden beginnen, benötigen Sie Folgendes:

      Schritt 1 — Erstellen der supervisord-Konfiguration

      Da Ihr Server nun ausgeführt wird und Docker installiert ist, können Sie mit der Konfiguration des Containers Ihrer Anwendung beginnen. Da Ihr Container aus mehreren Komponenten besteht, müssen Sie einen Prozessmanager verwenden, um sie zu starten und zu überwachen. In diesem Fall verwenden Sie supervisord . supervisord ist ein in Python geschriebener Prozessmanager, der häufig zur Organisation komplexer Container verwendet wird.

      Erstellen und geben Sie zunächst ein Verzeichnis namens thunderbird für Ihren Container ein:

      • mkdir ~/thunderbird
      • cd ~/thunderbird

      Erstellen und öffnen Sie nun eine Datei namens supervisord.conf mit nano oder Ihrem bevorzugten Editor:

      Fügen Sie nun diesen ersten Code-Block in supervisord.conf ein, der die globalen Optionen für supervisord definiert:

      ~/thunderbird/supervisord.conf

      [supervisord]
      nodaemon=true
      pidfile=/tmp/supervisord.pid
      logfile=/dev/fd/1
      logfile_maxbytes=0
      

      In diesem Block konfigurieren Sie supervisord selbst. Sie müssen nodaemon auf true setzen, da es innerhalb eines Docker-Containers als Einstiegspunkt ausgeführt wird. Daher möchten Sie, dass es weiterhin im Vordergrund ausgeführt wird. Außerdem setzten Sie pidfile auf einen Pfad, auf den ein Nicht-root-Benutzer Zugriff hat (mehr dazu später), und logfile, auf stdout, damit Sie die Protokolle sehen können.

      Fügen Sie als Nächstes einen weiteren kleinen Code-Block zu supervisord.conf hinzu. Dieser Block startet TigerVNC, das ein kombinierter VNC/X11-Server ist:

      ~/thunderbird/supervisord.conf

      ...
      [program:x11]
      priority=0
      command=/usr/bin/Xtigervnc -desktop "Thunderbird" -localhost -rfbport 5900 -SecurityTypes None -AlwaysShared -AcceptKeyEvents -AcceptPointerEvents -AcceptSetDesktopSize -SendCutText -AcceptCutText :0
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      In diesem Block richten Sie den X11-Server ein. X11 ist ein Display-Server-Protokoll, das die Ausführung von GUI-Anwendungen ermöglicht. Beachten Sie, dass es in Zukunft durch Wayland ersetzt werden wird, aber der Fernzugriff befindet sich noch in der Entwicklung.

      Für diesen Container verwenden Sie TigerVNC und seinen integrierten VNC-Server. Dies hat eine Reihe von Vorteilen gegenüber der Verwendung eines separaten X11- und VNC-Servers:

      • Schneller Reaktionszeit, da die GUI-Zeichnung direkt auf dem VNC-Server erfolgt und nicht in einem zwischengeschalteten Frambuffer (dem Speicher, der den Bildschirminhalt speichert).
      • Automatische Größenanpassung des Bildschirms, wodurch die Fernanwendung die Größe automatisch an den Client (in diesem Fall Ihr Webbrowser-Fenster) anpassen kann.

      Wenn Sie möchten, können Sie das Argument für die Option -desktop von Thunderbird auf etwas anderes Ihrer Wahl ändern. Der Server zeigt Ihre Wahl als Titel der Webseite an, die für den Zugriff auf Ihre Anwendung verwendet wird.

      Fügen wir nun einen dritten Code-Block zu supervisord.conf hinzu, um easy-novnc zu starten:

      ~/thunderbird/supervisord.conf

      ...
      [program:easy-novnc]
      priority=0
      command=/usr/local/bin/easy-novnc --addr :8080 --host localhost --port 5900 --no-url-password --novnc-params "resize=remote"
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      In diesem Block richten Sie easy-novnc ein, einen eigenständigen Server, der einen Wrapper um noVNC bereitstellt. Dieser Server erfüllt zwei Rollen. Erstens stellt er eine einfache Verbindungsseite bereit, auf der Sie Optionen für die Verbindung konfigurieren und Standardoptionen festlegen können. Zweitens stellt er VNC über WebSocket als Proxy bereit, sodass der Zugriff über einen gewöhnlichen Webbrowser möglich ist.

      Normalerweise wird die Größenanpassung auf der Client-Seite vorgenommen (d. h. die Bildskalierung), aber Sie verwenden die Option resize=remote, um die Vorteile der Remote-Auflösungseinstellung von TigerVNC voll zu nutzen. Dies bietet auch eine geringere Latenz auf langsameren Geräten, wie z. B. Chromebooks niedrigerer Leistungsklassen:

      Anmerkung: Dieses Tutorial verwendet easy-novnc. Wenn Sie möchten, können Sie stattdessen websockify und einen separaten Webserver verwenden. Der Vorteil von easy-novnc besteht darin, dass der Speicherverbrauch und die Startzeit deutlich geringer sind und dass es in sich geschlossen ist. easy-novnc bietet außerdem eine sauberere Verbindungsseite als die Standardseite von noVNC und ermöglicht die Einstellung von Standardoptionen, die für diese Einrichtung hilfreich sind (wie resize=remote).

      Fügen Sie nun den folgenden Block zu Ihrer Konfiguration hinzu, um OpenBox, den Fenstermanager, zu starten:

      ~/thunderbird/supervisord.conf

      ...
      [program:openbox]
      priority=1
      command=/usr/bin/openbox
      environment=DISPLAY=:0
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      In diesem Block richten Sie OpenBox ein, einen schlanken X11-Fenstermanager. Sie könnten diesen Schritt überspringen, aber ohne ihn hätten Sie keine Titellisten und könnten die Fenstergröße nicht ändern.

      Zum Schluss fügen wir den letzten Block zu supervisord.conf hinzu, wodurch die Hauptanwendung gestartet wird:

      ~/thunderbird/supervisord.conf

      ...
      [program:app]
      priority=1
      environment=DISPLAY=:0
      command=/usr/bin/thunderbird
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      In diesem letzten Block setzen Sie priority auf 1, um sicherzustellen, dass Thunderbird nach TigerVNC gestartet wird. Ansonsten würde es auf eine Race-Bedingung treffen und womöglich nicht starten. Wir setzen auch autorestart=true, um die Anwendung automatisch wieder zu öffnen, wenn sie versehentlich geschlossen wird. Die Umgebungsvariable DISPLAY weist die Anwendung zur Anzeige auf dem zuvor erstellten VNC-Server an.

      So wird Ihre fertiggestellte supervisord.conf aussehen:

      ~/thunderbird/supervisord.conf

      [supervisord]
      nodaemon=true
      pidfile=/tmp/supervisord.pid
      logfile=/dev/fd/1
      logfile_maxbytes=0
      
      [program:x11]
      priority=0
      command=/usr/bin/Xtigervnc -desktop "Thunderbird" -localhost -rfbport 5900 -SecurityTypes None -AlwaysShared -AcceptKeyEvents -AcceptPointerEvents -AcceptSetDesktopSize -SendCutText -AcceptCutText :0
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      
      [program:easy-novnc]
      priority=0
      command=/usr/local/bin/easy-novnc --addr :8080 --host localhost --port 5900 --no-url-password --novnc-params "resize=remote"
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      
      [program:openbox]
      priority=1
      command=/usr/bin/openbox
      environment=DISPLAY=:0
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      
      [program:app]
      priority=1
      environment=DISPLAY=:0
      command=/usr/bin/thunderbird
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      Wenn Sie eine andere Anwendung containerisieren möchten, ersetzen Sie /usr/bin/thunderbird durch den Pfad zur ausführbaren Datei Ihrer Anwendung. Andernfalls sind Sie nun bereit, das Hauptmenü Ihrer GUI zu konfigurieren.

      Schritt 2 — Einrichten des OpenBox-Menüs

      Nachdem Ihr Prozessmanager konfiguriert ist, richten wir nun das OpenBox-Menü ein. Dieses Menü ermöglicht es uns, Anwendungen innerhalb des Containers zu starten. Bei Bedarf werden wir auch einen Terminal- und Prozessmonitor für das Debugging einschließen.

      Verwenden Sie innerhalb des Verzeichnisses Ihrer Anwendung nano oder Ihren bevorzugten Texteditor, um eine neue Datei namens menu.xml zu erstellen und zu öffnen:

      • nano ~/thunderbird/menu.xml

      Fügen Sie nun den folgenden Code zu menu.xml hinzu:

      ~/thunderbird/menu.xml

      <?xml version="1.0" encoding="utf-8"?>
      <openbox_menu xmlns="http://openbox.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://openbox.org/ file:///usr/share/openbox/menu.xsd">
          <menu id="root-menu" label="Openbox 3">
              <item label="Thunderbird">
                  <action name="Execute">
                      <execute>/usr/bin/thunderbird</execute>
                  </action>
              </item>
              <item label="Terminal">
                  <action name="Execute">
                      <execute>/usr/bin/x-terminal-emulator</execute>
                  </action>
              </item>
              <item label="Htop">
                  <action name="Execute">
                      <execute>/usr/bin/x-terminal-emulator -e htop</execute>
                  </action>
              </item>
          </menu>
      </openbox_menu>
      

      Diese XML-Datei enthält die Menüeinträge, die angezeigt werden, wenn Sie mit der rechten Maustaste auf den Desktop klicken. Jedes Element besteht aus einem Label und einer Aktion.

      Wenn Sie eine andere Anwendung containerisieren möchten, ersetzen Sie /usr/bin/thunderbird durch den Pfad zur ausführbaren Datei Ihrer Anwendung und ändern Sie das Label des Elements.

      Schritt 3 — Erstellen der Dockerfile

      Nachdem OpenBox konfiguriert ist, erstellen Sie nun die Dockerfile, die alles miteinander verbindet.

      Erstellen Sie eine Dockerfile im Verzeichnis Ihres Containers:

      • nano ~/thunderbird/Dockerfile

      Um zu beginnen, fügen wir etwas Code hinzu, um easy-novnc zu erstellen:

      ~/thunderbird/Dockerfile

      FROM golang:1.14-buster AS easy-novnc-build
      WORKDIR /src
      RUN go mod init build && 
          go get github.com/geek1011/easy-novnc@v1.1.0 && 
          go build -o /bin/easy-novnc github.com/geek1011/easy-novnc
      

      In der ersten Stufe erstellen Sie easy-novnc. Dies wird aus Gründen der Einfachheit und Platzersparnis in einem separaten Schritt durchgeführt – Sie benötigen nicht die gesamte Go-Toolchain in Ihrem endgültigen Image. Beachten Sie das @v1.1.0 im Befehl „build“. Dadurch wird sichergestellt, dass das Ergebnis deterministisch ist, was wichtig ist, weil Docker das Ergebnis jedes einzelnen Schritts zwischenspeichert. Wenn Sie keine explizite Version angegeben hätten, würde Docker zum Zeitpunkt der ersten Erstellung des Images auf die neueste Version von easy-novnc verweisen. Darüber hinaus möchten Sie sicherstellen, dass Sie eine bestimmte Version von easy-novnc herunterladen, für den Fall, dass an der CLI-Schnittstelle gravierende Änderungen vorgenommen werden.

      Erstellen wir nun die zweite Stufe, die zum endgültigen Image wird. Hier verwenden Sie Debian 10 (buster) als Basis-Image. Beachten Sie, dass dieses, da es in einem Container ausgeführt wird, unabhängig von der auf Ihrem Server laufenden Distribution funktioniert.

      Fügen Sie als Nächstes den folgenden Block zu Ihrer Dockerfile hinzu:

      ~/thunderbird/Dockerfile

      ...
      FROM debian:buster
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends openbox tigervnc-standalone-server supervisor gosu && 
          rm -rf /var/lib/apt/lists && 
          mkdir -p /usr/share/desktop-directories
      

      In dieser Anweisung installieren Sie Debian 10 als Ihr Basis-Image und installieren dann das absolute Minimum, das erforderlich ist, um GUI-Anwendungen in Ihrem Container auszuführen. Beachten Sie, dass Sie apt-get update als Teil der gleichen Anweisung ausführen, um Zwischenspeicherungsprobleme von Docker zu verhindern. Um Speicherplatz zu sparen, entfernen Sie auch die danach heruntergeladenen Paketlisten (die zwischengespeicherten Pakete selbst werden standardmäßig entfernt). Sie erstellen auch /usr/share/desktop-directories, da einige Anwendungen von dem vorhandenen Verzeichnis abhängen.

      Fügen wir einen weiteren kleinen Code-Block hinzu:

      ~/thunderbird/Dockerfile

      ...
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends lxterminal nano wget openssh-client rsync ca-certificates xdg-utils htop tar xzip gzip bzip2 zip unzip && 
          rm -rf /var/lib/apt/lists
      

      In dieser Anweisung installieren Sie einige nützliche Allzweck-Dienstprogramme und -Pakete. Von besonderem Interesse sind hier xdg-utils (das die Basisbefehle bereitstellt, die von Desktop-Anwendungen unter Linux verwendet werden) und ca-certificates (das die Stammzertifikate installiert, um uns den Zugriff auf HTTPS-Seiten zu ermöglichen).

      Nun können wir die Anweisungen für die Hauptanwendung hinzufügen:

      ~/thunderbird/Dockerfile

      ...
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends thunderbird && 
          rm -rf /var/lib/apt/lists
      

      Wie zuvor installieren wir hier die Anwendung. Wenn Sie eine andere Anwendung containerisieren möchten, können Sie diese Befehle durch die Befehle ersetzen, die zum Installieren Ihrer spezifischen Anwendung erforderlich sind. Einige Anwendungen erfordern etwas mehr Arbeit, um in Docker ausgeführt zu werden. Wenn Sie beispielsweise eine App installieren, die Chrome, Chromium oder QtWebEngine verwendet, müssen Sie das Befehlszeilenargument --no-sandbox verwenden, da es von Docker nicht unterstützt wird.

      Als Nächstes fügen wir die Anweisungen zum Hinzufügen der letzten wenigen Dateien zum Container hinzu:

      ~/thunderbird/Dockerfile

      ...
      COPY --from=easy-novnc-build /bin/easy-novnc /usr/local/bin/
      COPY menu.xml /etc/xdg/openbox/
      COPY supervisord.conf /etc/
      EXPOSE 8080
      

      Hier fügen Sie dem Image die zuvor erstellten Konfigurationsdateien hinzu, und kopieren die Binärdatei easy-novnc aus der ersten Stufe.

      Dieser nächste Code-Block erstellt das Datenverzeichnis und fügt einen dedizierten Benutzer für Ihre App hinzu. Dies ist wichtig, da einige Anwendungen sich weigern als root ausgeführt zu werden. Es ist auch eine bewährte Praxis, Anwendungen nicht als root auszuführen, auch nicht in einem Container.

      ~/thunderbird/Dockerfile

      ...
      RUN groupadd --gid 1000 app && 
          useradd --home-dir /data --shell /bin/bash --uid 1000 --gid 1000 app && 
          mkdir -p /data
      VOLUME /data
      

      Um eine konsistente UID/GID für die Dateien zu gewährleisten, setzen Sie beide ausdrücklich auf 1000. Außerdem installieren Sie ein Volumen in das Datenverzeichnis, um sicherzustellen, dass es zwischen den Neustarts erhalten bleibt.

      Zum Schluss fügen wir noch die Anweisungen zum Starten von allem hinzu:

      ~/thunderbird/Dockerfile

      ...
      CMD ["sh", "-c", "chown app:app /data /dev/stdout && exec gosu app supervisord"]
      

      Wenn sie den Standardbefehl auf supervisord setzen,wir der Manager die für die Ausführung Ihrer Anwendung erforderlichen Prozesse starten. In diesem Fall verwenden Sie CMD anstatt ENTRYPOINT. In den meisten Fällen würde es keinen Unterschied machen, aber die Verwendung von CMD ist für diesen Zweck aus einigen Gründen besser geeignet. Erstens nimmt supervisord keine Argumente entgegen, die für uns relevant wären, und wenn Sie dem Container Argumente hinzufügen, ersetzten diese CMD und werden an ENTRYPOINT angehängt. Zweitens ermöglicht uns die Verwendung von CMD, bei der Übergabe von Argumenten an den Container einen völlig anderen Befehl (der von /bin/sh -c ausgeführt wird), anzugeben, was das Debuggen erleichtert.

      Und schließlich müssen Sie vor dem Starten von supervisord chown als root ausführen, um Berechtigungsprobleme auf dem Datenvolumen zu verhindern und den untergeordneten Prozessen das Öffnen von stdout zu ermöglichen. Das bedeutet auch, dass sie gosu anstelle der Anweisung USER verwenden müssen, um den Benutzer zu wechseln.

      So wird Ihre fertiggestellte Dockerfile aussehen:

      ~/thunderbird/Dockerfile

      FROM golang:1.14-buster AS easy-novnc-build
      WORKDIR /src
      RUN go mod init build && 
          go get github.com/geek1011/easy-novnc@v1.1.0 && 
          go build -o /bin/easy-novnc github.com/geek1011/easy-novnc
      
      FROM debian:buster
      
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends openbox tigervnc-standalone-server supervisor gosu && 
          rm -rf /var/lib/apt/lists && 
          mkdir -p /usr/share/desktop-directories
      
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends lxterminal nano wget openssh-client rsync ca-certificates xdg-utils htop tar xzip gzip bzip2 zip unzip && 
          rm -rf /var/lib/apt/lists
      
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends thunderbird && 
          rm -rf /var/lib/apt/lists
      
      COPY --from=easy-novnc-build /bin/easy-novnc /usr/local/bin/
      COPY menu.xml /etc/xdg/openbox/
      COPY supervisord.conf /etc/
      EXPOSE 8080
      
      RUN groupadd --gid 1000 app && 
          useradd --home-dir /data --shell /bin/bash --uid 1000 --gid 1000 app && 
          mkdir -p /data
      VOLUME /data
      
      CMD ["sh", "-c", "chown app:app /data /dev/stdout && exec gosu app supervisord"]
      

      Speichern und schließen Sie Ihre Dockerfile. Nun sind wir bereit, unseren Container zu erstellen und auszuführen und dann auf Thunderbird — eine GUI-Anwendung — zugreifen.

      Schritt 4 — Erstellen und Ausführen des Containers

      Der nächste Schritt besteht darin, Ihren Container zu erstellen und so einzustellen, dass er beim Starten ausgeführt wird. Sie werden auch ein Volumen einrichten, um die Anwendungsdaten zwischen Neustarts und Aktualisierungen zu erhalten.

      Erstellen Sie zuerst Ihren Container. Stellen Sie sicher, dass diese Befehle im Verzeichnis ~/thunderbird ausgeführt werden:

      • docker build -t thunderbird .

      Erstellen Sie nun ein neues Netzwerk, das von den Containern der Anwendung gemeinsam genutzt wird:

      • docker network create thunderbird-net

      Erstellen Sie dann ein Volume zum Speichern der Anwendungsdaten:

      • docker volume create thunderbird-data

      Führen Sie es abschließen aus und stellen Sie es so ein, dass es automatisch neu startet:

      • docker run --detach --restart=always --volume=thunderbird-data:/data --net=thunderbird-net --name=thunderbird-app thunderbird

      Beachten Sie, dass Sie, wenn Sie möchten, die thunderbird-app nach der Option --name durch einen anderen Namen ersetzen können. Was auch immer Sie gewählt haben, Ihre Anwendung ist nun containerisiert und wird ausgeführt. Verwenden wir nun den Caddy Webserver, um sie zu sichern und eine Fernverbindung zu ihr aufzubauen.

      Schritt 5 — Einrichten von Caddy

      In diesem Schritt richten Sie den Caddy-Webserver so ein, dass er Authentifizierung und, optional, Fernzugriff auf Ihre Dateien über WebDAV bietet. Der Einfachheit halber und damit Sie ihn mit Ihrem vorhandenen Reverse-Proxy verwenden können, werden Sie ihn in einem anderen Container ausführen.

      Erstellen Sie ein neues Verzeichnis und gehen Sie dann in dieses:

      Erstellen Sie nun mit nano oder Ihrem bevorzugten Editor eine neue Dockerfile:

      Fügen Sie dann die folgenden Anweisungen hinzu:

      ~/caddy/Dockerfile

      FROM golang:1.14-buster AS caddy-build
      WORKDIR /src
      RUN echo 'module caddy' > go.mod && 
          echo 'require github.com/caddyserver/caddy/v2 v2.0.0' >> go.mod && 
          echo 'require github.com/mholt/caddy-webdav v0.0.0-20200523051447-bc5d19941ac3' >> go.mod
      RUN echo 'package main' > caddy.go && 
          echo 'import caddycmd "github.com/caddyserver/caddy/v2/cmd"' >> caddy.go && 
          echo 'import _ "github.com/caddyserver/caddy/v2/modules/standard"' >> caddy.go && 
          echo 'import _ "github.com/mholt/caddy-webdav"' >> caddy.go && 
          echo 'func main() { caddycmd.Main() }' >> caddy.go
      RUN go build -o /bin/caddy .
      
      FROM debian:buster
      
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends gosu && 
          rm -rf /var/lib/apt/lists
      
      COPY --from=caddy-build /bin/caddy /usr/local/bin/
      COPY Caddyfile /etc/
      EXPOSE 8080
      
      RUN groupadd --gid 1000 app && 
          useradd --home-dir /data --shell /bin/bash --uid 1000 --gid 1000 app && 
          mkdir -p /data
      VOLUME /data
      
      WORKDIR /data
      CMD ["sh", "-c", "chown app:app /data && exec gosu app /usr/local/bin/caddy run -adapter caddyfile -config /etc/Caddyfile"]
      

      Diese Dockerfile erstellt Caddy mit dem aktivierten WebDAV-Plugin und startet ihn dann auf Port 8080 mit der Caddyfile unter /etc/Caddyfile. Speichern und schließen Sie die Datei.

      Als Nächstes konfigurieren Sie den Caddy-Webserver. Erstellen Sie eine Datei namens Caddyfile im gerade erstellten Verzeichnis:

      Fügen Sie nun den folgenden Code-Block zu Ihrer Caddyfile hinzu:

      ~/caddy/Caddyfile

      {
          order webdav last
      }
      :8080 {
          log
          root * /data
          reverse_proxy thunderbird-app:8080
      
          handle /files/* {
              uri strip_prefix /files
              file_server browse
          }
          redir /files /files/
      
          handle /webdav/* {
              uri strip_prefix /webdav
              webdav
          }
          redir /webdav /webdav/
      
          basicauth /* {
              {env.APP_USERNAME} {env.APP_PASSWORD_HASH}
          }
      }
      

      Diese Caddyfile verweist das Stammverzeichnis an den in Schritt 4 erstellten Container thunderbird-app (Docker löst ihn in die richtige IP auf). Es wird auch einen schreibgeschützten webbasierten Dateibrowser auf /files bedienen und einen WebDAV-Server auf /webdav ausführen, den Sie lokal installieren können, um auf Ihre Dateien zugreifen zu können. Der Benutzername und das Passwort werden aus den Umgebungsvariablen APP_USERNAME und APP_PASSWORD_HASH gelesen.

      Erstellen Sie nun den Container:

      • docker build -t thunderbird-caddy .

      Caddy v.2 erfordert, dass Sie Ihr gewünschtes Passwort hashen. Führen Sie den folgenden Befehl aus und denken Sie daran, mypass durch ein starkes Passwort Ihrer Wahl zu ersetzen:

      • docker run --rm -it thunderbird-caddy caddy hash-password -plaintext 'mypass'

      Dieser Befehl gibt eine Zeichenfolge aus. Kopieren Sie diese in die Zwischenablage, um die Ausführung des nächsten Befehls vorzubereiten.

      Jetzt sind Sie bereit, den Container auszuführen. Achten Sie darauf, myuser durch einen Benutzernamen Ihrer Wahl zu ersetzen und ersetzen Sie mypass-hash durch die Ausgabe des im vorherigen Schritt ausgeführten Befehls. Sie können auch den Port (hier 8080) ändern, um über einen anderen Port auf Ihren Server zuzugreifen:

      • docker run --detach --restart=always --volume=thunderbird-data:/data --net=thunderbird-net --name=thunderbird-web --env=APP_USERNAME="myuser" --env=APP_PASSWORD_HASH="mypass-hash" --publish=8080:8080 thunderbird-caddy

      Wir sind nun bereit, auf unsere Anwendung zugreifen und sie zu testen.

      Schritt 6 — Testen und Verwalten der Anwendung

      Greifen wir nun auf die Anwendung zu und stellen sicher, dass sie funktioniert.

      Öffnen Sie zunächst http://your_server_ip:8080 in einem Webbrowser, melden Sie sich mit den zuvor gewählten Anmeldeinformationen an und klicken Sie auf Connect.

      Verbindungsseite von NoVNC

      Sie sollten nun in der Lage sein, mit der Anwendung zu interagieren und sie sollte sich automatisch an die Größe Ihres Browserfensters anpassen.

      Hauptmenü von Thunderbird

      Wenn Sie mit der rechten Maustaste auf den schwarzen Desktop klicken, sollten Sie ein Menü sehen, das Ihnen den Zugriff auf ein Terminal ermöglicht. Wenn Sie mit der mittleren Maustaste klicken, sollten Sie eine Liste von Fenstern sehen.

      NoVNC Klicken mit der rechten Maustaste

      Öffnen Sie nun http://your_server_ip:8080/files/ in einem Webbrowser. Sie sollten in der Lage sein, auf Ihre Dateien zugreifen.

      NoVNC Dateizugriff webdav

      Optional können Sie versuchen, http://your_server_ip:8080/webdav/ in einem WebDAV-Client zu installieren. Sie sollten in der Lage sein, direkt auf Ihre Dateien zuzugreifen und sie zu ändern. Wenn Sie die Option Map network drive (Netzlaufwerk zuordnen) im Windows Explorer verwenden, müssen Sie entweder einen Reverse-Proxy verwenden, um HTTPS hinzuzufügen oder HKLMSYSTEMCurrentControlSetServicesWebClientParametersBasicAuthLevel auf DWORD:2 setzen.

      In beiden Fällen ist Ihre native GUI-Anwendung nun für die Fernverwendung bereit.

      Zusammenfassung

      Sie haben nun erfolgreich einen Docker-Container für Thunderbird eingerichtet und dann mit Caddy den Zugriff darauf über einen Webbrowser konfiguriert. Sollten Sie Ihre App jemals aktualisieren müssen, halten Sie die Container an, führen Sie docker rm thunderbird-app thunderbird-web aus, erstellen Sie die Images neu und führen Sie dann die Befehle docker run aus den vorherigen Schritten oben erneut aus. Ihre Daten bleiben weiterhin erhalten, da sie in einem Volumen gespeichert sind.

      Wenn Sie mehr über grundlegende Docker-Befehle erfahren möchten, können Sie dieses Tutorial oder dieses Cheatsheet lesen. Für den längerfristigen Gebrauch sollten Sie auch in Betracht ziehen, HTTPS (hierfür ist eine Domäne erforderlich) für zusätzliche Sicherheit zu aktivieren.

      Wenn Sie mehr als eine Anwendung bereitstellen, möchten Sie möglicherweise Docker Compose oder Kubernetes verwenden, anstatt jeden Container manuell zu starten. Denken Sie daran, dass dieses Tutorial als Grundlage für die Ausführung jeder anderen Linux-Anwendung auf Ihrem Server dienen kann, einschließlich:

      • Wine, eine Kompatibilitätsschicht für die Ausführung von Windows-Anwendungen unter Linux.
      • GIMP, ein Open-Source-Bildbearbeitungsprogramm.
      • Cutter, eine Open-Source-Plattform für Reverse Engineering.

      Diese letzte Option zeigt das große Potenzial der Containerisierung und des Fernzugriffs auf GUI-Anwendungen. Mit dieser Einrichtung können Sie nun einen Server mit wesentlich mehr Rechenleistung, als Sie möglicherweise vor Ort haben, verwenden, um ressourcenintensive Tools wie Cutter auszuführen.



      Source link