Als ich das letzte Mal nachgesehen habe, hatte Docker keine Möglichkeit, dem Container Zugriff auf den seriellen oder USB-Port des Hosts zu gewähren . Gibt es einen Trick, der das erlaubt?
Als ich das letzte Mal nachgesehen habe, hatte Docker keine Möglichkeit, dem Container Zugriff auf den seriellen oder USB-Port des Hosts zu gewähren . Gibt es einen Trick, der das erlaubt?
Antworten:
Es gibt mehrere Möglichkeiten. Sie können das --device
Flag verwenden, mit dem auf USB-Geräte ohne --privileged
Modus 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, --privileged
ist unsicher und sollte mit Vorsicht behandelt werden.
Mit aktuellen Versionen von Docker können Sie das --device
Flag verwenden, um das zu erreichen, was Sie möchten, ohne auf alle USB-Geräte zugreifen zu müssen.
Wenn Sie beispielsweise nur /dev/ttyUSB0
in Ihrem Docker-Container zugänglich machen möchten, können Sie Folgendes tun:
docker run -t -i --device=/dev/ttyUSB0 ubuntu bash
--device
Wie 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?
--device
funktioniert 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:/dev
aber 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.
189
diese ersetzt werden muss. Eine Beschreibung dessen, was gesendet werdendevices.allow
soll, finden Sie hier: kernel.org/doc/Documentation/cgroup-v1/devices.txt
Ich wollte die bereits gegebenen Antworten um die Unterstützung für dynamisch verbundene Geräte erweitern, mit denen nicht erfasst wurde, /dev/bus/usb
und 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 /dev
anstelle von /dev/bus/usb
in 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/ttyACM0
oder gilt /dev/ttyUSB0
.
Die Docker-Ausführungsbefehle funktionieren auch mit einem Linux-Host.
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 --device
Option der beste Weg. Wenn Sie kurzlebige Geräte haben, habe ich Folgendes verwendet:
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.
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.
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
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.
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.
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).
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 run
mö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:
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.
Ü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:
Fügen Sie Regeln hinzu, wenn Sie den Docker-Container starten:
--device-cgroup-rule='c major_number:* rmw'
Regel für jeden Gerätetyp hinzu, auf den Sie zugreifen möchten-v /run/udev:/run/udev:ro
-v /dev:/dev
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