Docker - a way to give access to a host USB or serial device?
上次我检查时,Docker没有任何方法允许容器访问主机串行或USB端口。 有没有办法做到这一点?
有两种选择。您可以使用
1 | docker run -t -i --device=/dev/ttyUSB0 ubuntu bash |
或者,假设您的USB设备在
1 | docker run -t -i --privileged -v /dev/bus/usb:/dev/bus/usb ubuntu bash |
注意,顾名思义,
对于当前版本的Docker,您可以使用
例如,如果您只想在Docker容器中访问
1 | docker run -t -i --device=/dev/ttyUSB0 ubuntu bash |
您可以只使用
在这方面,使用cgroups方法更好,并且可以在容器启动后添加的设备上使用。
在此处查看详细信息:在不使用--privileged的情况下访问Docker中的USB设备
粘贴起来有点困难,但是简而言之,您需要获取字符设备的主要编号并将其发送给cgroup:
189是/ dev / ttyUSB *的主要号码,您可以通过'ls -l'获得。您的系统上的系统可能与我的系统上的系统不同:
1 2 | root@server:~# echo 'c 189:* rwm' > /sys/fs/cgroup/devices/docker/$A*/devices.allow (A contains the docker containerID) |
然后像这样启动您的容器:
1 | docker run -v /dev/bus:/dev/bus:ro -v /dev/serial:/dev/serial:ro -i -t --entrypoint /bin/bash debian:amd64 |
如果不执行此操作,则容器启动后任何新插入或重新引导的设备都将获得新的总线ID,并且将不允许在容器中访问该设备。
我想扩展已经给出的答案,以包括对未使用
如果使用Windows,则需要在VirtualBox管理器中为要Docker访问的设备添加任何USB规则。为此,您可以通过运行以下命令来停止VM:
1 | host:~$ docker-machine stop default |
打开VirtualBox Manager,然后根据需要添加带有过滤器的USB支持。
启动boot2docker VM:
1 | host:~$ docker-machine start default |
由于USB设备已连接到boot2docker VM,因此需要从该计算机上运行命令。使用VM打开终端并运行docker run命令:
1 2 | host:~$ docker-machine ssh docker@default:~$ docker run -it --privileged ubuntu bash |
请注意,以这种方式运行命令时,将仅捕获以前连接的USB设备。仅当您希望它与容??器启动后连接的设备一起使用时,才需要volumes标志。在这种情况下,您可以使用:
1 | docker@default:~$ docker run -it --privileged -v /dev:/dev ubuntu bash |
注意,在某些情况下,必须使用
docker run命令也将与Linux主机一起使用。
另一个选择是调整udev,它控制设备的安装方式和特权。允许非root用户访问串行设备很有用。如果您已永久连接设备,则
1.设置udev规则
默认情况下,将挂载串行设备,以便只有root用户才能访问该设备。我们需要添加udev规则,以使非root用户可以读取它们。
创建一个名为/etc/udev/rules.d/99-serial.rules的文件。将以下行添加到该文件:
MODE =" 0666"将授予所有用户对ttyUSB设备的读/写(但不执行)权限。这是最宽松的选项,您可能想根据安全要求进一步限制它。您可以阅读udev以了解有关控制将设备插入Linux网关时发生的情况的更多信息。
2.在/ dev文件夹中从主机挂载到容器
串行设备通常是临时的(可以随时插入和拔出)。因此,我们无法挂载在直接设备甚至/ dev / serial文件夹中,因为当拔下电源时,它们可能会消失。即使您将它们重新插入并重新显示设备,从技术上讲,它也是与装入的文件不同的文件,因此Docker无法看到它。因此,我们将整个/ dev文件夹从主机安装到容器。您可以通过在Docker run命令中添加以下volume命令来执行此操作:
如果您的设备是永久连接的,那么从安全角度来看,使用--device选项或更特定的卷安装可能是更好的选择。
3.以特权模式运行容器
如果您未使用--device选项并安装在整个/ dev文件夹中,则将需要以特权模式运行容器(我将检查上述cgroup的内容,以查看是否可以删除此容器) )。您可以通过在Docker run命令中添加以下内容来做到这一点:
4.从/ dev / serial / by-id文件夹访问设备
如果可以插入和拔出设备,Linux不能保证将其始终安装在同一ttyUSBxxx位置(特别是如果您有多个设备)。幸运的是,Linux会自动在/ dev / serial / by-id文件夹中建立到设备的符号链接。此文件夹中的文件将始终被命名为相同的文件。
这是一个快速的总结,我有一篇博客文章,其中有更多详细信息。
对于想要快速使用docker内部工作的外部USB设备(HDD,闪存驱动器)并且不使用特权模式的用户,请添加以下答案:
在主机上找到设备的devpath:
1 | sudo fdisk -l |
您可以从列表中很容易地通过容量识别驱动器。复制此路径(对于以下示例,该路径为
1 2 3 4 | Disque /dev/sda2: 554,5 Go, 57151488octets, 111624secteurs Unités: secteur de 1 × 512 = 512octets Taille de secteur (logique / physique): 512octets / 512octets taille d'E/S (minimale / optimale): 512octets / 512octets |
挂载此devpath(最好是
1 | sudo mount <drive path> /media/<mount folder name> |
然后,您可以将其用作
1 | docker run -it -v /media/<mount folder name>:/media/<mount folder name> |
或在docker下根据卷撰写:
1 2 3 4 | services: whatevermyserviceis: volumes: - /media/<mount folder name>:/media/<mount folder name> |
现在,当您运行并输入容器时,您应该可以通过
免责声明:
我只测试了USB存储驱动器。
除非您重置安装路径并重新启动容器,否则该方法将很烦人,并且也将不起作用。
对于我们而言,很难将特定的USB设备绑定到同样特定的Docker容器。如您所见,推荐的实现方法是:
1 | docker run -t -i --privileged -v /dev/bus/usb:/dev/bus/usb ubuntu bash |
它将所有设备绑定到此容器。不安全每个容器都被允许操作所有这些容器。
另一种方法是通过devpath绑定设备。它可能看起来像:
1 | docker run -t -i --privileged -v /dev/bus/usb/001/002:/dev/bus/usb/001/002 ubuntu bash |
或
1 | docker run -t -i --device /dev/bus/usb/001/002 ubuntu bash |
安全得多。但是实际上很难知道特定设备的devpath是什么。
我已经写了这个仓库来解决这个问题。
https://github.com/williamfzc/usb2container
部署此服务器后,您可以通过HTTP请求轻松获得所有已连接设备的信息:
1 | curl 127.0.0.1:9410/api/device |
并得到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | { "/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是
1 | docker run -t -i --device /dev/bus/usb/001/120 ubuntu bash |
也许会有所帮助。
使用最新版本的docker,这就足够了:
1 | docker run -ti --privileged ubuntu bash |
它将允许访问所有系统资源(例如,在/ dev中)