Docker Volumes: Eine Übersicht
Die grundlegende Motivation hinter der Entkopplung von Daten und Containern habe ich in der Zusammenfassung für Bind Mounts erklärt: Sämtliche Modifikationen, die ein Container am Dateisystem seines darunterliegenden Images vornimmt, existieren nur in dem jeweiligen Container und gehen zusammen mit dem Container verloren.
Wer Daten persistieren möchte, die von einem Container generiert wurden, muss diese Daten ins Dateisystem des Hosts auslagern. Der bevorzugte Weg hierfür sind Volumes.
Unterschiede und Vorteile gegenüber Bind Mounts
Im Gegensatz zu Bind Mounts legt der Benutzer bei Volumes kein Verzeichnis auf dem Host fest, das in den Container eingehängt werden soll. Stattdessen gibt er nur an, welches Verzeichnis auf dem Container er als Volume einbinden möchte. Die Daten dieses Volumes liegen dann in einem Bereich auf dem Host, der ausschließlich von Docker verwaltet wird.
Das offizielle PostgreSQL-Image speichert seine Daten im Verzeichnis
Welche Vorteile bringt das gegenüber Bind Mounts?
Named Volumes erstellen
Im obigen Beispiel haben wir die PostgreSQL-Daten in ein eigenes Volume auslagert. Da wir keinen expliziten Namen für dieses Volume vergeben haben, handelt es sich um ein anonymes Volume. Es erhielt von Docker eine zufällig generierte ID als "Namen":
Um besser mit Volumes arbeiten zu können, kann ein zusätzlicher Name für das Volume angegeben werden. Im Falle der
In diesem Beispiel wird ein Named Volume mit dem Namen
Dieser Befehl erlaubt auch die Angabe von verschiedenen Optionen, wie beispielsweise die Verwendung eines bestimmten Volume-Treibers. Mit
Warum --mount zu bevorzugen ist
Wem die Option
Um hier Verwirrung zu vermeiden, ist es sehr ratsam, auf die Option
Als
Backups mit temporären Containern erstellen
Nur weil alle Volume-Daten ausschließlich von Docker verwaltet werden, bedeutet das nicht, dass wir nicht mit den Daten arbeiten können. Der Name eines Volumes bietet dem Nutzer einen Anhaltspunkt, um beispielsweise Backups dieser Daten zu erstellen.
Die Situation: Der PostgreSQL-Container
Dieser temporäre Container hängt das Volume an der Stelle
Neben diesem Pattern gibt es zahlreiche weitere Möglichkeiten, mit Volumes zu arbeiten. Damit eignen sich Volumes hervorragend, um Verzeichnisse und Daten unabhängig vom Lebenszyklus eines Containers zu machen und bieten darüber hinaus auch die Möglichkeit, Daten auf einem anderen Host oder bei Cloud-Diensten wie AWS zu speichern.
Die grundlegende Motivation hinter der Entkopplung von Daten und Containern habe ich in der Zusammenfassung für Bind Mounts erklärt: Sämtliche Modifikationen, die ein Container am Dateisystem seines darunterliegenden Images vornimmt, existieren nur in dem jeweiligen Container und gehen zusammen mit dem Container verloren.
Wer Daten persistieren möchte, die von einem Container generiert wurden, muss diese Daten ins Dateisystem des Hosts auslagern. Der bevorzugte Weg hierfür sind Volumes.
Unterschiede und Vorteile gegenüber Bind Mounts
Im Gegensatz zu Bind Mounts legt der Benutzer bei Volumes kein Verzeichnis auf dem Host fest, das in den Container eingehängt werden soll. Stattdessen gibt er nur an, welches Verzeichnis auf dem Container er als Volume einbinden möchte. Die Daten dieses Volumes liegen dann in einem Bereich auf dem Host, der ausschließlich von Docker verwaltet wird.
Das offizielle PostgreSQL-Image speichert seine Daten im Verzeichnis
/var/lib/postgres/data
, welches hier als Volume eingebunden wird. Syntaktisch unterscheidet sich der entsprechende Befehl nur dadurch von einem Bind-Mount, dass das Host-Verzeichnis fehlt:
Bash:
$ docker container run -d --name database -v /var/lib/postgres/data postgres
Welche Vorteile bringt das gegenüber Bind Mounts?
- Volumes können Namen erhalten und sind dadurch einfacher handhabbar
- Mit Volumes muss sich der Benutzer nicht mit Speicherort und Implementierung auseinandersetzen
- Volumes sind First-Class-Citizens in Docker und können über die CLI verwaltet werden
- Volumes können unterschiedliche Treiber für unterschiedliche Speicherarten und -orte verwenden
- Mehrere Container können auf ein Volume sicher zugreifen
- Unter Berücksichtigung der eigenen Konfiguration werden Volumes vollständig von Docker verwaltet
Named Volumes erstellen
Im obigen Beispiel haben wir die PostgreSQL-Daten in ein eigenes Volume auslagert. Da wir keinen expliziten Namen für dieses Volume vergeben haben, handelt es sich um ein anonymes Volume. Es erhielt von Docker eine zufällig generierte ID als "Namen":
Bash:
$ docker volume ls
DRIVER VOLUME NAME
local 21aef22affde3ed4ede8c0d66092f73240147099856688389256c05ddd311da8
Um besser mit Volumes arbeiten zu können, kann ein zusätzlicher Name für das Volume angegeben werden. Im Falle der
-v
-Option geschieht das, indem man einen beliebigen Namen vor den Dateipfad setzt:
Bash:
$ docker container run -d --name database -v pg-data:/var/lib/postgres/data postgres
In diesem Beispiel wird ein Named Volume mit dem Namen
pg-data
erstellt. Ein Volume kann aber auch unabhängig vom Start eines Containers erstellt werden:
Bash:
$ docker volume create pg-data
Dieser Befehl erlaubt auch die Angabe von verschiedenen Optionen, wie beispielsweise die Verwendung eines bestimmten Volume-Treibers. Mit
docker volume rm pg-data
kann das Volume später wieder gelöscht werden. Die Behandlung von Volumes als First-Class-Citizens - neben Images, Containern und Netzwerken - erleichtert die Verwaltung erheblich.Warum --mount zu bevorzugen ist
Wem die Option
-v pg-data:/var/lib/postgres/data
bekannt vorkommt, hatte vermutlich bereits Kontakt zu Bind Mounts. Leider unterscheidet sich die Syntax eines Named Volumes durch einen Bind Mount ausschließlich dadurch, dass das erste Argument bei einem Bind Mount ein absoluter Pfad sein muss. Die Option -v $(pwd)/pg-data:/var/lib/postgres/data
würde einen Bind Mount erstellen.Um hier Verwirrung zu vermeiden, ist es sehr ratsam, auf die Option
--mount
mit ihrer selbsterklärenden Syntax zurückzugreifen. Als Nutzer muss man hier nicht darauf achten, ob das erste Argument ein absoluter Pfad oder ein Volume-Name ist. Stattdessen wird der Typ des Mounts explizit angegeben.
Bash:
$ docker container run -d \
--name database \
--mount type=volume,source=pg-data,destination=/var/lib/postgres/data \
postgres
Als
source
wird hier einfach der Name des Volumes angegeben. Die explizite Typangabe macht die Natur des Mounts deutlich sichtbar.Backups mit temporären Containern erstellen
Nur weil alle Volume-Daten ausschließlich von Docker verwaltet werden, bedeutet das nicht, dass wir nicht mit den Daten arbeiten können. Der Name eines Volumes bietet dem Nutzer einen Anhaltspunkt, um beispielsweise Backups dieser Daten zu erstellen.
Die Situation: Der PostgreSQL-Container
database
speichert seine Daten im Volume pg-data
und wir möchten ein Backup im lokalen Verzeichnis db-backup
erstellen. Ein geläufiges Pattern hierfür ist die Verwendung eines temporären Containers, der die Volumes vom PostgreSQL-Container einbindet und die Daten in das Zielverzeichnis kopiert.
Bash:
$ docker container run -d \
--rm \
--mount type=volume,source=pg-data,destination=/from \
--mount type=bind,source=$(pwd)/db-backup,destination=/to \
ubuntu \
tar cvf /to/backup.tar /from
Dieser temporäre Container hängt das Volume an der Stelle
/from
ein und erstellt einen Bind Mount auf das lokale Backup-Verzeichnis. Für das Kopieren der Daten ins Backup-Verzeichnis ist der tar
-Befehl am Ende verantwortlich.Neben diesem Pattern gibt es zahlreiche weitere Möglichkeiten, mit Volumes zu arbeiten. Damit eignen sich Volumes hervorragend, um Verzeichnisse und Daten unabhängig vom Lebenszyklus eines Containers zu machen und bieten darüber hinaus auch die Möglichkeit, Daten auf einem anderen Host oder bei Cloud-Diensten wie AWS zu speichern.