Docker - un moyen de donner accès à un périphérique USB ou série hôte?


Réponses:


194

Il existe plusieurs options. Vous pouvez utiliser l' --deviceindicateur que l'utilisation peut utiliser pour accéder aux périphériques USB sans --privilegedmode:

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

Sinon, en supposant que votre périphérique USB est disponible avec des pilotes fonctionnant, etc. sur l'hôte dans /dev/bus/usb, vous pouvez le monter dans le conteneur en utilisant le mode privilégié et l' option volumes . Par exemple:

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

Notez que comme son nom l'indique, --privilegedn'est pas sûr et doit être manipulé avec précaution.


4
Vous n'avez pas besoin de -v - privilégié signifie déjà l'accès à tous les appareils
Art

12
Existe-t-il un mécanisme comme celui-ci pour le client Docker Windows?
Pascal

En utilisant cette solution, je ne vois pas les périphériques d'un conteneur docker ... Voici les détails de stackoverflow.com/questions/37213812 de mon problème. J'apprécie toute aide! Merci.
kashesandr

1
Ne fonctionne toujours pas si le périphérique USB est connecté après que Docker est déjà en cours d'exécution.
Franklin Dattein

Je veux dire, il ne mappe pas le périphérique sous / tty / USBX bien que lsusb puisse le lister.
Franklin Dattein

78

Avec les versions actuelles de Docker, vous pouvez utiliser l' --deviceindicateur pour réaliser ce que vous voulez, sans avoir besoin de donner accès à tous les périphériques USB.

Par exemple, si vous souhaitez rendre /dev/ttyUSB0accessible uniquement dans votre conteneur Docker, vous pouvez faire quelque chose comme:

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

3
notez simplement que l'appareil ne peut pas être un lien symbolique pour le moment. github.com/docker/docker/issues/13840
wligtenberg

6
à l'aide de l' --deviceindicateur, comment déterminer quel /dev/<device>est le périphérique Android associé sur la machine hôte, en particulier lors de l'utilisation du Docker Quickstart Terminal (VirtualBox Host) pour Windows ou Mac?
DanCat

1
Cela fonctionne bien si le nom de votre appareil ne change jamais. Mais si vous utilisez quelque chose de dynamique qui utilise des périphériques dans / dev / bus / usb, cela ne fonctionnera pas car le nom du périphérique change lorsque vous le branchez et le débranchez. Vous aurez besoin de la solution -v (volumes) ci-dessus à la place.
Brad Grissom

1
Les règles udev @DanCat peuvent garantir que votre appareil se monte sur un chemin statique
C. Reed

1
Pourquoi quelqu'un serait-il intéressé à avoir accès à un seul périphérique USB? Les appareils USB sont destinés à être connectés et déconnectés et cela doit être fait pendant l'exécution des applications. L'USB n'est pas SATA ou quelque chose du genre, vous ne pouvez pas vous attendre à ce que quelque chose soit toujours là ... Et je ne pense pas que les gens lancent simplement des applications via docker pour des exécutions uniques et les quittent dès que les périphériques USB sont déconnectés, non? J'imagine plus comme des applications de type service, pas des jars à exécution unique ... Mais merci, cela pourrait en aider certains pour lesquels ce scénario très limité conviendrait
Arturas M

17

--devicefonctionne jusqu'à ce que votre périphérique USB soit débranché / rebranché, puis il cesse de fonctionner. Vous devez utiliser des périphériques de groupe de contrôle pour le contourner.
Vous pouvez simplement l'utiliser, -v /dev:/devmais ce n'est pas sûr car il mappe tous les périphériques de votre hôte dans le conteneur, y compris les périphériques de disque brut, etc. Fondamentalement, cela permet au conteneur de gagner la racine sur l'hôte, ce qui n'est généralement pas ce que vous voulez.
L'utilisation de l'approche cgroups est meilleure à cet égard et fonctionne sur les périphériques qui sont ajoutés après le démarrage du conteneur.

Voir les détails ici: Accéder aux périphériques USB dans Docker sans utiliser --privileged

C'est un peu difficile à coller, mais en un mot, vous devez obtenir le numéro majeur de votre périphérique de personnage et l'envoyer au groupe de contrôle:

189 est le nombre majeur de / dev / ttyUSB *, que vous pouvez obtenir avec «ls -l». Cela peut être différent sur votre système que sur le mien:

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

Ensuite, démarrez votre conteneur comme ceci:

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

sans cela, tout périphérique nouvellement branché ou redémarré après le démarrage du conteneur recevra un nouvel ID de bus et ne sera pas autorisé à accéder au conteneur.


7
Aux personnes qui ont fait cela, aidez-nous et dites ce que vous aimeriez améliorer. J'ai écrit cette page pour aider les autres qui ont rencontré le problème que nous avons rencontré. Je serai un peu honnête en disant que je ne suis pas en train d'essayer de partager et d'aider les gens sur stackoverflow aussi: - /
Marc Merlin

Si vous lisez ma réponse, vous verrez que l'ajout du volume «-v / dev: / dev» donnera accès aux périphériques branchés dynamiquement.
rrpilot

5
rrpilot: -v / dev: / dev vous donne tout / dev, y compris / dev / sda et d'autres choses que vous ne voulez vraiment pas exposer à un utilisateur root dans le conteneur. En d'autres termes, votre solution fonctionne, mais elle n'est pas sûre. Le mien contourne ce problème. Je vais modifier ma réponse pour le souligner.
Marc Merlin

1
La réponse pourrait être améliorée en montrant comment obtenir le nombre majeur et en clarifiant celui qui 189doit être remplacé. Une description de ce qu'il faut envoyer devices.allowpeut être trouvée ici: kernel.org/doc/Documentation/cgroup-v1/devices.txt
Craig Younkins

1
Il existe une nouvelle fonctionnalité de Docker qui rend cela légèrement plus simple: "--device-cgroup-rule" ( docs.docker.com/engine/reference/commandline/create/… )
tianon

14

Je voulais étendre les réponses déjà données pour inclure la prise en charge des appareils connectés dynamiquement qui ne sont pas capturés avec /dev/bus/usbet comment faire fonctionner cela lors de l'utilisation d'un hôte Windows avec la VM boot2docker.

Si vous travaillez avec Windows, vous devrez ajouter des règles USB pour les périphériques auxquels vous souhaitez que Docker accède dans le gestionnaire VirtualBox. Pour ce faire, vous pouvez arrêter la VM en exécutant:

host:~$ docker-machine stop default

Ouvrez le gestionnaire VirtualBox et ajoutez la prise en charge USB avec des filtres si nécessaire.

Démarrez la VM boot2docker:

host:~$ docker-machine start default

Étant donné que les périphériques USB sont connectés à la machine virtuelle boot2docker, les commandes doivent être exécutées à partir de cette machine. Ouvrez un terminal avec la machine virtuelle et exécutez la commande docker run:

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

Notez que lorsque la commande est exécutée de cette manière, seuls les périphériques USB précédemment connectés seront capturés. L'indicateur de volumes n'est requis que si vous souhaitez que cela fonctionne avec les périphériques connectés après le démarrage du conteneur. Dans ce cas, vous pouvez utiliser:

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

Remarque, j'ai dû utiliser /devau lieu de /dev/bus/usbdans certains cas pour capturer un appareil comme /dev/sg2. Je ne peux que supposer qu'il en serait de même pour des appareils tels que /dev/ttyACM0ou /dev/ttyUSB0.

Les commandes d'exécution du docker fonctionneront également avec un hôte Linux.


Bon point de montage / dev: / dev à la place. Cela donne plus de flexibilité en termes de capture d'autres appareils et aide également à l'élément dynamique.
kotakotakota

et compromet également la sécurité et l'isolation de votre machine hôte.
Exadra37

@ Exadra37 Oui ... et si cela compte dans votre application, vous ne devriez pas l'utiliser. Cependant, il est important de noter que certaines applications ne vous intéressent pas et n'utilisent pas docker pour son isolation. Dans mon cas spécifique, vous pouvez exécuter une application Linux packagée sous Windows.
rrpilot

3

Une autre option consiste à ajuster udev, qui contrôle la façon dont les périphériques sont montés et avec quels privilèges. Utile pour autoriser l'accès non root aux périphériques série. Si vous avez des périphériques connectés en permanence, l' --deviceoption est la meilleure solution. Si vous avez des appareils éphémères, voici ce que j'utilise:

1. Définissez la règle udev

Par défaut, les périphériques série sont montés de manière à ce que seuls les utilisateurs root puissent accéder au périphérique. Nous devons ajouter une règle udev pour les rendre lisibles par des utilisateurs non root.

Créez un fichier nommé /etc/udev/rules.d/99-serial.rules. Ajoutez la ligne suivante à ce fichier:

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

MODE = "0666" donnera à tous les utilisateurs des autorisations de lecture / écriture (mais pas d'exécution) sur vos périphériques ttyUSB. Il s'agit de l'option la plus permissive et vous souhaiterez peut-être la restreindre davantage en fonction de vos exigences en matière de sécurité. Vous pouvez lire sur udev pour en savoir plus sur le contrôle de ce qui se passe lorsqu'un périphérique est connecté à une passerelle Linux.

2. Montez dans le dossier / dev de l'hôte au conteneur

Les appareils série sont souvent éphémères (peuvent être branchés et débranchés à tout moment). Pour cette raison, nous ne pouvons pas monter dans le périphérique direct ou même dans le dossier / dev / serial, car ceux-ci peuvent disparaître lorsque les choses sont débranchées. Même si vous les rebranchez et que l'appareil réapparaît, il s'agit techniquement d'un fichier différent de celui qui a été monté, donc Docker ne le verra pas. Pour cette raison, nous montons tout le dossier / dev de l'hôte vers le conteneur. Vous pouvez le faire en ajoutant la commande de volume suivante à votre commande d'exécution Docker:

-v /dev:/dev

Si votre appareil est connecté de manière permanente, utiliser l'option --device ou un montage de volume plus spécifique est probablement une meilleure option du point de vue de la sécurité.

3. Exécutez le conteneur en mode privilégié

Si vous n'avez pas utilisé l'option --device et monté dans tout le dossier / dev, vous devrez exécuter le conteneur en mode privilégié (je vais vérifier les éléments de groupe de contrôle mentionnés ci-dessus pour voir si cela peut être supprimé ). Vous pouvez le faire en ajoutant ce qui suit à votre commande d'exécution Docker:

--privileged

4. Accédez au périphérique à partir du dossier / dev / serial / by-id

Si votre appareil peut être branché et débranché, Linux ne garantit pas qu'il sera toujours monté au même emplacement ttyUSBxxx (surtout si vous avez plusieurs appareils). Heureusement, Linux créera automatiquement un lien symbolique vers le périphérique dans le dossier / dev / serial / by-id. Le fichier de ce dossier sera toujours nommé de la même manière.

Voici le résumé rapide, j'ai un article de blog qui va dans plus de détails.


2

Il est difficile pour nous de lier un périphérique USB spécifique à un conteneur Docker qui est également spécifique. Comme vous pouvez le voir, la méthode recommandée pour y parvenir est:

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

Il liera tous les appareils à ce conteneur. C'est dangereux. Tous les conteneurs ont été autorisés à tous les exploiter.

Une autre méthode consiste à lier les périphériques par devpath. Cela peut ressembler à:

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

ou --device(mieux, non privileged):

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

Beaucoup plus sécuritaire. Mais en fait, il est difficile de savoir quel est le chemin de développement d'un périphérique spécifique.

J'ai écrit ce repo pour résoudre ce problème.

https://github.com/williamfzc/usb2container

Après avoir déployé ce serveur, vous pouvez facilement obtenir toutes les informations des appareils connectés via une requête HTTP:

curl 127.0.0.1:9410/api/device

et obtenir:

{
    "/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"
    },
    ...
}

et liez-les à vos conteneurs. Par exemple, vous pouvez voir que le DEVNAME de cet appareil est /dev/bus/usb/001/120:

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

Cela aidera peut-être.


0

Avec les dernières versions de docker, cela suffit:

docker run -ti --privileged ubuntu bash

Il donnera accès à toutes les ressources système (dans / dev par exemple)


2
privilégié est une option terrible à utiliser pour la sécurité, même si oui, cela fonctionne.
Marc Merlin

2
Si elle est utilisée pour programmer des trucs comme des trucs liés à Arduino, cette solution est bonne
Jose Cabrera Zuniga

0

Ajout aux réponses ci-dessus, pour ceux qui veulent un moyen rapide d'utiliser un périphérique USB externe (disque dur, lecteur flash) fonctionnant à l'intérieur du docker et n'utilisant pas le mode privilégié:

Recherchez le chemin de développement vers votre appareil sur l'hôte:

sudo fdisk -l

Vous pouvez reconnaître votre disque par sa capacité assez facilement dans la liste. Copiez ce chemin (pour l'exemple suivant /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

Montez ce devpath (préférable à /media):

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

Vous pouvez ensuite utiliser ceci comme paramètre pour docker runaimer:

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

ou en docker composez sous volumes:

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

Et maintenant, lorsque vous exécutez et entrez dans votre conteneur, vous devriez pouvoir accéder au lecteur à l'intérieur du conteneur à /media/<mount folder name>

AVERTISSEMENT:

  1. Cela ne fonctionnera probablement pas pour les périphériques série tels que les webcams, etc. Je n'ai testé cela que pour les lecteurs de stockage USB.
  2. Si vous avez besoin de reconnecter et déconnecter des périphériques régulièrement, cette méthode serait ennuyeuse et ne fonctionnerait pas à moins que vous ne réinitialisiez le chemin de montage et redémarriez le conteneur.
  3. J'ai utilisé docker 17.06 + comme prescrit dans la documentation

0

Si vous souhaitez accéder dynamiquement aux périphériques USB qui peuvent être branchés alors que le conteneur Docker est déjà en cours d'exécution, par exemple accéder à une webcam USB juste connectée à / dev / video0, vous pouvez ajouter une règle de groupe de contrôle lors du démarrage du conteneur. Cette option ne nécessite pas de conteneur --privileged et autorise uniquement l'accès à des types de matériel spécifiques.

Étape 1

Vérifiez le numéro principal de l'appareil du type d'appareil que vous souhaitez ajouter. Vous pouvez le rechercher dans la documentation du noyau Linux . Ou vous pouvez le vérifier pour votre appareil. Par exemple, pour vérifier le numéro majeur du périphérique pour une webcam connectée à / dev / video0, vous pouvez faire un ls -la /dev/video0. Cela donne quelque chose comme:

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

Où le premier nombre (81) est le numéro majeur de l'appareil. Quelques numéros majeurs de périphériques courants:

  • 81: webcams USB
  • 188: convertisseurs USB vers série

Étape 2

Ajoutez des règles lorsque vous démarrez le conteneur Docker:

  • Ajoutez une --device-cgroup-rule='c major_number:* rmw'règle pour chaque type d'appareil auquel vous souhaitez accéder
  • Ajoutez un accès aux informations udev afin que les conteneurs Docker puissent obtenir plus d'informations sur vos appareils USB avec -v /run/udev:/run/udev:ro
  • Mappez le volume / dev à votre conteneur Docker avec -v /dev:/dev

Emballer

Donc, pour ajouter toutes les webcams USB et les périphériques serial2usb à votre conteneur docker, procédez comme suit:

docker run -it -v /dev:/dev --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 81:* rmw' ubuntu bash
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.