Ich habe eine Weile mit Docker herumgespielt und finde immer wieder das gleiche Problem, wenn ich mit persistenten Daten arbeite.
Ich erstelle mein VolumeDockerfile
und mache es verfügbar oder verwende es --volumes-from
, um einen Hostordner in meinem Container bereitzustellen .
Welche Berechtigungen sollte ich für das freigegebene Volume auf dem Host anwenden?
Ich kann mir zwei Möglichkeiten vorstellen:
Bisher habe ich allen Lese- / Schreibzugriff gewährt, damit ich aus dem Docker-Container in den Ordner schreiben kann.
Ordnen Sie die Benutzer vom Host dem Container zu, damit ich detailliertere Berechtigungen zuweisen kann. Ich bin mir nicht sicher, ob dies möglich ist und habe nicht viel darüber gefunden. Bisher kann ich den Container nur als Benutzer ausführen:
docker run -i -t -user="myuser" postgres
Dieser Benutzer hat jedoch eine andere UID als mein Hostmyuser
, sodass Berechtigungen nicht funktionieren. Ich bin mir auch nicht sicher, ob die Zuordnung der Benutzer Sicherheitsrisiken birgt.
Gibt es andere Alternativen?
Wie geht ihr Jungs / Mädels mit diesem Problem um?
Antworten:
UPDATE 2016-03-02 : Ab Docker 1.9.0 hat Docker Volumes benannt, die Nur-Daten-Container ersetzen . Die folgende Antwort sowie mein verlinkter Blog-Beitrag haben immer noch einen Wert in dem Sinne, wie man über Daten in Docker nachdenkt. Verwenden Sie jedoch benannte Volumes, um das unten beschriebene Muster anstelle von Datencontainern zu implementieren.
Ich glaube, der kanonische Weg, dies zu lösen, ist die Verwendung von Nur-Daten-Containern . Bei diesem Ansatz erfolgt der gesamte Zugriff auf die Volumendaten über Container, die
-volumes-from
den Datencontainer verwenden, sodass die Host-UID / GID keine Rolle spielt.Ein in der Dokumentation angegebener Anwendungsfall ist beispielsweise das Sichern eines Datenvolumens. Zu diesem Zweck wird ein anderer Container verwendet, um die Sicherung über durchzuführen
tar
, und er wird auch verwendet-volumes-from
, um das Volume bereitzustellen. Ich denke, der entscheidende Punkt bei grok ist: Anstatt darüber nachzudenken, wie Sie mit den richtigen Berechtigungen auf die Daten auf dem Host zugreifen können, sollten Sie darüber nachdenken, wie Sie alles tun können, was Sie benötigen - Backups, Surfen usw. - über einen anderen Container . Die Container selbst müssen konsistente UID / GIDs verwenden, müssen jedoch nichts auf dem Host zuordnen und bleiben somit portabel.Dies ist auch für mich relativ neu, aber wenn Sie einen bestimmten Anwendungsfall haben, können Sie dies gerne kommentieren, und ich werde versuchen, die Antwort zu erweitern.
UPDATE : Für den angegebenen Anwendungsfall in den Kommentaren haben Sie möglicherweise ein Bild
some/graphite
zum Ausführen von Graphit und ein Bildsome/graphitedata
als Datencontainer. Wenn man also Ports und dergleichen ignoriert, ist dasDockerfile
Bildsome/graphitedata
so etwas wie:Erstellen und erstellen Sie den Datencontainer:
Das
some/graphite
Dockerfile sollte auch die gleiche UID / GID erhalten, daher könnte es ungefähr so aussehen:Und es würde wie folgt laufen:
Ok, jetzt erhalten wir unseren Graphitcontainer und den zugehörigen Nur-Daten-Container mit dem richtigen Benutzer / der richtigen Gruppe (beachten Sie, dass Sie den
some/graphite
Container auch für den Datencontainer wiederverwenden können, indem Sie den Eintrag / cmd beim Ausführen überschreiben, ihn aber als haben separate Bilder IMO ist klarer).Angenommen, Sie möchten etwas im Datenordner bearbeiten. Erstellen Sie einen neuen Container, um diese Aufgabe zu erledigen, anstatt das Mounten des Volumes an den Host zu binden und dort zu bearbeiten. Nennen wir es
some/graphitetools
. Erstellen wir auch den entsprechenden Benutzer / die entsprechende Gruppe, genau wie dassome/graphite
Bild.Sie können diesen DRY erstellen, indem Sie von
some/graphite
odersome/graphitedata
in der Docker-Datei erben oder anstatt ein neues Image zu erstellen, verwenden Sie einfach eines der vorhandenen (überschreiben Sie den Einstiegspunkt / cmd nach Bedarf).Jetzt rennst du einfach:
und dann
vi /data/graphite/whatever.txt
. Dies funktioniert perfekt, da alle Behälter denselben Graphitbenutzer mit passender UID / GID haben.Da Sie niemals
/data/graphite
vom Host aus mounten , ist es Ihnen egal, wie die Host-UID / GID der UID / GID zugeordnet wird, die in den Containerngraphite
und definiert istgraphitetools
. Diese Container können jetzt auf jedem Host bereitgestellt werden und funktionieren weiterhin einwandfrei.Das Schöne daran ist, dass
graphitetools
es alle möglichen nützlichen Dienstprogramme und Skripte geben kann, die Sie jetzt auch portabel bereitstellen können.UPDATE 2 : Nachdem ich diese Antwort geschrieben hatte, beschloss ich, einen vollständigeren Blog-Beitrag über diesen Ansatz zu schreiben . Ich hoffe, es hilft.
UPDATE 3 : Ich habe diese Antwort korrigiert und weitere Details hinzugefügt. Zuvor enthielt es einige falsche Annahmen zu Besitz und Dauerwellen. Der Besitz wird normalerweise zum Zeitpunkt der Datenträgererstellung zugewiesen, dh im Datencontainer, da zu diesem Zeitpunkt der Datenträger erstellt wird. Siehe diesen Blog . Dies ist jedoch keine Voraussetzung - Sie können den Datencontainer einfach als "Referenz / Handle" verwenden und den Besitz / die Dauerwellen in einem anderen Container über chown in einem Einstiegspunkt festlegen, der mit gosu endet, um den Befehl als richtigen Benutzer auszuführen. Wenn sich jemand für diesen Ansatz interessiert, kommentieren Sie ihn bitte und ich kann mit diesem Ansatz Links zu einem Beispiel bereitstellen.
quelle
/data/newcontainer
? Ichdocker
gehe davon aus, dass Sie als Root ausgeführt werden (ist dies nicht möglich?). Gibt es auch Unterschiede bei diesen Berechtigungen, wenn die Daten direkt im Hauptcontainer oder über einen Nur-Daten-Container bereitgestellt werden ?/var/lib/docker
irgendwo sein, aber immer noch ein großer SchmerzEine sehr elegante Lösung ist auf dem offiziellen Redis-Bild und allgemein auf allen offiziellen Bildern zu sehen.
Schritt für Schritt beschrieben:
Wie in Dockerfile-Kommentaren zu sehen:
gosu ist eine Alternative zu
su
/sudo
für ein einfaches Herunterfahren vom Root-Benutzer. (Redis wird immer mitredis
Benutzer ausgeführt)/data
Volume und legen Sie es als Arbeitsverzeichnis festDurch Konfigurieren des / data-Volumes mit dem
VOLUME /data
Befehl haben wir jetzt ein separates Volume, das entweder Docker-Volume sein oder an ein Host-Verzeichnis gebunden werden kann.Wenn Sie es als workdir (
WORKDIR /data
) konfigurieren, wird es zum Standardverzeichnis, in dem Befehle ausgeführt werden.Dies bedeutet, dass alle Containerausführungen über das Docker-Entrypoint-Skript ausgeführt werden. Standardmäßig lautet der auszuführende Befehl redis-server.
docker-entrypoint
ist ein Skript, das eine einfache Funktion ausführt: Ändern Sie den Besitz des aktuellen Verzeichnisses (/ data) und wechseln Sie vonroot
zuredis
Benutzer, um es auszuführenredis-server
. (Wenn der ausgeführte Befehl kein Redis-Server ist, wird der Befehl direkt ausgeführt.)Dies hat folgenden Effekt
Wenn das Verzeichnis / data an den Host gebunden ist, bereitet der Docker-Einstiegspunkt die Benutzerberechtigungen vor, bevor der Redis-Server unter
redis
Benutzer ausgeführt wird.Dies gibt Ihnen die Gewissheit, dass es keine Einrichtung gibt, um den Container unter einer beliebigen Volume-Konfiguration auszuführen.
Wenn Sie das Volume für verschiedene Bilder freigeben müssen, müssen Sie natürlich sicherstellen, dass sie dieselbe Benutzer- / Gruppen-ID verwenden. Andernfalls übernimmt der neueste Container die Benutzerberechtigungen des vorherigen.
quelle
chown
es imENTRYPOINT
Skript?Dies ist wohl nicht der beste Weg für die meisten Umstände, aber es wurde noch nicht erwähnt, vielleicht hilft es jemandem.
Binden Sie das Mount-Host-Volume
Host folder FOOBAR is mounted in container /volume/FOOBAR
Ändern Sie das Startskript Ihres Containers, um die GID des Volumes zu finden, an dem Sie interessiert sind
$ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)
Stellen Sie sicher, dass Ihr Benutzer zu einer Gruppe mit dieser GID gehört (möglicherweise müssen Sie eine neue Gruppe erstellen). In diesem Beispiel werde ich so tun, als würde meine Software als
nobody
Benutzer ausgeführt, wenn ich mich im Container befinde. Daher möchte ich sicherstellen, dass sienobody
zu einer Gruppe mit einer Gruppen-ID von gehörtTARGET_GID
Ich mag dies, weil ich Gruppenberechtigungen auf meinen Host-Volumes leicht ändern kann und weiß, dass diese aktualisierten Berechtigungen im Docker-Container gelten. Dies geschieht ohne Erlaubnis oder Eigentumsänderungen an meinen Host-Ordnern / -Dateien, was mich glücklich macht.
Ich mag das nicht, weil davon ausgegangen wird, dass es keine Gefahr gibt, sich einer beliebigen Gruppe innerhalb des Containers hinzuzufügen, die zufällig eine gewünschte GID verwendet. Es kann nicht mit einer
USER
Klausel in einer Docker-Datei verwendet werden (es sei denn, dieser Benutzer verfügt vermutlich über Root-Rechte). Außerdem schreit es Hack Job ;-)Wenn Sie Hardcore sein möchten, können Sie dies natürlich auf viele Arten erweitern - z. B. nach allen Gruppen in Subdateien, mehreren Volumes usw. suchen.
quelle
$TARGET_GID
wäre die Verwendunggrep ':$TARGET_GID:'
, andernfalls, wenn der Container zB gid 10001 hat und Ihr Host 1000 ist, wird diese Prüfung bestanden, sollte es aber nicht.Ok, dies wird jetzt in der Docker-Ausgabe Nr. 7198 verfolgt
Im Moment beschäftige ich mich mit Ihrer zweiten Option:
Dockerfile
CLI
UPDATE Ich bin derzeit eher geneigt, Hamy zu antworten
quelle
id -u <username>
,id -g <username>
,id -G <username>
die Benutzer - ID und Gruppen - ID eines bestimmten Benutzers , anstatt zu bekommenVersuchen Sie, Dockerfile einen Befehl hinzuzufügen
Credits gehen an https://github.com/denderello/symfony-docker-example/issues/2#issuecomment-94387272
quelle
Genau wie Sie habe ich nach einer Möglichkeit gesucht, Benutzer / Gruppen vom Host auf Docker-Container abzubilden. Dies ist der kürzeste Weg, den ich bisher gefunden habe:
Dies ist ein Auszug aus meiner docker-compose.yml.
Die Idee ist, Benutzer- / Gruppenlisten (im schreibgeschützten Modus) vom Host in den Container zu mounten, damit der Container nach dem Start des UID-> Benutzernamens (sowie für Gruppen) mit dem Host übereinstimmt. Jetzt können Sie Benutzer- / Gruppeneinstellungen für Ihren Dienst im Container so konfigurieren, als ob er auf Ihrem Hostsystem funktioniert.
Wenn Sie Ihren Container auf einen anderen Host verschieben möchten, müssen Sie nur den Benutzernamen in der Dienstkonfigurationsdatei in den Namen ändern, den Sie auf diesem Host haben.
quelle
-u $( id -u $USER ):$( id -g $USER )
und sich nicht mehr um den Benutzernamen kümmern müssen. Dies funktioniert gut für lokale Entwicklungsumgebungen, in denen Sie Dateien (z. B. Binärdateien) generieren möchten, auf die Sie standardmäßig Lese- / Schreibzugriff haben.Hier ist ein Ansatz, bei dem immer noch ein Nur-Daten-Container verwendet wird, der jedoch nicht mit dem Anwendungscontainer synchronisiert werden muss (in Bezug auf dieselbe UID / GID).
Vermutlich möchten Sie eine App im Container als Nicht-Root-USER ohne Login-Shell ausführen.
In der Docker-Datei:
Dann in entrypoint.sh:
quelle
Versuchen Sie für sichere und geänderte Root für Docker-Container einen Docker-Host verwenden
--uidmap
und--private-uids
Optionenhttps://github.com/docker/docker/pull/4572#issuecomment-38400893
Aus
--cap-drop
Sicherheitsgründen können Sie auch mehrere Funktionen ( ) im Docker-Container entfernenhttp://opensource.com/business/14/9/security-for-docker
UPDATE- Unterstützung sollte kommen
docker > 1.7.0
UPDATE- Version
1.10.0
(2016-02-04)--userns-remap
Flag hinzufügen https://github.com/docker/docker/blob/master/CHANGELOG.md#security-2quelle
--uidmap
noch der--private-uids
Optionen. Sieht so aus, als hätte die PR es nicht geschafft und wurde nicht zusammengeführt."We apparently do have so some of conflicting designs between libnetwork and user namespaces ... and something we'd like to get in for 1.8.0. So don't think we're dropping this, we're definitely going to take a break after all these, and see how we need to reconsider the current design and integration of libnetwork to make this possible. Thanks!"
github.com/docker/docker/pull/12648 Ich denke, wir sollten die nächste stabile Version abwarten.Mein Ansatz besteht darin, die aktuelle UID / GID zu erkennen, dann einen solchen Benutzer / eine solche Gruppe im Container zu erstellen und das Skript unter ihm auszuführen. Infolgedessen stimmen alle von ihm erstellten Dateien mit dem Benutzer auf dem Host (dem Skript) überein:
quelle
Basisbild
Verwenden Sie dieses Bild: https://hub.docker.com/r/reduardo7/docker-host-user
oder
Wichtig: Dadurch wird die Portabilität von Containern zwischen Hosts zerstört .
1)
init.sh
2)
Dockerfile
3) run.sh.
4) Bauen mit
docker
4) Lauf!
quelle
In meinem speziellen Fall habe ich versucht, mein Knotenpaket mit dem Knoten-Docker-Image zu erstellen, damit ich npm nicht auf dem Bereitstellungsserver installieren muss. Es funktionierte gut, bis ich außerhalb des Containers und auf dem Host-Computer versuchte, eine Datei in das Verzeichnis node_modules zu verschieben, das das Docker-Image des Knotens erstellt hatte, für das mir die Berechtigungen verweigert wurden, weil es Root gehörte. Ich erkannte, dass ich dies umgehen konnte, indem ich das Verzeichnis aus dem Container auf den Host-Computer kopierte. Über Docker-Dokumente ...
Dies ist der Bash-Code, mit dem ich den Besitz des Verzeichnisses geändert habe, das von und innerhalb des Docker-Containers erstellt wurde.
Bei Bedarf können Sie das Verzeichnis mit einem zweiten Docker-Container entfernen.
quelle
Versuchen Sie den folgenden Befehl, um den Ordner zwischen Docker-Host und Docker-Container freizugeben
Das Flag -v stellt das aktuelle Arbeitsverzeichnis im Container bereit. Wenn das Hostverzeichnis eines bindgebundenen Volumes nicht vorhanden ist, erstellt Docker dieses Verzeichnis automatisch auf dem Host für Sie.
Es gibt jedoch zwei Probleme, die wir hier haben:
Lösung:
Container: Erstellen Sie einen Benutzer, sagen Sie 'testuser'. Standardmäßig beginnt die Benutzer-ID bei 1000,
Host: Erstellen Sie eine Gruppe mit dem Namen 'testgroup' mit der Gruppen-ID 1000 und teilen Sie das Verzeichnis der neuen Gruppe (testgroup) mit
quelle
Wenn Sie Docker Compose verwenden, starten Sie den Container im vorherigen Modus:
quelle