上次我检查时,Docker没有任何方法允许容器访问主机串行或USB端口。有没有技巧可以做到这一点?
上次我检查时,Docker没有任何方法允许容器访问主机串行或USB端口。有没有技巧可以做到这一点?
Answers:
有两种选择。您可以使用--device
可用于访问无--privileged
模式USB设备的标志:
docker run -t -i --device=/dev/ttyUSB0 ubuntu bash
或者,假设您的USB设备在主机上的驱动程序可用等情况下可用/dev/bus/usb
,则可以使用特权模式和volumes选项将其安装在容器中。例如:
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设备,尤其是在Windows或Mac上使用Docker Quickstart Terminal(VirtualBox主机)时?
--device
直到您的USB设备拔出/重新插入,然后停止工作。您必须使用cgroup devices.allow解决它。
您可以使用-v /dev:/dev
它,但这是不安全的,因为它会将主机中的所有设备映射到容器中,包括原始磁盘设备等。基本上,这使容器可以在主机上获得根,这通常不是您想要的。
在这方面,使用cgroups方法更好,并且可以在容器启动后添加的设备上使用。
在此处查看详细信息:在不使用--privileged的情况下访问Docker中的USB设备
粘贴起来有点困难,但是简而言之,您需要获取字符设备的主要编号并将其发送给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
如果不这样做,则在容器启动后,任何新插入或重新启动的设备都将获得新的总线ID,并且将不允许在容器中进行访问。
189
必须替换的主号码,可以使答案更好。有关发送内容的说明,请devices.allow
参见:kernel.org/doc/Documentation/cgroup-v1/devices.txt
我想扩展已经给出的答案,以包括对未捕获的动态连接的设备的支持,/dev/bus/usb
以及如何在将Windows主机与boot2docker VM一起使用时如何使该设备正常工作。
如果您使用Windows,则需要在VirtualBox管理器中为希望Docker访问的设备添加任何USB规则。为此,您可以通过运行以下命令来停止VM:
host:~$ docker-machine stop default
打开VirtualBox Manager并根据需要添加带有过滤器的USB支持。
启动boot2docker VM:
host:~$ docker-machine start default
由于USB设备已连接到boot2docker VM,因此需要从该计算机上运行命令。使用VM打开终端并运行docker run命令:
host:~$ docker-machine ssh
docker@default:~$ docker run -it --privileged ubuntu bash
请注意,以这种方式运行命令时,将仅捕获以前连接的USB设备。仅当您希望它与容器启动后连接的设备一起使用时,才需要volumes标志。在这种情况下,您可以使用:
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
选项是最佳选择。如果您拥有临时设备,这就是我一直在使用的设备:
默认情况下,将挂载串行设备,以便只有root用户才能访问该设备。我们需要添加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 run命令中添加以下volume命令来执行此操作:
-v /dev:/dev
如果您的设备是永久连接的,那么从安全角度来看,使用--device选项或更特定的卷安装可能是更好的选择。
如果您未使用--device选项并安装在整个/ dev文件夹中,则将需要以特权模式运行容器(我将检查上述cgroup的内容,以查看是否可以删除此容器) )。您可以通过在Docker run命令中添加以下内容来做到这一点:
--privileged
如果可以插入和拔出设备,Linux不能保证将其始终安装在同一ttyUSBxxx位置(特别是如果您有多个设备)。幸运的是,Linux会自动在/ dev / serial / by-id文件夹中建立到设备的符号链接。此文件夹中的文件将始终被命名为相同的文件。
这是一个快速的总结,我有一篇博客文章,其中有更多详细信息。
对于我们来说,很难将特定的USB设备绑定到同样特定的Docker容器。如您所见,推荐的实现方法是:
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中)
对于想要快速使用docker 内部工作的外部USB设备(HDD,闪存驱动器)并且不使用特权模式的用户,请添加以下答案:
在主机上找到设备的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>
或在docker下根据卷撰写:
services:
whatevermyserviceis:
volumes:
- /media/<mount folder name>:/media/<mount folder name>
现在,当您运行并输入容器时,您应该可以在以下位置访问容器内的驱动器 /media/<mount folder name>
免责声明:
如果您想动态访问可在Docker容器运行时插入的USB设备,例如访问/ dev / video0上刚刚连接的USB网络摄像头,则可以在启动容器时添加cgroup规则。此选项不需要--privileged容器,仅允许访问特定类型的硬件。
检查您要添加的设备类型的设备主号码。您可以在linux内核文档中进行查找。或者,您可以为您的设备检查它。例如,要检查连接到/ dev / video0的网络摄像机的设备主号码,可以执行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容器,请执行以下操作:
docker run -it -v /dev:/dev --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 81:* rmw' ubuntu bash