Docker-一种允许访问主机USB或串行设备的方法?

Docker-一种允许访问主机USB或串行设备的方法?,docker,Docker,上次我查的时候。有什么技巧可以做到这一点吗?有两种选择。您可以使用--device标志,该标志用于在没有--privileged模式的情况下访问USB设备: 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 ubu

上次我查的时候。有什么技巧可以做到这一点吗?

有两种选择。您可以使用
--device
标志,该标志用于在没有
--privileged
模式的情况下访问USB设备:

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设备

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

docker run -t -i --device=/dev/ttyUSB0 ubuntu bash
crw-rw----+ 1 root video 81, 0 Jul  6 10:22 /dev/video0

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

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

host:~$ docker-machine stop default
打开VirtualBox Manager并根据需要添加带过滤器的USB支持

启动boot2docker虚拟机:

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主机上运行。

--device
会一直工作,直到USB设备拔出/重新插上电源,然后停止工作。您必须使用cgroup设备。允许绕过它。
您可以只使用
-v/dev:/dev
,但这是不安全的,因为它将主机中的所有设备映射到容器中,包括原始磁盘设备等等。基本上,这允许容器在主机上获得根目录,这通常不是您想要的。
在这方面,使用cgroups方法更好,并且适用于在容器启动后添加的设备

详情如下:

粘贴有点困难,但简而言之,您需要获取角色设备的主要编号并将其发送到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,并且将不允许在容器中访问。

对于最新版本的docker,这就足够了:

docker run -ti --privileged ubuntu bash

它将允许访问所有系统资源(例如在/dev中)

另一个选项是调整udev,它控制设备的安装方式和权限。用于允许对串行设备进行非根访问。如果您有永久连接的设备,
--device
选项是最好的选择。如果你有短暂的设备,下面是我一直在使用的:

1.设置udev规则 默认情况下,安装串行设备时,只有root用户才能访问该设备。我们需要添加一个udev规则,以使非root用户能够读取它们

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

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

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

2.在/dev文件夹中从主机装载到容器 串行设备通常是短暂的(可以随时插拔)。因此,我们无法在direct设备或甚至/dev/serial文件夹中装载,因为这些东西在拔掉插头后可能会消失。即使你将它们重新插入,设备再次显示,从技术上讲,它与挂载的文件不同,所以Docker不会看到它。因此,我们将整个/dev文件夹从主机装载到容器中。可以通过将以下卷命令添加到Docker run命令来完成此操作:

host:~$ docker-machine ssh
docker@default:~$ docker run -it --privileged ubuntu bash
-v/dev:/dev

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

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

host:~$ docker-machine ssh
docker@default:~$ docker run -it --privileged ubuntu bash
--特权

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

这是一个快速的概述,我有一个更详细的说明。

它是
sudo mount <drive path> /media/<mount folder name>
docker run -it -v /media/<mount folder name>:/media/<mount folder name>
services:
  whatevermyserviceis:
    volumes:
      - /media/<mount folder name>:/media/<mount folder name>
crw-rw----+ 1 root video 81, 0 Jul  6 10:22 /dev/video0
docker run -it -v /dev:/dev --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 81:* rmw' ubuntu bash
$ ls -l /dev/ | grep ttyUSB
crw-rw-rw-  1 root  dialout 188,   0 Mar  1 18:23 ttyUSB0 #Example output

docker run --device-cgroup-rule='c 188:* rmw' -itd --name my_container ubuntu
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'"
root@~$ udevadm control --reload 
#!/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 
root@~$ chmod +x /usr/local/bin/docker_tty.sh
docker exec -it my_container bash