В прошлый раз, когда я проверял, у Docker не было никаких средств, чтобы предоставить контейнеру доступ к последовательному порту хоста или порту USB . Есть ли хитрость, которая позволяет это сделать?
В прошлый раз, когда я проверял, у Docker не было никаких средств, чтобы предоставить контейнеру доступ к последовательному порту хоста или порту USB . Есть ли хитрость, которая позволяет это сделать?
Ответы:
Есть несколько вариантов. Вы можете использовать --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
является небезопасным и должны быть обработаны с осторожностью.
В текущих версиях Docker вы можете использовать этот --device
флаг, чтобы добиться желаемого, не предоставляя доступ ко всем USB-устройствам.
Например, если вы хотите сделать /dev/ttyUSB0
доступным только в вашем контейнере Docker, вы можете сделать что-то вроде:
docker run -t -i --device=/dev/ttyUSB0 ubuntu bash
--device
флаг, как определить, какое /dev/<device>
устройство Android связано с хостом, особенно при использовании терминала быстрого запуска Docker (VirtualBox Host) для Windows или Mac?
--device
работает до тех пор, пока ваше USB-устройство не будет отключено / повторно подключено, а затем перестает работать. Вы должны использовать cgroup devices.allow обойти это.
Вы можете просто использовать, -v /dev:/dev
но это небезопасно, поскольку оно сопоставляет все устройства вашего хоста с контейнером, включая устройства с необработанным диском и так далее. По сути, это позволяет контейнеру получить права root на хосте, что обычно не то, что вам нужно.
Использование подхода cgroups лучше в этом отношении и работает на устройствах, которые добавляются после контейнера при запуске.
Подробности здесь: Доступ к USB-устройствам в Docker без использования --privileged
Это немного сложно вставить, но в двух словах, вам нужно получить главный номер для вашего устройства персонажа и отправить его в cgroup:
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
без этого любое новое подключенное или перезагружаемое устройство после запуска контейнера получит новый идентификатор шины и не получит доступ к контейнеру.
189
необходимо заменить. Описание того, что отправлять, devices.allow
можно найти здесь: kernel.org/doc/Documentation/cgroup-v1/devices.txt
Я хотел бы расширить уже предоставленные ответы, чтобы включить поддержку динамически подключенных устройств, которые не были захвачены, /dev/bus/usb
и как заставить это работать при использовании хоста Windows вместе с виртуальной машиной boot2docker.
Если вы работаете с Windows, вам нужно добавить любые правила USB для устройств, к которым вы хотите, чтобы Docker имел доступ в диспетчере VirtualBox. Для этого вы можете остановить виртуальную машину, выполнив:
host:~$ docker-machine stop default
Откройте VirtualBox Manager и добавьте поддержку USB с фильтрами по мере необходимости.
Запустите boot2docker VM:
host:~$ docker-machine start default
Поскольку устройства USB подключены к виртуальной машине boot2docker, команды необходимо запускать с этого компьютера. Откройте терминал с виртуальной машиной и выполните команду docker run:
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
.
Команды docker run также будут работать с хостом Linux.
Другой вариант - настроить udev, который управляет монтированием устройств и какими привилегиями. Полезно, чтобы разрешить доступ без полномочий root к последовательным устройствам. Если у вас есть постоянно подключенные устройства, этот --device
вариант - лучший способ. Если у вас есть эфемерные устройства, вот что я использовал:
По умолчанию последовательные устройства монтируются так, что только корневые пользователи могут получить доступ к устройству. Нам нужно добавить правило udev, чтобы сделать его читаемым пользователями без полномочий root.
Создайте файл с именем /etc/udev/rules.d/99-serial.rules. Добавьте следующую строку в этот файл:
KERNEL=="ttyUSB[0-9]*",MODE="0666"
MODE = "0666" предоставит всем пользователям права на чтение / запись (но не выполнение) для ваших устройств ttyUSB. Это наиболее допустимый вариант, и вы можете ограничить его в зависимости от ваших требований безопасности. Вы можете прочитать об udev, чтобы узнать больше об управлении тем, что происходит, когда устройство подключено к шлюзу Linux.
Последовательные устройства часто бывают эфемерными (могут быть подключены и отключены в любое время). Из-за этого мы не можем подключиться к прямому устройству или даже к папке / dev / serial, потому что они могут исчезнуть при отключении устройства. Даже если вы подключите их снова, и устройство снова появится, это технически файл, отличный от того, что был смонтирован, поэтому Docker его не увидит. По этой причине мы монтируем всю папку / dev с хоста в контейнер. Вы можете сделать это, добавив следующую команду громкости в команду запуска Docker:
-v /dev:/dev
Если ваше устройство постоянно подключено, то с точки зрения безопасности, вероятно, лучше использовать параметр --device или более конкретное монтирование тома.
Если вы не использовали опцию --device и монтировали его во всей папке / dev, вам потребуется запустить контейнер в привилегированном режиме (я собираюсь проверить материал cgroup, упомянутый выше, чтобы увидеть, можно ли его удалить ). Вы можете сделать это, добавив в команду Docker следующую команду:
--privileged
Если ваше устройство может быть подключено и отключено, Linux не гарантирует, что оно всегда будет установлено в одном и том же месте ttyUSBxxx (особенно если у вас несколько устройств). К счастью, Linux автоматически создаст символическую ссылку на устройство в папке / dev / serial / by-id. Файл в этой папке всегда будет называться одинаково.
Это краткое изложение, у меня есть статья в блоге , в которой более подробно.
Нам сложно привязать определенное 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
Намного безопаснее. Но на самом деле трудно понять, что такое devpath конкретного устройства.
Я написал этот репо, чтобы решить эту проблему.
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
Может быть, это поможет.
Для последних версий Docker этого достаточно:
docker run -ti --privileged ubuntu bash
Это даст доступ ко всем системным ресурсам (например, в / dev)
В дополнение к ответам выше, для тех, кто хочет быстро использовать внешнее USB-устройство (жесткий диск, флэш-диск), работающее в докере и не использующее привилегированный режим:
Найдите devpath для вашего устройства на хосте:
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
Смонтируйте этот devpath (предпочтительно /media
):
sudo mount <drive path> /media/<mount folder name>
Затем вы можете использовать это как параметр, чтобы docker run
понравиться:
docker run -it -v /media/<mount folder name>:/media/<mount folder name>
или в докере составь под тома:
services:
whatevermyserviceis:
volumes:
- /media/<mount folder name>:/media/<mount folder name>
И теперь, когда вы запустите и войдете в свой контейнер, вы сможете получить доступ к диску внутри контейнера в /media/<mount folder name>
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ:
Если вы хотите получить динамический доступ к USB-устройствам, которые могут быть подключены, когда док-контейнер уже запущен, например, получить доступ к только что подключенной USB-камере по адресу / dev / video0, вы можете добавить правило cgroup при запуске контейнера. Эта опция не требует контейнера --privileged и разрешает доступ только к определенным типам оборудования.
Проверьте основной номер устройства типа устройства, которое вы хотите добавить. Вы можете посмотреть это в документации ядра Linux . Или вы можете проверить это для вашего устройства. Например, чтобы проверить основной номер устройства для веб-камеры, подключенной к / dev / video0, вы можете сделать a ls -la /dev/video0
. Это приводит к чему-то вроде:
crw-rw----+ 1 root video 81, 0 Jul 6 10:22 /dev/video0
Где первый номер (81) является основным номером устройства. Некоторые основные номера устройств:
Добавьте правила при запуске контейнера Docker:
--device-cgroup-rule='c major_number:* rmw'
правило для каждого типа устройства, к которому вы хотите получить доступ-v /run/udev:/run/udev:ro
-v /dev:/dev
Итак, чтобы добавить все USB-камеры и устройства serial2usb в ваш докер-контейнер, выполните:
docker run -it -v /dev:/dev --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 81:* rmw' ubuntu bash