Docker: un modo per dare accesso a un dispositivo USB host o seriale?


Risposte:


194

Ci sono un paio di opzioni. Puoi usare il --deviceflag che puoi usare per accedere ai dispositivi USB senza --privilegedmodalità:

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

In alternativa, supponendo che il dispositivo USB sia disponibile con driver funzionanti, ecc. Sull'host /dev/bus/usb, è possibile montarlo nel contenitore utilizzando la modalità privilegiata e l' opzione dei volumi . Per esempio:

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

Si noti che, come suggerisce il nome, non --privilegedè sicuro e deve essere gestito con cura.


4
Non è necessario -v - privilegiato significa già accesso a tutti i dispositivi
Art

12
Esiste un meccanismo come questo per il client docker di Windows?
Pascal,

Utilizzando questa soluzione non vedo i dispositivi da un contenitore docker ... Ecco i dettagli stackoverflow.com/questions/37213812 del mio problema. Apprezzo qualsiasi aiuto! Grazie.
kashesandr,

1
Non funziona ancora se il dispositivo USB è collegato dopo che Docker è già in esecuzione.
Franklin Dattein,

Voglio dire, non mappa il dispositivo in / tty / USBX nonostante lsusb sia in grado di elencarlo.
Franklin Dattein,

78

Con le versioni attuali di Docker, è possibile utilizzare la --devicebandiera per ottenere ciò che si desidera, senza la necessità di consentire l'accesso a tutti i dispositivi USB.

Ad esempio, se si desidera rendere /dev/ttyUSB0accessibile solo all'interno del contenitore Docker, è possibile fare qualcosa del tipo:

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

3
nota che al momento il dispositivo non può essere un collegamento simbolico. github.com/docker/docker/issues/13840
wligtenberg

6
usando il --deviceflag, come posso determinare qual /dev/<device>è il dispositivo Android associato sul computer host, specialmente quando utilizzo Docker Quickstart Terminal (VirtualBox Host) per Windows o Mac?
DanCat,

1
Funziona bene se il nome del tuo dispositivo non cambia mai. Ma se stai usando qualcosa di dinamico che utilizza dispositivi all'interno di / dev / bus / usb, questo non funzionerà perché il nome del dispositivo cambia quando lo colleghi e lo scolleghi. Avrai invece bisogno della soluzione sopra -v (volumi).
Brad Grissom,

1
Le regole udev di @DanCat possono garantire che il tuo dispositivo si monti su un percorso statico
C. Reed,

1
Perché qualcuno dovrebbe essere interessato ad avere accesso a un solo dispositivo USB ?? I dispositivi USB devono essere collegati e disconnessi e devono essere eseguiti durante il runtime delle app. L'USB non è SATA o qualcosa del genere, non puoi aspettarti che qualcosa sia sempre lì ... E non credo che le persone avviino semplicemente le app tramite docker per le singole esecuzioni e le chiudano non appena i dispositivi USB vengono scollegati, giusto? Immagino di più come le app di tipo di servizio, non i vasetti a corsa singola ... Ma grazie, in effetti ciò potrebbe aiutare alcuni per i quali quello scenario molto limitato andrebbe bene
Arturas M

17

--devicefunziona fino a quando il dispositivo USB non viene scollegato / ricollegato e quindi smette di funzionare. Devi usare i dispositivi di cgroup. Ammetterlo .
Potresti semplicemente usare -v /dev:/devma non è sicuro in quanto mappa tutti i dispositivi dal tuo host al contenitore, inclusi i dispositivi a disco grezzo e così via. Fondamentalmente questo consente al container di ottenere il root sull'host, che di solito non è quello che vuoi.
L'uso dell'approccio cgroups è migliore sotto questo aspetto e funziona su dispositivi che vengono aggiunti dopo l'avvio del contenitore.

Vedi i dettagli qui: Accesso ai dispositivi USB in Docker senza usare --privileged

È un po 'difficile da incollare, ma in poche parole, devi ottenere il numero principale per il tuo dispositivo personaggio e inviarlo al cgroup:

189 è il numero maggiore di / dev / ttyUSB *, che puoi ottenere con 'ls -l'. Potrebbe essere diverso sul tuo sistema rispetto al mio:

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

Quindi avviare il contenitore in questo modo:

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

senza fare ciò, qualsiasi dispositivo appena collegato o riavviato dopo l'avvio del contenitore, otterrà un nuovo ID bus e non gli sarà consentito l'accesso nel contenitore.


7
Alle persone che hanno fatto questo, aiutatemi e dite cosa vorreste migliorare. Ho scritto questa pagina per aiutare gli altri a colpire il problema che abbiamo fatto. Sarò un po 'onesto nel dire che sono stato disattivato dal tentativo di condividere e aiutare anche le persone su StackOverflow: - /
Marc Merlin

Se leggi la mia risposta, vedrai che l'aggiunta del volume '-v / dev: / dev' darà accesso ai dispositivi collegati dinamicamente.
rrpilot,

5
rrpilot: -v / dev: / dev ti dà tutto / dev, incluso / dev / sda e altre cose che non vuoi davvero esporre a un utente root nel contenitore. In altre parole, la tua soluzione funziona, ma non è sicura. Il mio aggira quel problema. Modificherò la mia risposta per evidenziarlo.
Marc Merlin,

1
La risposta potrebbe essere migliorata mostrando come ottenere il numero maggiore e chiarendo che 189deve essere sostituito. Una descrizione di cosa inviare devices.allowè disponibile qui: kernel.org/doc/Documentation/cgroup-v1/devices.txt
Craig Younkins

1
C'è una nuova funzionalità di Docker che lo rende leggermente più semplice: "--device-cgroup-rule" ( docs.docker.com/engine/reference/commandline/create/… )
tianon

14

Volevo estendere le risposte già fornite per includere il supporto per i dispositivi connessi dinamicamente che non sono stati acquisiti /dev/bus/usbe come farlo funzionare quando si utilizza un host Windows insieme alla VM boot2docker.

Se lavori con Windows, dovrai aggiungere eventuali regole USB per i dispositivi a cui vuoi accedere a Docker nel gestore VirtualBox. Per fare ciò è possibile arrestare la VM eseguendo:

host:~$ docker-machine stop default

Apri VirtualBox Manager e aggiungi il supporto USB con i filtri come richiesto.

Avviare la VM boot2docker:

host:~$ docker-machine start default

Poiché i dispositivi USB sono collegati alla VM boot2docker, i comandi devono essere eseguiti da quella macchina. Apri un terminale con la VM ed esegui il comando Esegui finestra mobile:

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

Nota, quando il comando viene eseguito in questo modo, verranno acquisiti solo i dispositivi USB precedentemente collegati. Il flag dei volumi è richiesto solo se si desidera che funzioni con i dispositivi collegati dopo l'avvio del contenitore. In tal caso, puoi utilizzare:

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

Nota, ho dovuto usare /devinvece che /dev/bus/usbin alcuni casi per catturare un dispositivo simile /dev/sg2. Posso solo supporre che lo stesso sarebbe vero per dispositivi come /dev/ttyACM0o /dev/ttyUSB0.

I comandi di esecuzione docker funzioneranno anche con un host Linux.


Un buon punto nel montaggio / dev: / dev invece. Ciò offre maggiore flessibilità in termini di acquisizione di altri dispositivi e aiuta anche con l'elemento dinamico.
Kotakotakota,

e compromette anche la sicurezza e l'isolamento del computer host.
Exadra37

@ Exadra37 Lo fa ... e se questo è importante nella tua applicazione, non dovresti usarlo. Tuttavia, è importante notare che ci sono alcune applicazioni in cui non ti interessa e non stai usando la finestra mobile per il suo isolamento. Nel mio caso specifico, puoi eseguire un'applicazione Linux in pacchetto su Windows.
rrpilot,

3

Un'altra opzione è quella di regolare udev, che controlla come sono montati i dispositivi e con quali privilegi. Utile per consentire l'accesso non root ai dispositivi seriali. Se hai dispositivi permanentemente collegati, l' --deviceopzione è il modo migliore per andare. Se hai dispositivi effimeri, ecco cosa ho usato:

1. Imposta la regola udev

Per impostazione predefinita, i dispositivi seriali sono montati in modo che solo gli utenti root possano accedere al dispositivo. Dobbiamo aggiungere una regola udev per renderli leggibili dagli utenti non root.

Crea un file chiamato /etc/udev/rules.d/99-serial.rules. Aggiungi la seguente riga a quel file:

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

MODE = "0666" fornirà a tutti gli utenti autorizzazioni di lettura / scrittura (ma non di esecuzione) per i tuoi dispositivi ttyUSB. Questa è l'opzione più permissiva e potresti voler restringere ulteriormente a seconda delle tue esigenze di sicurezza. Puoi leggere su udev per saperne di più sul controllo di ciò che accade quando un dispositivo è collegato a un gateway Linux.

2. Montare nella cartella / dev dall'host al contenitore

I dispositivi seriali sono spesso effimeri (possono essere collegati e scollegati in qualsiasi momento). Per questo motivo, non possiamo montare nel dispositivo diretto o nella cartella / dev / serial, perché possono scomparire quando le cose sono scollegate. Anche se li ricolleghi e il dispositivo si presenta di nuovo, tecnicamente è un file diverso da quello che è stato montato, quindi Docker non lo vedrà. Per questo motivo, montiamo l'intera cartella / dev dall'host al contenitore. È possibile farlo aggiungendo il seguente comando di volume al comando di esecuzione Docker:

-v /dev:/dev

Se il tuo dispositivo è collegato in modo permanente, utilizzare l'opzione --device o un montaggio di volume più specifico è probabilmente un'opzione migliore dal punto di vista della sicurezza.

3. Eseguire il contenitore in modalità privilegiata

Se non hai usato l'opzione --device e montato nell'intera cartella / dev, ti verrà richiesto di eseguire il contenitore in modalità privilegiata (vado a controllare le cose del cgroup sopra menzionate per vedere se questo può essere rimosso ). È possibile farlo aggiungendo quanto segue al comando di esecuzione Docker:

--privileged

4. Accedere al dispositivo dalla cartella / dev / serial / by-id

Se il dispositivo può essere collegato e scollegato, Linux non garantisce che verrà sempre montato nella stessa posizione ttyUSBxxx (specialmente se si dispone di più dispositivi). Fortunatamente, Linux creerà automaticamente un collegamento simbolico al dispositivo nella cartella / dev / serial / by-id. Il file in questa cartella sarà sempre chiamato lo stesso.

Questa è la carrellata, ho un articolo sul blog che approfondisce i dettagli.


2

È difficile per noi associare un dispositivo USB specifico a un contenitore docker che è anche specifico. Come puoi vedere, il modo consigliato per raggiungere è:

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

Legherà tutti i dispositivi a questo contenitore. Non è sicuro. A tutti i container è stato concesso di gestirli tutti.

Un altro modo è legare i dispositivi con devpath. Potrebbe apparire come:

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

o --device(meglio, no privileged):

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

Molto più sicuro. Ma in realtà è difficile sapere qual è il devpath di un dispositivo specifico.

Ho scritto questo repository per risolvere questo problema.

https://github.com/williamfzc/usb2container

Dopo aver distribuito questo server, è possibile ottenere facilmente tutte le informazioni dei dispositivi collegati tramite richiesta HTTP:

curl 127.0.0.1:9410/api/device

e prendi:

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

e legali ai tuoi contenitori. Ad esempio, puoi vedere il DEVNAME di questo dispositivo è /dev/bus/usb/001/120:

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

Forse aiuterà.


0

Con le ultime versioni della finestra mobile, questo è sufficiente:

docker run -ti --privileged ubuntu bash

Darà accesso a tutte le risorse di sistema (in / dev per esempio)


2
priviledged è una terribile opzione da utilizzare per la sicurezza, anche se sì, funziona.
Marc Merlin,

2
Se usata per programmare cose come Arduino, questa soluzione è buona
Jose Cabrera Zuniga,

0

Aggiungendo alle risposte sopra, per coloro che desiderano un modo rapido per utilizzare un dispositivo USB esterno (HDD, unità flash) che lavora all'interno della docker e non utilizza la modalità privilegiata:

Trova il devpath sul tuo dispositivo sull'host:

sudo fdisk -l

È possibile riconoscere l'unità in base alla sua capacità abbastanza facilmente dall'elenco. Copia questo percorso (per l'esempio che segue /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

Montare questo devpath (preferibile a /media):

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

Puoi quindi usarlo come parametro per docker runpiacere:

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

o nella finestra mobile comporre sotto i volumi:

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

E ora quando corri ed entri nel tuo contenitore, dovresti essere in grado di accedere all'unità all'interno del contenitore in /media/<mount folder name>

NOTA BENE:

  1. Questo probabilmente non funzionerà per dispositivi seriali come webcam ecc. Ho provato questo solo per le unità di archiviazione USB.
  2. Se è necessario riconnettere e disconnettere i dispositivi regolarmente, questo metodo sarebbe fastidioso e inoltre non funzionerebbe se non si ripristina il percorso di montaggio e si riavvia il contenitore.
  3. Ho usato la finestra mobile 17.06 + come prescritto nei documenti

0

Se si desidera accedere dinamicamente ai dispositivi USB che possono essere collegati mentre il contenitore docker è già in esecuzione, ad esempio accedere a una webcam USB appena collegata su / dev / video0, è possibile aggiungere una regola cgroup all'avvio del contenitore. Questa opzione non ha bisogno di un contenitore --privileged e consente solo l'accesso a tipi specifici di hardware.

Passo 1

Controlla il numero principale del dispositivo del tipo di dispositivo che desideri aggiungere. Puoi cercarlo nella documentazione del kernel linux . Oppure puoi controllarlo per il tuo dispositivo. Ad esempio, per controllare il numero principale del dispositivo per una webcam collegata a / dev / video0, è possibile eseguire una ls -la /dev/video0. Ciò si traduce in qualcosa di simile:

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

Dove il primo numero (81) è il numero principale del dispositivo. Alcuni numeri principali dei dispositivi comuni:

  • 81: webcam usb
  • 188: convertitori da usb a seriale

Passo 2

Aggiungi regole all'avvio del contenitore finestra mobile:

  • Aggiungi una --device-cgroup-rule='c major_number:* rmw'regola per ogni tipo di dispositivo a cui desideri accedere
  • Aggiungi l'accesso alle informazioni udev in modo che i contenitori docker possano ottenere maggiori informazioni sui tuoi dispositivi USB con -v /run/udev:/run/udev:ro
  • Mappare il volume / dev sul contenitore della finestra mobile con -v /dev:/dev

Incartare

Quindi, per aggiungere tutte le webcam USB e i dispositivi serial2usb al contenitore della finestra mobile, eseguire:

docker run -it -v /dev:/dev --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 81:* rmw' ubuntu bash
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.