Ben*_*ley 171

有几种选择.首先,正如下面的@Mark所述,Docker 1.2.0版(2014/08发布)添加了一个--device标志,用于在没有--privileged模式的情况下访问USB设备:

docker run -t -i --device=/dev/ttyUSB0 ubuntu bash
Run Code Online (Sandbox Code Playgroud)

或者,假设您的USB设备可用于主机上的驱动程序等/dev/bus/usb,您可以使用特权模式卷选项将其安装在容器中.例如:

docker run -t -i --privileged -v /dev/bus/usb:/dev/bus/usb ubuntu bash
Run Code Online (Sandbox Code Playgroud)

  • 这个Windows docker客户端有这样的机制吗? (9认同)
  • 不需要-v-特权已经意味着可以访问所有设备 (2认同)
  • 如果在 Docker 已经运行后连接了 USB 设备,则仍然不起作用。 (2认同)
  • 我的意思是,尽管 lsusb 能够列出它,但它并没有映射 /tty/USBX 下的设备。 (2认同)

Mar*_*ark 76

使用当前版本的Docker,您可以使用该--device标志来实现您想要的功能,而无需访问所有USB设备.

例如,如果您只想/dev/ttyUSB0在Docker容器中访问,则可以执行以下操作:

docker run -t -i --device=/dev/ttyUSB0 ubuntu bash
Run Code Online (Sandbox Code Playgroud)

  • 使用`--device`标志,如何确定哪个`/ dev/<device>`是主机上相关的Android设备,特别是在使用适用于Windows或Mac的Docker Quickstart Terminal(VirtualBox Host)时? (4认同)
  • 请注意,此刻设备不能是符号链接.https://github.com/docker/docker/issues/13840 (3认同)
  • @DanCat udev 规则可以确保您的设备挂载到静态路径 (2认同)
  • 为什么有人会对仅访问一个 USB 设备感兴趣?USB 设备旨在连接和断开连接,并且需要在应用程序运行时完成。USB 不是 SATA 之类的东西,你不能指望某些东西总是存在......而且我不认为人们只是通过 docker 启动应用程序进行单次运行并在 USB 设备断开连接后立即退出,对吧?我想象更像是服务类型的应用程序,而不是单次运行的罐子...但是谢谢,确实这可能会帮助一些非常有限的场景适合的人 (2认同)
  • @arturas-m 例如,现在很多传感器都是 USB 的。在 IMO 的许多用例中,不需要插入传感器。 (2认同)

rrp*_*lot 11

我想扩展已经给出的答案,包括支持未捕获的动态连接设备/dev/bus/usb以及如何在使用Windows主机和boot2docker VM时使其工作.

如果您使用的是Windows,则需要为希望Docker在VirtualBox管理器中访问的设备添加任何USB规则.为此,您可以通过运行以下命令来停止VM:

host:~$ docker-machine stop default
Run Code Online (Sandbox Code Playgroud)

打开VirtualBox Manager并根据需要添加带有过滤器的USB支持.

启动boot2docker VM:

host:~$ docker-machine start default
Run Code Online (Sandbox Code Playgroud)

由于USB设备连接到boot2docker VM,因此需要从该计算机运行命令.使用VM打开终端并运行docker run命令:

host:~$ docker-machine ssh
docker@default:~$ docker run -it --privileged ubuntu bash
Run Code Online (Sandbox Code Playgroud)

注意,当命令像这样运行时,只会捕获以前连接的USB设备.只有在您希望在启动容器后才能使用连接的设备时,才需要使用卷标志.在这种情况下,您可以使用:

docker@default:~$ docker run -it --privileged -v /dev:/dev ubuntu bash
Run Code Online (Sandbox Code Playgroud)

注意,我不得不使用/dev而不是/dev/bus/usb在某些情况下捕获像这样的设备/dev/sg2.我只能假设像/dev/ttyACM0或或类似的设备也是如此/dev/ttyUSB0.

docker run命令也适用于Linux主机.


Mar*_*lin 11

--device直到您的USB设备拔出/重新插入,然后停止工作。您必须使用cgroup devices.allow解决它。
您可以使用-v /dev:/dev它,但这是不安全的,因为它会将主机中的所有设备(包括原始磁盘设备等)映射到容器中。基本上,这允许容器在主机上获得root权限,这通常不是您想要的。
在这方面,使用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)
Run Code Online (Sandbox Code Playgroud)

然后像这样启动您的容器:

docker run -v /dev/bus:/dev/bus:ro -v /dev/serial:/dev/serial:ro -i -t --entrypoint /bin/bash debian:amd64
Run Code Online (Sandbox Code Playgroud)

否则,容器启动后任何新插入或重新启动的设备都将获得新的总线ID,并且将不允许在容器中访问它。

  • 对于-1版的用户,请帮助并说出您希望改进的地方。我写这个页面是为了帮助其他遇到我们问题的人。我会坦白地说,我被禁止尝试共享和帮助人们进行stackoverflow的行为被关闭了:-/ (5认同)
  • Docker 的一个新功能使这个过程稍微简单一些:“--device-cgroup-rule”(https://docs.docker.com/engine/reference/commandline/create/#dealing-with-dynamically-created) -设备---设备-cgroup-规则) (5认同)
  • rrpilot:-v / dev:/ dev确实为您提供了/ dev的所有内容,包括/ dev / sda以及您确实不想向容器中的root用户公开的其他内容。换句话说,您的解决方案确实有效,但这是不安全的。我的解决了这个问题。我将编辑答案以指出这一点。 (4认同)
  • 通过展示如何获得主编号并阐明必须替换“189”,可以更好地回答问题。可以在此处找到发送“devices.allow”的内容的描述:https://www.kernel.org/doc/Documentation/cgroup-v1/devices.txt (3认同)

小智 11

如果您想动态访问可以在 docker 容器已经运行时插入的 USB 设备,例如访问刚刚连接到 /dev/video0 的 USB 网络摄像头,您可以在启动容器时添加 cgroup 规则。此选项不需要 --privileged 容器,只允许访问特定类型的硬件。

第1步

检查您要添加的设备类型的设备主要编号。您可以在linux 内核文档中查找它。或者您可以为您的设备检查它。例如,要检查连接到 /dev/video0 的网络摄像头的设备主编号,您可以执行ls -la /dev/video0. 这会导致类似的结果:

crw-rw----+ 1 root video 81, 0 Jul  6 10:22 /dev/video0
Run Code Online (Sandbox Code Playgroud)

其中第一个数字 (81) 是设备主编号。一些常见的设备主号:

  • 81:USB 网络摄像头
  • 188:USB转串口转换器

第2步

启动docker容器时添加规则:

  • --device-cgroup-rule='c major_number:* rmw'为您要访问的每种类型的设备添加规则
  • 添加对 udev 信息的访问权限,以便 docker 容器可以通过以下方式获取有关您的 USB 设备的更多信息 -v /run/udev:/run/udev:ro
  • 使用以下命令将 /dev 卷映射到您的 docker 容器 -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
Run Code Online (Sandbox Code Playgroud)


小智 8

在没有--privileged模式的情况下访问 tty 设备的安全和正确的方法

只需一行一行地按照说明进行操作,所有步骤都有说明

想法是正确配置cgroup规则。首先,让我们找到您的 USB 设备的 cgroup 属性。运行以下命令:

$ ls -l /dev/ | grep ttyUSB
crw-rw-rw-  1 root  dialout 188,   0 Mar  1 18:23 ttyUSB0 #Example output

Run Code Online (Sandbox Code Playgroud)

根据输出,您可以看到主要的 tty 设备组188在我的情况下,因此我将继续进行。

您可以运行 docker image允许访问具有特定主编号的设备范围,docker 会在您的主机中为您添加所需的规则(这将在分离模式下运行 docker,我们稍后会附加到它):

docker run --device-cgroup-rule='c 188:* rmw' -itd --name my_container ubuntu
Run Code Online (Sandbox Code Playgroud)

现在的想法是添加一个脚本,每次插入或拔出 USB 设备时都会运行该脚本。关于自定义规则herehere关于传递参数的一些解释。在 ubuntu 上,您应该/etc/udev/rules.d/99-docker-tty.rules以超级用户身份(sudo)创建文件:

ACTION=="add", SUBSYSTEM=="tty", RUN+="/usr/local/bin/docker_tty.sh 'added' '%E{DEVNAME}' '%M' '%m'"
ACTION=="remove", SUBSYSTEM=="tty", RUN+="/usr/local/bin/docker_tty.sh 'removed' '%E{DEVNAME}' '%M' '%m'"
Run Code Online (Sandbox Code Playgroud)

该文件为您的规则添加了新条目,基本上是说:每次插入add或拔出tty 设备时,remove运行提供的脚本并传递一些参数。如果您想更具体,您可以使用udevadm info --name=<device name>查找其他参数,您可以根据这些参数过滤设备。您可以按照此处的建议测试规则。要应用这些规则:

root@~$ udevadm control --reload 
Run Code Online (Sandbox Code Playgroud)

现在我们还需要以/usr/local/bin/docker_tty.sh超级用户(sudo)的身份创建以下脚本。您可以看到它被设置为在我们之前创建的 udev 规则中运行。

#!/usr/bin/env bash  
                                                           
echo "Usb event: $1 $2 $3 $4" >> /tmp/docker_tty.log        
if [ ! -z "$(docker ps -qf name=env_dev)" ]                                     
then                                                                            
if [ "$1" == "added" ]                                                          
    then                                                                        
        docker exec -u 0 env_dev mknod $2 c $3 $4                               
        docker exec -u 0 env_dev chmod -R 777 $2                                
        echo "Adding $2 to docker" >> /tmp/docker_tty.log                
    else                                                                        
        docker exec -u 0 env_dev rm $2                                          
        echo "Removing $2 from docker" >> /tmp/docker_tty.log            
    fi                                                                          
fi 
Run Code Online (Sandbox Code Playgroud)

此脚本将在您正在运行的 docker 容器中创建 tty 设备,或者根据设备是否已插入或已拔出将其删除(类似于 Ubuntu 机器发生的情况 - 每次插入设备时,您都可以在/dev/目录下看到它)。提示:检查/tmp/docker_tty.log主机上的一些调试输出文件,此外,按照此处的建议调试 bash 脚本。

不要忘记使脚本可执行:

root@~$ chmod +x /usr/local/bin/docker_tty.sh
Run Code Online (Sandbox Code Playgroud)

现在连接到 docker,看看/dev/当你插入和拔出设备时,设备是否出现在目录中:

docker exec -it my_container bash
Run Code Online (Sandbox Code Playgroud)


Bad*_*yon 6

另一个选择是调整 udev,它控制设备的安装方式以及具有哪些权限。对于允许非 root 访问串行设备很有用。如果您有永久连接的设备,那么该--device选项是最好的选择。如果您有临时设备,这是我一直在使用的:

\n\n

1.设置udev规则

\n\n

默认情况下,会挂载串行设备,以便只有 root 用户才能访问该设备。我们需要添加 udev 规则以使非 root 用户可以读取它们。

\n\n

创建名为 /etc/udev/rules.d/99-serial.rules 的文件。将以下行添加到该文件中:

\n\n

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

\n\n

MODE="0666" 将授予所有用户对 ttyUSB 设备的读/写(但不是执行)权限。这是最宽松的选项,您可能需要根据您的安全要求进一步限制此选项。您可以阅读 udev 以了解有关控制设备插入 Linux 网关时发生的情况的更多信息。

\n\n

2.从主机到容器的/dev文件夹中挂载

\n\n

串行设备通常是短暂的(可以随时插入和拔出)。因此,我们可以\xe2\x80\x99t挂载在直接设备甚至/dev/serial文件夹中,因为当拔掉插头时这些可能会消失。即使您将它们重新插入并且设备再次显示,从技术上讲,它是与安装的文件不同的文件,因此 Docker 不会看到它。因此,我们将整个 /dev 文件夹从主机挂载到容器。您可以通过将以下卷命令添加到 Docker 运行命令来完成此操作:

\n\n

-v /dev:/dev

\n\n

如果您的设备是永久连接的,那么从安全角度来看,使用 --device 选项或更具体的卷安装可能是更好的选择。

\n\n

3.以特权模式运行容器

\n\n

如果您没有使用 --device 选项并安装在整个 /dev 文件夹中,您将需要以特权模式运行容器(我将检查上面提到的 cgroup 内容,看看这是否可以已删除)。您可以通过将以下内容添加到 Docker 运行命令来完成此操作:

\n\n

--privileged

\n\n

4.从/dev/serial/by-id文件夹访问设备

\n\n

如果您的设备可以插入和拔出,Linux 不保证它将始终安装在同一个 ttyUSBxxx 位置(特别是如果您有多个设备)。幸运的是,Linux 会自动在 /dev/serial/by-id 文件夹中创建一个到设备的符号链接。该文件夹中的文件将始终以相同的名称命名。

\n\n

这是简要概述,我有一篇博客文章介绍了更多详细信息。

\n