上次我检查时,Docker没有任何方法让容器访问主机串行或USB端口。有什么技巧可以做到吗?
当前回答
还有一种更简单的共享usb设备的方法,没有——privileged标志。这样做:
Docker运行…——device=/dev/bus/usb——device=/dev/usb <container> .使用实例
其他回答
我们很难将特定的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(最好没有特权):
docker run -t -i --device /dev/bus/usb/001/002 ubuntu bash
更安全。但实际上很难知道特定设备的devpath是什么。
我写了这个repo来解决这个问题。
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中,你可以使用——device标志来实现你想要的,而不需要访问所有的USB设备。
例如,如果你想在Docker容器中只使/dev/ttyUSB0可访问,你可以这样做:
docker run -t -i --device=/dev/ttyUSB0 ubuntu bash
--device works until your USB device gets unplugged/replugged and then it stops working. You have to use cgroup devices.allow get around it. You could just use -v /dev:/dev but that's unsafe as it maps all the devices from your host into the container, including raw disk devices and so forth. Basically this allows the container to gain root on the host, which is usually not what you want. Using the cgroups approach is better in that respect and works on devices that get added after the container as started.
在Docker中访问USB设备而不使用——特权
这有点难粘贴,但简而言之,你需要获得你的角色设备的主编号,并将其发送到cgroup:
188是/dev/ttyUSB*的主编号,可以通过'ls -l'获得。你的系统和我的系统可能不同:
root@server:~# echo 'c 188:* 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,并且将不允许访问容器。
另一种选择是调整udev,它控制设备的挂载方式和权限。用于允许非根用户访问串行设备。如果你有永久连接的设备,——device选项是最好的选择。如果你有短暂的设备,这是我一直在使用的:
1. 设置udev规则
默认情况下,串口设备被挂载,只有root用户可以访问该设备。我们需要添加一条udev规则,让非root用户也能读懂它们。
创建一个名为/etc/udev/rules.d/99-serial.rules的文件。在该文件中添加以下一行:
内核==“ttyUSB[0-9]*”,MODE=“0666”
MODE="0666"将给予所有用户对ttyUSB设备的读/写(但不执行)权限。这是最允许的选项,您可能希望根据您的安全需求进一步限制它。您可以阅读udev以了解更多关于控制设备插入Linux网关时发生的事情的信息。
2. 从主机到容器挂载在/dev文件夹中
Serial devices are often ephemeral (can be plugged and unplugged at any time). Because of this, we can’t mount in the direct device or even the /dev/serial folder, because those can disappear when things are unplugged. Even if you plug them back in and the device shows up again, it’s technically a different file than what was mounted in, so Docker won’t see it. For this reason, we mount the entire /dev folder from the host to the container. You can do this by adding the following volume command to your Docker run command:
- v / dev: / dev
如果您的设备是永久连接的,那么从安全角度来看,使用——device选项或更特定的卷挂载可能是更好的选择。
3.以特权模式运行container
如果你没有使用——device选项,并且挂载在整个/dev文件夹中,你将被要求运行容器的特权模式(我将检查上面提到的cgroup的东西,看看是否可以删除)。你可以通过在Docker run命令中添加以下命令来做到这一点:
——特权
4. 从/dev/serial/by-id文件夹访问设备
如果您的设备可以插拔,Linux并不保证它总是挂载在同一个ttyUSBxxx位置(特别是如果您有多个设备)。幸运的是,Linux会自动创建到/dev/serial/by-id文件夹中的设备的符号链接。此文件夹中的文件将始终命名相同。
这是一个快速的纲要,我有一篇博客文章详细介绍。
对于最新版本的docker,这就足够了:
docker run -ti --privileged ubuntu bash
它将允许访问所有系统资源(例如/dev)
推荐文章
- 试图连接到https://index.docker.io时,网络超时
- 为每个Docker图像查找图层和图层大小
- 如何避免在为Python项目构建Docker映像时重新安装包?
- 如何用docker-compose更新现有图像?
- 如何在构建docker期间设置环境变量
- 拉访问拒绝存储库不存在或可能需要docker登录
- 如何在ENTRYPOINT数组中使用Docker环境变量?
- Docker:容器不断地重新启动
- Mac/OS X上的/var/lib/docker在哪里
- 如何用docker-compose标记docker图像
- 从环境文件中读入环境变量
- 禁用特定RUN命令的缓存
- 从Docker容器获取环境变量
- E: gnupg, gnupg2和gnupg1似乎没有安装,但是这个操作需要其中一个
- 如何从docker更改默认docker注册表。IO到我的私人注册表?