Docker - спосіб надати доступ до хост-USB або послідовного пристрою?


Відповіді:


194

Є пара варіантів. Ви можете використовувати --deviceпрапор, який може використовувати для доступу до USB-пристроїв без --privilegedрежиму:

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

Крім того, якщо припустити, що ваш USB-пристрій доступний з драйверами, що працюють тощо, на хості /dev/bus/usb, ви можете встановити це в контейнер, використовуючи привілейований режим та опцію гучності . Наприклад:

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

Зауважте, що як випливає з назви, --privilegedце небезпечно і з ними слід ставитися обережно.


4
Не потрібно -v - привілейований вже означає доступ до всіх пристроїв
Art

12
Чи є такий механізм для клієнта докера Windows?
Паскаль

Використовуючи це рішення, я не бачу пристроїв із докерного контейнера ... Ось деталі stackoverflow.com/questions/37213812 моєї проблеми. Вдячний за будь-яку допомогу! Дякую.
kashesandr

1
Все ще не працює, якщо USB-пристрій підключено після того, як Docker вже працює.
Франклін Даттейн

Я маю на увазі, що він не відображає пристрій під / tty / USBX, незважаючи на те, що lsusb зможе його перерахувати.
Франклін Даттейн

78

У поточних версіях Docker ви можете використовувати --deviceпрапор, щоб досягти бажаного, не потребуючи доступу до всіх USB-пристроїв.

Наприклад, якщо ви хочете зробити /dev/ttyUSB0доступними лише у вашому контейнері Docker, ви можете зробити щось на кшталт:

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

3
лише зауважте, що на даний момент пристрій не може бути символьним посиланням. github.com/docker/docker/isissue/13840
wligtenberg

6
використовуючи --deviceпрапор, як визначити, з яким /dev/<device>пов’язаним пристроєм Android на хост-машині, особливо коли використовується термінал Docker Quickstart (VirtualBox Host) для Windows або Mac?
DanCat

1
Це добре працює, якщо ім’я вашого пристрою ніколи не змінюється. Але якщо ви використовуєте щось динамічне, яке використовує пристрої в / dev / bus / usb, це не працюватиме, оскільки ім'я пристрою змінюється, коли ви підключаєте його та вимикаєте його з розетки. Натомість вам знадобиться вищевказане рішення (томи).
Бред Гріссом

1
Правила @DanCat udev можуть гарантувати, що ваш пристрій зможе встановити статичний шлях
C. Reed,

1
Чому хтось зацікавився б мати доступ лише до одного USB-пристрою ?? Пристрої usb призначені для підключення qnd від'єднано, і це потрібно зробити під час виконання програм. USB - це не SATA чи щось подібне, ви не можете очікувати, що щось завжди буде там ... І я не думаю, що люди просто запускають програми через докер для одноразових запусків і закривають їх, як тільки USB-пристрої відключаються, правда? Я б більше уявляв, як програми типу служб, а не одноразові банки ... Але, дякую, справді це може допомогти деяким, для яких підійде цей дуже обмежений сценарій
Arturas M

17

--deviceпрацює, поки ваш USB-пристрій не вимкнеться / відключено від мережі, а потім він перестане працювати. Ви повинні використовувати пристрої групи. Дозвольте їх обійти.
Ви можете просто використовувати, -v /dev:/devале це небезпечно, оскільки він відображає всі пристрої з вашого хоста в контейнер, включаючи пристрої з необробленим диском тощо. В основному це дозволяє контейнеру отримати корінь на хості, що зазвичай не є тим, що потрібно.
Використання підходу cgroups в цьому відношенні краще і працює на пристроях, які додаються після запуску контейнера.

Деталі див. Тут: Доступ до USB-пристроїв у Docker без використання --privileged

Це трохи важко вставити, але в двох словах, вам потрібно отримати основне число вашого персонального пристрою і надіслати це в групу:

189 - основна кількість / dev / ttyUSB *, яку ви можете отримати з 'ls -l'. У вашій системі це може відрізнятися, ніж у моїй:

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

Потім запустіть контейнер так:

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

не роблячи цього, будь-який щойно підключений або перезавантажений пристрій після запуску контейнера отримає новий ідентифікатор шини і не буде дозволений доступ до контейнера.


7
Людям, які це зробили, будь ласка, допоможіть і скажіть, що ви хочете, щоб вас покращили. Я написав цю сторінку, щоб допомогти іншим, хто потрапив у цю проблему. Я буду трохи чесним, сказавши, що мене відключають від спроби поділитися ззаду та допомагати людям у stackoverflow також: - /
Марк Мерлін

Якщо ви прочитаєте мою відповідь, ви побачите, що додавання гучності "-v / dev: / dev" надасть доступ до динамічно підключених пристроїв.
rrpilot

5
rrpilot: -v / dev: / dev дає вам усе / dev, включаючи / dev / sda та інші речі, які ви дійсно не хочете виставляти кореневому користувачеві в контейнері. Іншими словами, ваше рішення дійсно працює, але це небезпечно. Моя обходить цю проблему. Я відредагую свою відповідь, щоб вказати на це.
Марк Мерлін

1
Відповідь можна було б покращити, показавши, як отримати основну кількість, та уточнивши, що її 189потрібно замінити. Опис того, що надіслати, devices.allowможна знайти тут: kernel.org/doc/Documentation/cgroup-v1/devices.txt
Крейг Юнкінс

1
Є нова функція Docker, яка робить це трохи простіше: "--device-cgroup-rule" ( docs.docker.com/engine/reference/commandline/create/… )
tianon

14

Я хотів би розширити відповіді, що вже були надані, щоб включити підтримку динамічно підключених пристроїв, які не захоплені, /dev/bus/usbі як зробити це робочим при використанні хоста Windows разом із boot2docker VM.

Якщо ви працюєте з Windows, вам потрібно буде додати будь-які правила USB для пристроїв, до яких ви хочете, щоб Docker отримав доступ у менеджері VirtualBox. Для цього ви можете зупинити VM, запустивши:

host:~$ docker-machine stop default

Відкрийте диспетчер VirtualBox і додайте підтримку USB із необхідними фільтрами.

Запустіть boot2docker VM:

host:~$ docker-machine start default

Оскільки USB-пристрої підключені до VM boot2docker, команди потрібно запустити з цієї машини. Відкрийте термінал з VM та запустіть команду run docker:

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

Зауважте, що коли команда виконується так, то захоплюються лише раніше підключені USB-пристрої. Прапор томів потрібен лише у тому випадку, якщо ви хочете, щоб це працювало з пристроями, підключеними після запуску контейнера. У цьому випадку ви можете використовувати:

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

Зауважте, мені довелося використовувати, /devа не /dev/bus/usbв деяких випадках, щоб захопити такий пристрій /dev/sg2. Я можу лише припустити, що те саме було б справедливо і для таких пристроїв, як /dev/ttyACM0або /dev/ttyUSB0.

Команди запуску докера також будуть працювати з хостом Linux.


Хороший момент у монтажі / dev: / dev замість цього. Це дає більшу гнучкість щодо захоплення інших пристроїв, а також допомагає з динамічним елементом.
kotakotakota

а також загрожує безпеці та ізоляції вашого хост-машини.
Exadra37

@ Exadra37 Це так ... і якщо це має значення у вашій програмі, ви не повинні використовувати це. Однак важливо зазначити, що є деякі програми, де вам не байдуже і не використовуєте докер для його ізоляції. У моєму конкретному випадку ви можете запустити пакетну програму Linux у Windows.
rrpilot

3

Інший варіант - налаштувати udev, який контролює, як встановлюються пристрої та які привілеї. Корисно для дозволу некорінного доступу до послідовних пристроїв. Якщо у вас постійно приєднані пристрої, --deviceваріант є найкращим способом. Якщо у вас є ефемерні пристрої, ось що я використовував:

1. Встановити правило udev

За замовчуванням послідовні пристрої змонтовані так, що до нього можуть отримати доступ лише користувачі root. Нам потрібно додати правило udev, щоб зробити їх читабельними не-root користувачами.

Створіть файл з іменем /etc/udev/rules.d/99-serial.rules. Додайте до цього файлу наступний рядок:

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

MODE = "0666" надасть усім користувачам читання / запис (але не виконання) дозволів на ваші пристрої ttyUSB. Це найбільш дозволений варіант, і ви, можливо, захочете додатково обмежити це залежно від ваших вимог безпеки. Ви можете прочитати на udev, щоб дізнатися більше про контроль того, що відбувається, коли пристрій підключено до шлюзу Linux.

2. Змонтувати папку / dev від хоста до контейнера

Серійні пристрої часто є ефемерними (їх можна підключити та від'єднати в будь-який час). Через це ми не можемо встановити прямий пристрій або навіть папку / dev / serial, оскільки вони можуть зникнути, коли речі від'єднані від мережі. Навіть якщо ви підключите їх знову, і пристрій з’явиться знову, файл технічно відрізняється від того, що встановлено, тому Docker його не побачить. З цієї причини ми монтуємо всю папку / dev від хоста до контейнера. Ви можете зробити це, додавши до команди Docker наступну команду том:

-v /dev:/dev

Якщо ваш пристрій постійно підключений, то кращим варіантом з точки зору безпеки є використання опції --device або більш конкретного кріплення гучності.

3. Запустіть контейнер у привілейованому режимі

Якщо ви не використовували параметр --device і монтувались у всій папці / dev, вам буде потрібно запустити контейнер у привілейованому режимі (я збираюся перевірити згадані вище матеріали про групу, щоб побачити, чи можна це видалити ). Це можна зробити, додавши в команду запуску Docker наступне:

--privileged

4. Доступ до пристрою з папки / dev / serial / by-id

Якщо ваш пристрій можна підключити та відключити від мережі, Linux не гарантує, що він завжди буде встановлений у тому ж самому місці ttyUSBxxx (особливо якщо у вас є кілька пристроїв). На щастя, Linux автоматично зробить символьне посилання на пристрій у папці / dev / serial / by-id. Файл у цій папці завжди буде називатися однаковим.

Це швидкий пробіг, у мене є стаття в блозі, яка детальніше описується.


2

Нам важко прив’язати конкретний USB-пристрій до докерного контейнера, який також є специфічним. Як бачите, рекомендований спосіб досягти:

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

Він прив’яже всі пристрої до цього контейнера. Це небезпечно. Кожен контейнер був наданий для експлуатації всіх.

Інший спосіб - прив'язка пристроїв devpath. Це може виглядати так:

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

або --device(краще, ні privileged):

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

Набагато безпечніше. Але насправді важко знати, що таке конкретний пристрій.

Я написав це репо, щоб вирішити цю проблему.

https://github.com/williamfzc/usb2container

Після розгортання цього сервера ви можете легко отримати всю інформацію про підключені пристрої через HTTP-запит:

curl 127.0.0.1:9410/api/device

і отримуй:

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

і прив’яжіть їх до своїх контейнерів. Наприклад, ви можете бачити DEVNAME цього пристрою /dev/bus/usb/001/120:

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

Можливо, це допоможе.


0

Для останніх версій докера цього достатньо:

docker run -ti --privileged ubuntu bash

Це дасть доступ до всіх системних ресурсів (наприклад, in / dev)


2
priviledged - це жахливий варіант використання для безпеки, хоча так, він працює.
Марк Мерлін

2
Якщо використовується для програмування таких матеріалів, як Ардуїно, це рішення добре
Хосе Кабрера Зуніга

0

Додаючи відповіді вище, для тих, хто хоче швидким способом використовувати зовнішній USB-пристрій (жорсткий диск, флешку), що працює всередині докера та не використовує приватний режим:

Знайдіть розробку до свого пристрою на хості:

sudo fdisk -l

Ви можете розпізнати свій привід за його місткістю досить легко зі списку. Скопіюйте цей шлях (для наступного прикладу це /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

Гора цей шлях (бажано /media):

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

Потім ви можете використовувати це як параметр, щоб docker runподобатися:

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

або в docker складати під томами:

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

А тепер, коли ви запустите та введете контейнер, ви повинні мати доступ до диска всередині контейнера /media/<mount folder name>

ВІДМОВА:

  1. Можливо, це не буде працювати для серійних пристроїв, таких як веб-камери тощо. Я протестував це лише на накопичувачах USB.
  2. Якщо вам потрібно регулярно підключати та відключати пристрої, цей спосіб буде дратувати, а також не буде працювати, якщо ви не скинете шлях монтажу та перезавантажте контейнер.
  3. Я використовував docker 17.06 +, як прописано в документах

0

Якщо ви хочете динамічно отримувати доступ до USB-пристроїв, які можна підключити під час роботи контейнера докера, наприклад, отримати доступ до щойно приєднаної веб-камери usb за адресою / dev / video0, ви можете додати правило групи під час запуску контейнера. Цей параметр не потребує - привілейований контейнер і дозволяє лише доступ до певних типів обладнання.

Крок 1

Перевірте основну кількість пристрою типу пристрою, який ви хочете додати. Ви можете знайти його в документації на ядро ​​Linux . Або ви можете перевірити це на своєму пристрої. Наприклад, для перевірки основного номера пристрою для веб-камери, підключеної до / dev / video0, ви можете зробити це ls -la /dev/video0. Це призводить до такого типу:

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

Де перший номер (81) - основне число пристрою. Деякі основні номери основних пристроїв:

  • 81: веб-камери usb
  • 188: usb до послідовних перетворювачів

Крок 2

Додайте правила під час запуску контейнера докер:

  • Додайте --device-cgroup-rule='c major_number:* rmw'правило для кожного типу пристроїв, до яких ви хочете отримати доступ
  • Додайте доступ до інформації udev, щоб докерні контейнери могли отримати більше інформації на ваших USB-пристроях -v /run/udev:/run/udev:ro
  • Зіставте / dev том у вашому докерному контейнері -v /dev:/dev

Загорнути

Отже, щоб додати всі веб-камери usb та serial2usb до вашого контейнера docker, зробіть:

docker run -it -v /dev:/dev --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 81:* rmw' ubuntu bash
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.