上次我检查时,Docker没有任何方法让容器访问主机串行或USB端口。有什么技巧可以做到吗?


当前回答

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

如果你正在使用Windows,你需要在VirtualBox管理器中为你想要Docker访问的设备添加任何USB规则。为此,您可以通过以下命令停止虚拟机:

host:~$ docker-machine stop default

打开VirtualBox管理器,根据需要添加带有过滤器的USB支持。

启动boot2docker虚拟机:

host:~$ docker-machine start default

由于USB设备连接到boot2docker虚拟机,因此需要从该机器运行命令。打开虚拟机的终端,运行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运行命令也可以在Linux主机上运行。

其他回答

在没有-特权模式的情况下安全正确地访问tty设备

只要一行一行地按照说明做,所有步骤都有说明

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

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

根据输出,您可以看到tty设备的主要组在我的示例中是188,因此我将继续进行此操作。

你可以运行docker镜像,允许访问特定主号的设备范围,docker将在你的主机上为你添加所需的规则(这将以分离模式运行docker,我们稍后将附加到它):

docker run --device-cgroup-rule='c 188:* rmw' -itd --name my_container ubuntu

现在的想法是添加一个脚本,它将在每次USB设备插入或拔出时运行。这里和这里对传递参数的自定义规则做了一些解释。在ubuntu上,你应该以超级用户(sudo)的身份创建文件/etc/udev/rules.d/99-docker- ty.rules:

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'"

该文件将新的条目添加到您的规则中,基本上是说:每次tty设备被插入-添加或插入-删除时,运行提供的脚本并传递一些参数。如果你想要更具体,你可以使用udevadm info——name=<设备名>来查找其他可以过滤设备的参数。您可以测试这里建议的规则。要应用这些规则:

root@~$ udevadm control --reload 

现在我们需要以超级用户(sudo)的身份在/usr/local/bin/ docker_ty .sh中创建以下脚本。您可以看到它被设置为在我们之前创建的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 

这个脚本将在运行的docker容器中创建tty设备,或者根据设备是否插入或拔出来删除它(类似于Ubuntu机器的情况-每次设备插入时,您都可以在/dev/目录下看到它)。提示:检查/tmp/ docker_ty .log文件,以获得主机上的一些调试输出,以及这里建议的调试bash脚本。

别忘了让脚本可执行:

root@~$ chmod +x /usr/local/bin/docker_tty.sh

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

docker exec -it my_container bash

有几个选择。你可以使用——device标志,用户可以在没有——特权模式的情况下访问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是不安全的,应该小心处理。

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

如果你正在使用Windows,你需要在VirtualBox管理器中为你想要Docker访问的设备添加任何USB规则。为此,您可以通过以下命令停止虚拟机:

host:~$ docker-machine stop default

打开VirtualBox管理器,根据需要添加带有过滤器的USB支持。

启动boot2docker虚拟机:

host:~$ docker-machine start default

由于USB设备连接到boot2docker虚拟机,因此需要从该机器运行命令。打开虚拟机的终端,运行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运行命令也可以在Linux主机上运行。

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

docker run -ti --privileged ubuntu bash

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

除了上面的答案,对于那些想要快速使用外部USB设备(HDD,闪存驱动器)在docker内部工作,而不使用特权模式的人:

在主机上找到你的设备的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运行的参数:

docker run -it -v /media/<mount folder name>:/media/<mount folder name>

或者在docker中合成volumes:

services:
  whatevermyserviceis:
    volumes:
      - /media/<mount folder name>:/media/<mount folder name>

现在,当您运行并进入容器时,您应该能够访问容器中的驱动器/media/<挂载文件夹名>

免责声明:

这可能不适用于串行设备,如网络摄像头等。 我只对USB存储驱动器进行了测试。 如果您需要定期重新连接和断开设备,这 方法将会很烦人,并且除非重置挂载路径并重新启动容器,否则将无法工作。 我使用docker 17.06 +在文档中规定