Docker - eine Möglichkeit, Zugriff auf ein Host-USB- oder serielles Gerät zu gewähren?


Antworten:


194

Es gibt mehrere Möglichkeiten. Sie können das --deviceFlag verwenden, mit dem auf USB-Geräte ohne --privilegedModus zugegriffen werden kann:

docker run -t -i --device=/dev/ttyUSB0 ubuntu bash

Unter der Annahme, dass Ihr USB-Gerät mit funktionierenden Treibern usw. auf dem Host verfügbar ist /dev/bus/usb, können Sie dies alternativ im privilegierten Modus und mit der Volume-Option im Container bereitstellen . Beispielsweise:

docker run -t -i --privileged -v /dev/bus/usb:/dev/bus/usb ubuntu bash

Beachten Sie, dass , wie der Name schon sagt, --privilegedist unsicher und sollte mit Vorsicht behandelt werden.


4
Benötigen Sie nicht -v - privilegiert bedeutet bereits Zugriff auf alle Geräte
Art

12
Gibt es einen solchen Mechanismus für den Windows Docker-Client?
Pascal

Mit dieser Lösung sehe ich keine Geräte aus einem Docker-Container ... Hier sind Details zu stackoverflow.com/questions/37213812 meines Problems. Schätzen Sie jede Hilfe! Vielen Dank.
Kashsandr

1
Funktioniert immer noch nicht, wenn das USB-Gerät angeschlossen ist, nachdem Docker bereits ausgeführt wurde.
Franklin Dattein

Ich meine, es ordnet das Gerät nicht unter / tty / USBX zu, obwohl lsusb es auflisten kann.
Franklin Dattein

78

Mit aktuellen Versionen von Docker können Sie das --deviceFlag verwenden, um das zu erreichen, was Sie möchten, ohne auf alle USB-Geräte zugreifen zu müssen.

Wenn Sie beispielsweise nur /dev/ttyUSB0in Ihrem Docker-Container zugänglich machen möchten, können Sie Folgendes tun:

docker run -t -i --device=/dev/ttyUSB0 ubuntu bash

3
Beachten Sie nur, dass das Gerät derzeit kein Symlink sein kann. github.com/docker/docker/issues/13840
wligtenberg

6
--deviceWie kann ich anhand des Flags feststellen, welches /dev/<device>Android-Gerät auf dem Host-Computer zugeordnet ist, insbesondere wenn das Docker-Schnellstart-Terminal (VirtualBox-Host) für Windows oder Mac verwendet wird?
DanCat

1
Dies funktioniert gut, wenn sich Ihr Gerätename nie ändert. Wenn Sie jedoch etwas Dynamisches verwenden, das Geräte in / dev / bus / usb verwendet, funktioniert dies nicht, da sich der Gerätename beim Ein- und Ausstecken ändert. Sie benötigen stattdessen die obige -v (Volumes) -Lösung.
Brad Grissom

1
@ DanCat udev-Regeln können sicherstellen, dass Ihr Gerät auf einem statischen Pfad bereitgestellt wird
C. Reed

1
Warum sollte jemand daran interessiert sein, auf nur ein USB-Gerät zuzugreifen? USB-Geräte sollen verbunden und getrennt werden. Dies muss während der Laufzeit der Apps erfolgen. USB ist nicht SATA oder so, man kann nicht erwarten, dass immer etwas da ist ... Und ich glaube nicht, dass die Leute Apps einfach über Docker für einzelne Läufe starten und beenden, sobald die USB-Geräte getrennt werden, oder? Ich würde mir eher Service-Apps vorstellen, keine Single-Run-Jars ... Aber danke, das könnte einigen helfen, für die dieses sehr begrenzte Szenario
geeignet

17

--devicefunktioniert so lange, bis Ihr USB-Gerät vom Stromnetz getrennt / wieder angeschlossen wird und dann nicht mehr funktioniert. Sie müssen cgroup-Geräte verwenden .
Sie könnten es einfach verwenden, -v /dev:/devaber das ist unsicher, da es alle Geräte von Ihrem Host in den Container abbildet, einschließlich Raw-Disk-Geräte und so weiter. Grundsätzlich ermöglicht dies dem Container, auf dem Host root zu werden, was normalerweise nicht das ist, was Sie wollen.
Die Verwendung des cgroups-Ansatzes ist in dieser Hinsicht besser und funktioniert auf Geräten, die nach dem Start des Containers hinzugefügt werden.

Weitere Informationen finden Sie hier: Zugriff auf USB-Geräte in Docker ohne Verwendung von --privileged

Es ist etwas schwierig einzufügen, aber kurz gesagt, Sie müssen die Hauptnummer für Ihr Charaktergerät ermitteln und diese an cgroup senden:

189 ist die Hauptzahl von / dev / ttyUSB *, die Sie mit 'ls -l' erhalten können. Es kann auf Ihrem System anders sein als auf meinem:

root@server:~# echo 'c 189:* rwm' > /sys/fs/cgroup/devices/docker/$A*/devices.allow  
(A contains the docker containerID)

Dann starten Sie Ihren Container wie folgt:

docker run -v /dev/bus:/dev/bus:ro -v /dev/serial:/dev/serial:ro -i -t --entrypoint /bin/bash debian:amd64

Ohne dies zu tun, erhält jedes neu angeschlossene oder neu startende Gerät nach dem Start des Containers eine neue Bus-ID und erhält keinen Zugriff auf den Container.


7
Für Leute, die dies getan haben, helfen Sie bitte und sagen Sie, was Sie verbessern möchten. Ich habe diese Seite geschrieben, um anderen zu helfen, die auf das Problem gestoßen sind, das wir gemacht haben. Ich bin ein bisschen ehrlich, wenn ich sage, dass ich nicht mehr versuchen kann, etwas zu teilen und den Leuten beim Stackoverflow zu helfen: - /
Marc Merlin

Wenn Sie meine Antwort lesen, werden Sie sehen, dass das Hinzufügen des Volumes '-v / dev: / dev' den Zugriff auf dynamisch angeschlossene Geräte ermöglicht.
RPPILOT

5
rrpilot: -v / dev: / dev gibt Ihnen alles von / dev, einschließlich / dev / sda und anderen Dingen, die Sie einem Root-Benutzer im Container wirklich nicht zugänglich machen möchten. Mit anderen Worten, Ihre Lösung funktioniert, ist aber unsicher. Meins umgeht dieses Problem. Ich werde meine Antwort bearbeiten, um darauf hinzuweisen.
Marc Merlin

1
Die Antwort könnte besser gemacht werden, indem gezeigt wird, wie man die Hauptnummer erhält, und klargestellt wird, dass 189diese ersetzt werden muss. Eine Beschreibung dessen, was gesendet werdendevices.allow soll, finden Sie hier: kernel.org/doc/Documentation/cgroup-v1/devices.txt
Craig Younkins

1
Es gibt eine neue Funktion von Docker, die dies etwas einfacher macht: "--device-cgroup-rule" ( docs.docker.com/engine/reference/commandline/create/… )
Tianon

14

Ich wollte die bereits gegebenen Antworten um die Unterstützung für dynamisch verbundene Geräte erweitern, mit denen nicht erfasst wurde, /dev/bus/usbund wie dies funktioniert, wenn ein Windows-Host zusammen mit der boot2docker-VM verwendet wird.

Wenn Sie mit Windows arbeiten, müssen Sie alle USB-Regeln für Geräte hinzufügen, auf die Docker im VirtualBox-Manager zugreifen soll. Dazu können Sie die VM stoppen, indem Sie Folgendes ausführen:

host:~$ docker-machine stop default

Öffnen Sie den VirtualBox Manager und fügen Sie nach Bedarf USB-Unterstützung mit Filtern hinzu.

Starten Sie die boot2docker-VM:

host:~$ docker-machine start default

Da die USB-Geräte an die boot2docker-VM angeschlossen sind, müssen die Befehle von diesem Computer ausgeführt werden. Öffnen Sie ein Terminal mit der VM und führen Sie den Docker-Befehl run aus:

host:~$ docker-machine ssh
docker@default:~$ docker run -it --privileged ubuntu bash

Beachten Sie, dass bei einer solchen Ausführung des Befehls nur zuvor angeschlossene USB-Geräte erfasst werden. Das Volume-Flag ist nur erforderlich, wenn dies mit Geräten funktionieren soll, die nach dem Start des Containers verbunden sind. In diesem Fall können Sie Folgendes verwenden:

docker@default:~$ docker run -it --privileged -v /dev:/dev ubuntu bash

Beachten Sie, dass ich /devanstelle von /dev/bus/usbin einigen Fällen verwenden musste, um ein Gerät wie zu erfassen /dev/sg2. Ich kann nur davon ausgehen, dass dies auch für Geräte wie /dev/ttyACM0oder gilt /dev/ttyUSB0.

Die Docker-Ausführungsbefehle funktionieren auch mit einem Linux-Host.


Guter Punkt beim Mounten von / dev: / dev. Dies bietet mehr Flexibilität bei der Erfassung anderer Geräte und hilft auch beim dynamischen Element.
Kotakotakota

Außerdem wird die Sicherheit und Isolation Ihres Host-Computers beeinträchtigt.
Exadra37

@ Exadra37 Es tut ... und wenn das in Ihrer Anwendung wichtig ist, sollten Sie dies nicht verwenden. Es ist jedoch wichtig zu beachten, dass es einige Anwendungen gibt, bei denen Sie sich nicht darum kümmern und Docker nicht für die Isolierung verwenden. In meinem speziellen Fall können Sie eine gepackte Linux-Anwendung unter Windows ausführen.
rrpilot

3

Eine weitere Option ist die Anpassung von udev, mit der gesteuert wird, wie Geräte mit welchen Berechtigungen bereitgestellt werden. Nützlich, um den Zugriff auf serielle Geräte ohne Rootberechtigung zu ermöglichen. Wenn Sie fest angeschlossene Geräte haben, ist die --deviceOption der beste Weg. Wenn Sie kurzlebige Geräte haben, habe ich Folgendes verwendet:

1. Stellen Sie die udev-Regel ein

Standardmäßig werden serielle Geräte bereitgestellt, sodass nur Root-Benutzer auf das Gerät zugreifen können. Wir müssen eine udev-Regel hinzufügen, damit sie von Nicht-Root-Benutzern gelesen werden können.

Erstellen Sie eine Datei mit dem Namen /etc/udev/rules.d/99-serial.rules. Fügen Sie dieser Datei die folgende Zeile hinzu:

KERNEL=="ttyUSB[0-9]*",MODE="0666"

MODE = "0666" gibt allen Benutzern Lese- / Schreibberechtigungen (aber keine Ausführungsberechtigungen) für Ihre ttyUSB-Geräte. Dies ist die zulässigste Option, und Sie können dies abhängig von Ihren Sicherheitsanforderungen weiter einschränken. Sie können auf udev nachlesen, um mehr darüber zu erfahren, was passiert, wenn ein Gerät an ein Linux-Gateway angeschlossen wird.

2. Hängen Sie den Ordner / dev vom Host in den Container ein

Serielle Geräte sind häufig kurzlebig (können jederzeit ein- und ausgesteckt werden). Aus diesem Grund können wir nicht im direkten Gerät oder sogar im Ordner / dev / serial mounten, da diese verschwinden können, wenn die Stecker gezogen werden. Selbst wenn Sie sie wieder anschließen und das Gerät wieder angezeigt wird, handelt es sich technisch gesehen um eine andere Datei als die, in die sie eingebunden wurde, sodass Docker sie nicht sieht. Aus diesem Grund mounten wir den gesamten Ordner / dev vom Host in den Container. Sie können dies tun, indem Sie Ihrem Docker-Ausführungsbefehl den folgenden Volume-Befehl hinzufügen:

-v /dev:/dev

Wenn Ihr Gerät dauerhaft angeschlossen ist, ist die Verwendung der Option --device oder einer spezifischeren Volume-Bereitstellung aus Sicherheitsgründen wahrscheinlich die bessere Option.

3. Führen Sie den Container im privilegierten Modus aus

Wenn Sie die Option --device nicht verwendet und im gesamten Ordner / dev gemountet haben, müssen Sie den Container im privilegierten Modus ausführen (ich werde die oben genannten cgroup-Inhalte überprüfen, um festzustellen, ob diese entfernt werden können ). Sie können dies tun, indem Sie Ihrem Docker-Ausführungsbefehl Folgendes hinzufügen:

--privileged

4. Greifen Sie über den Ordner / dev / serial / by-id auf das Gerät zu

Wenn Ihr Gerät ein- und ausgesteckt werden kann, garantiert Linux nicht, dass es immer am selben ttyUSBxxx-Speicherort bereitgestellt wird (insbesondere, wenn Sie mehrere Geräte haben). Glücklicherweise stellt Linux automatisch einen Symlink zum Gerät im Ordner / dev / serial / by-id her. Die Datei in diesem Ordner hat immer den gleichen Namen.

Dies ist der kurze Überblick. Ich habe einen Blog-Artikel , der auf weitere Details eingeht.


2

Es fällt uns schwer, ein bestimmtes USB-Gerät an einen Docker-Container zu binden, der ebenfalls spezifisch ist. Wie Sie sehen können, ist der empfohlene Weg zu erreichen:

docker run -t -i --privileged -v /dev/bus/usb:/dev/bus/usb ubuntu bash

Es bindet alle Geräte an diesen Container. Es ist unsicher. Jeder Container durfte alle betreiben.

Ein anderer Weg ist das Binden von Geräten per Devpath. Es kann aussehen wie:

docker run -t -i --privileged -v /dev/bus/usb/001/002:/dev/bus/usb/001/002 ubuntu bash

oder --device(besser nein privileged):

docker run -t -i --device /dev/bus/usb/001/002 ubuntu bash

Viel sicherer. Aber eigentlich ist es schwer zu wissen, was der Devpath eines bestimmten Geräts ist.

Ich habe dieses Repo geschrieben, um dieses Problem zu lösen.

https://github.com/williamfzc/usb2container

Nach der Bereitstellung dieses Servers können Sie alle Informationen zu den verbundenen Geräten einfach per HTTP-Anforderung abrufen:

curl 127.0.0.1:9410/api/device

und bekomme:

{
    "/devices/pci0000:00/0000:00:14.0/usb1/1-13": {
        "ACTION": "add",
        "DEVPATH": "/devices/pci0000:00/0000:00:14.0/usb1/1-13",
        "DEVTYPE": "usb_device",
        "DRIVER": "usb",
        "ID_BUS": "usb",
        "ID_FOR_SEAT": "xxxxx",
        "ID_MODEL": "xxxxx",
        "ID_MODEL_ID": "xxxxx",
        "ID_PATH": "xxxxx",
        "ID_PATH_TAG": "xxxxx",
        "ID_REVISION": "xxxxx",
        "ID_SERIAL": "xxxxx",
        "ID_SERIAL_SHORT": "xxxxx",
        "ID_USB_INTERFACES": "xxxxx",
        "ID_VENDOR": "xxxxx",
        "ID_VENDOR_ENC": "xxxxx",
        "ID_VENDOR_FROM_DATABASE": "",
        "ID_VENDOR_ID": "xxxxx",
        "INTERFACE": "",
        "MAJOR": "189",
        "MINOR": "119",
        "MODALIAS": "",
        "PRODUCT": "xxxxx",
        "SEQNUM": "xxxxx",
        "SUBSYSTEM": "usb",
        "TAGS": "",
        "TYPE": "0/0/0",
        "USEC_INITIALIZED": "xxxxx",
        "adb_user": "",
        "_empty": false,
        "DEVNAME": "/dev/bus/usb/001/120",
        "BUSNUM": "001",
        "DEVNUM": "120",
        "ID_MODEL_ENC": "xxxxx"
    },
    ...
}

und binde sie an deine Behälter. Sie können beispielsweise sehen, dass der DEVNAME dieses Geräts wie folgt lautet /dev/bus/usb/001/120:

docker run -t -i --device /dev/bus/usb/001/120 ubuntu bash

Vielleicht hilft es.


0

Mit den neuesten Docker-Versionen reicht dies aus:

docker run -ti --privileged ubuntu bash

Es wird Zugriff auf alle Systemressourcen gewähren (z. B. in / dev).


2
Privilegiert ist eine schreckliche Option für die Sicherheit, obwohl es funktioniert.
Marc Merlin

2
Wenn diese Lösung zum Programmieren von Dingen wie Arduino verwendet wird, ist sie gut
Jose Cabrera Zuniga

0

Hinzu kommen die obigen Antworten für diejenigen, die schnell ein externes USB-Gerät (Festplatte, Flash-Laufwerk) verwenden möchten , das im Docker arbeitet und keinen privilegierten Modus verwendet:

Suchen Sie den Devpath zu Ihrem Gerät auf dem Host:

sudo fdisk -l

Sie können Ihr Laufwerk anhand der Kapazität leicht an der Liste erkennen. Kopieren Sie diesen Pfad (für das folgende Beispiel ist es /dev/sda2).

Disque /dev/sda2 : 554,5 Go, 57151488 octets, 111624 secteurs
Unités : secteur de 1 × 512 = 512 octets
Taille de secteur (logique / physique) : 512 octets / 512 octets
taille d'E/S (minimale / optimale) : 512 octets / 512 octets

Montiere diesen Devpath (vorzuziehen /media):

sudo mount <drive path> /media/<mount folder name>

Sie können dies dann entweder als Parameter verwenden, um Folgendes zu docker runmögen:

docker run -it -v /media/<mount folder name>:/media/<mount folder name>

oder im Docker unter Bänden komponieren:

services:
  whatevermyserviceis:
    volumes:
      - /media/<mount folder name>:/media/<mount folder name>

Und jetzt, wenn Sie Ihren Container ausführen und betreten, sollten Sie auf das Laufwerk im Container unter zugreifen können /media/<mount folder name>

HAFTUNGSAUSSCHLUSS:

  1. Dies funktioniert wahrscheinlich nicht für serielle Geräte wie Webcams usw. Ich habe dies nur für USB-Speicherlaufwerke getestet.
  2. Wenn Sie Geräte regelmäßig neu verbinden und trennen müssen, ist diese Methode ärgerlich und funktioniert auch nur, wenn Sie den Mount-Pfad zurücksetzen und den Container neu starten.
  3. Ich habe Docker 17.06 + verwendet, wie in den Dokumenten vorgeschrieben

0

Wenn Sie dynamisch auf USB-Geräte zugreifen möchten, die angeschlossen werden können, während der Docker-Container bereits ausgeführt wird, z. B. auf eine gerade angeschlossene USB-Webcam unter / dev / video0, können Sie beim Starten des Containers eine cgroup-Regel hinzufügen. Diese Option benötigt keinen --privilegierten Container und ermöglicht nur den Zugriff auf bestimmte Hardwaretypen.

Schritt 1

Überprüfen Sie die Hauptnummer des Geräts des Gerätetyps, den Sie hinzufügen möchten. Sie können es in der Linux-Kernel-Dokumentation nachschlagen . Oder Sie können es für Ihr Gerät überprüfen. Um beispielsweise die Hauptnummer des Geräts für eine mit / dev / video0 verbundene Webcam zu überprüfen, können Sie eine ls -la /dev/video0. Dies führt zu etwas wie:

crw-rw----+ 1 root video 81, 0 Jul  6 10:22 /dev/video0

Wobei die erste Nummer (81) die Hauptnummer des Geräts ist. Einige gängige Hauptnummern für Geräte:

  • 81: USB-Webcams
  • 188: USB zu seriellen Konvertern

Schritt 2

Fügen Sie Regeln hinzu, wenn Sie den Docker-Container starten:

  • Fügen Sie eine --device-cgroup-rule='c major_number:* rmw'Regel für jeden Gerätetyp hinzu, auf den Sie zugreifen möchten
  • Fügen Sie den Zugriff auf udev-Informationen hinzu, damit Docker-Container mit mehr Informationen zu Ihren USB-Geräten erhalten -v /run/udev:/run/udev:ro
  • Ordnen Sie das / dev-Volume Ihrem Docker-Container mit zu -v /dev:/dev

Einpacken

Gehen Sie folgendermaßen vor, um alle USB-Webcams und serial2usb-Geräte zu Ihrem Docker-Container hinzuzufügen:

docker run -it -v /dev:/dev --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 81:* rmw' ubuntu bash
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.