Matthias S. schrieb:
ich habe mir einen Rechner mit div. Docker-Containern zerschossen. Dabei
durfte ich feststellen, dass meine BackUp-Strategrie wohl nicht die
beste war. Die beruhte drauf mit Resiliosync das
Docker-Volume-Verzeichnis /var/lib/docker/volumes auf einen anderen
Rechner zu synchronisieren.
"Nicht die beste BackUp-Strategrie" ist eine feine Untertreibung. :-)
Einige Container konnte ich ganz gut wieder zu laufen bringen, in dem
ich nach dem zurück kopieren (mithilfe eines Docker-Containers) ein
'chmod -R 777 ./' über das Volume ausgeführt habe.
Auch ein "chmod -R 777" ist keine besonders gute Strategrie, aber das haben die Kollegen in diesem Thread Dir ja bereits gesagt... So etwas wie
1 |
find <dir> -type d -print0 | xargs -0 -- chmod 755
|
2 |
find <dir> -type f -print0 | xargs -0 -- chmod 644
|
ist immer meistens noch keine gute Strategrie, aber immerhin besser, als alles (!) mit Lese-, Schreib- und Ausführrechten (!) zu versehen.
Etwas kurios ist dagegen InfluxDB (1.8):
Daten des Volumes zurück kopiert, 'chmod -R 777 ./' darüber ausgeführt.
Und kein chown(1)? Hm.
Container läuft, Datenbanken sind da, Benutzer sind da, NodeRed kann
Daten reinschreiben, Grafana kann Daten auslesen. Aber: alle bisherigen
Daten sind irgendwie weg, bzw. Grafana zeigt diese nicht mehr an -
obwohl die ja eigentlich da drinnen stecken sollten?
Leider kenne ich mich mit InfluxDB nicht aus, dafür aber mit einigen anderen Datenmanagementsystemen. Manche davon haben SEHR eigenwillige Vorstellungen davon, wem ihre Dateien und Verzeichnisse zu gehören und welche Permissions sie gefälligst zu haben haben. Das hier (vom klugen Ernst, natürlich) schon genannte PostgreSQL etwa verweigert den Start, wenn sein Datenverzeichnis nicht dem Benutzer "postgres" gehört, oder nicht die Permissions 0700 oder 0750 hat. Das ist auch gut so, denn in den Daten eines Datenmanagementsystems hat außer ihm selbst natürlich grundsätzlich nichts etwas zu suchen.
Und dann, hach ja, die Benutzerkennungen oder, genauer, die User-IDs. Weil so ein Linux-Setup ein, sagen wir mal... schwer vorhersagbares Ding ist, werden Benutzerkennungen häufig dynamisch vergeben, auch für Daemon- und Systemuser. Mit on-the-fly gestarteten Docker-Containern läßt sich das leicht überprüfen: installiere ich dort zuerst InfluxDB und dann PostgreSQL, dann sehen die UID so aus:
1 |
username | uid
|
2 |
---------+-----
|
3 |
influxdb | 100
|
4 |
postgres | 102
|
Installiere ich hingegen zuerst PostgreSQL und dann InfluxDB, haben die User plötzlich ganz andere User-IDs:
1 |
username | uid
|
2 |
---------+-----
|
3 |
postgres | 101
|
4 |
influxdb | 102
|
(Vor PostgreSQL wird noch ein User "messagebus" angelegt, aber das spielt hier keine Rolle.)
Du siehst: die Benutzerkennungen, unter denen Deine Prozesse innerhalb Deiner Container laufen, sind nicht immer dieselben -- und, Achtung: auch nicht die auf Deinem Hostsystem. Das führt hier bei mir beispielsweise zu der lustigen Situation, daß die Datendateien meines OpenSearch-Containers im Container die User-ID 1000 des Benutzers "opensearch", aber auf dem Host die User-Id meines normalen Shellbenutzers haben. In meinem Redis-Container hat der Redis-Server die Benutzerkennung "redis" mit der User-ID 999, die auf meinem Host dem User "systemd-coredump" vorbehalten ist.
Also -- und das ist der Punkt -- in Deinen Docker-Volume-Verzeichnissen auf Deinem Host, also: jenen Verzeichnissen, die Du mit Deiner "Backup-Strategrie" herum kopierst, legen die Prozesse Deiner Containern ihre Daten unter jener User-ID ab, mit der die Prozesse in Deinen Containern laufen. Die muß nicht einmal mit Deinem Host konsistent sein, und ist es höchstwahrscheinlich auch nicht zwischen verschiedenen Docker-Containern (oder -Generationen).
Okay, wie gehen wir mit dem "Problem" jetzt um? Da gibt es verschiedene Ideen und Strategien, die erste ist ein Feature namens userns-remaß, also Sub-UIDs und Sub-GIDs, die Manpages dazu gibt es in subuid(5) und subgid(5). Damit lassen sich Unter-IDs für Systembenutzer einrichten, aber Achtung: Docker läuft entweder mit oder ohne, und wer dieses Feature einschaltet, muß wissen, daß seine existierenden Container dann nicht mehr starten. Siehe auch [1].
Dann gibt es die Möglichkeit, feste User-IDs in den Containern bereits beim Erzeugen der Images festzulegen, sei es mit useradd(8) oder adduser(8), oder (diese Möglichkeit ist eher unbekannt) indem einfach die passenden Dateien passwd und group in /etc des Image angelegt werden, /bevor/ die gewünschte Software installiert wird. Einfach ein
1 |
echo 'nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin' > /etc/passwd
|
2 |
echo 'nogroup:x:65534:' > /etc/group
|
im "RUN" eines Dockerfile und danach ein "USER nobody", schon läuft der ganze Prozess im Container als "nobody" mit der User-ID 65534. Ebenso kann man eine definierte User-ID beispielsweise für Benutzer wie "postgres" oder "influxdb" anlegen, bevor die betreffende Software im Image installiert wird -- oder wenn sie bereits installiert ist, mit usermod(8) die angelegten User modifizieren und ihnen fest vorgegebene User-IDs zuzuweisen (dann allerdings auch die bei der Installation angelegten Dateien und Verzeichnisse... genau). Die letztere Möglichkeit funktioniert sogar, ohne daß die Benutzerverwaltungswerkzeuge im Image installiert worden sind.
Wie dem auch sei: am Ende wirst Du für jede halbwegs zuverlässige Strategie reproduzierbare User- und Group-IDs brauchen.
[1] https://docs.docker.com/engine/security/userns-remap/
Bessere Idee für BackUps? Interessant wäre ja:
https://github.com/alaub81/backup_docker_scripts
Da ich über das BackUp dann auch noch ein versioniertes BackUp laufen
lasse (Duplicati), würde ich mir in dieses jede Menge große Volumes
reinspeichern, was auch irgendwie doof ist...
Was nützt Dir die beste Backup-Strategrie, wenn Du das Restore nicht getestet hast? Richtig: nichts, oder, anders gesagt: hast Du kein Backup. Und ohne Dir zu Nahe treten zu wollen: einfach nur Daten irgendwohin sichern kostet zwar Speicherplatz, bietet Dir aber keine Garantie, sie im Falle eines Desasters wiederherstellen zu können. Und Dir irgendwas un- oder halb Verstandenes aus dem Internet zusammen zu kopieren, macht die Sache kaum besser.
In meinem ganz persönlichen Fall sind die allermeisten Images selbst erzeugt, und haben ein eigenes Programm als ENTRYPOINT. Je nachdem, wie es aufgerufen wird, arbeitet es als reiner Entrypoint und nutzt den Systembefehl exece(2), um den "eigentlichen" Entrypoint des Image zu starten. Gleichzeitig fungiert es mit den passenden Argumenten aber auch als HEALTHCHECK und bei Containern, die Daten persistieren, werden diese in Tarballs auf STDOUT gedumpt oder aus ebensolchen von STDIN restauriert. Dadurch haben die Images eine einheitliche Bedienung, die sich obendrein über Labels prima automatisieren läßt. Das ist zwar ein bisschen Arbeit, aber sehr komfortabel. Und es verträgt sich prima mit meinen versionierten Backups (noch rsnapshot, künftig wohl Borg).
Wie dem auch sei: wenn Deine Datenmengen nicht exorbitant groß oder variant sind, dann ist es meist einfacher, Deine Daten mit "docker exec" erstmal in einen konsistenten Dump zu überführen und dann ins Backup zu schieben. Die meisten mir bekannten Backupwerkzeuge bieten die Option, vor dem Anfertigen eines neuen Backup ein oder mehrere Skripte auszuführen. Nutze sie.