Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing devices (webcam, USB drives, etc) with Docker

I have a need to share specific devices from /dev on my host Linux machine with my docker containers.

The --privileged flag works for sharing any devices in /dev that are present at the time docker run is called, but any subsequently added or removed devices do not propagate into the container.

I tried docker run -v=/dev:/dev ... but that ended up screwing with the permissions and ownership of files like /dev/pts, leading to the host machine to not be able to create new psuedo-terminals.

I also tried the --device flag, but that doesn't allow you to share a device that doesn't yet exist.

Finally, I tried sharing volumes for devices like -v=/dev/video0:/dev/video0 but if /dev/video0 doesn't exist before run, docker creates a directory there and a webcam will not take /dev/video0 when plugged in.

Is there any better way to get this supported functionality?

like image 242
Ryan Avatar asked Dec 16 '15 00:12

Ryan


People also ask

Can Docker containers access USB devices?

Once you've got that bit in your docker-compose. yaml file you will need to run the docker-compose up -d command from the SSH session, in the folder where the docker-compose. yaml file lives, to recreate the container with the new USB mapping. ZHA should now find your USB stick and you can start pairing Zigbee devices!

Can 2 containers communicate with each other?

If you are running more than one container, you can let your containers communicate with each other by attaching them to the same network. Docker creates virtual networks which let your containers talk to each other. In a network, a container has an IP address, and optionally a hostname.


2 Answers

You are looking check the flag --device

   --device=[]       Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc:rwm) 

Have a nice day!

like image 109
Auzias Avatar answered Sep 19 '22 11:09

Auzias


I think in theory this is possible for sure using the --privileged flag, as this thing gives you the ability to access all the hosts devices. If you install usbutils or similar ( depending on your images Distribution ) you'll see that the privileged container is able to see hotplugged devices when running lsusb. Unfortunately though they do not show up under /dev. Scripting the creation of those descriptors and have them properly handled by your software under /dev can become fairly involved unfortunately. It doesn't have to be that way for your devices though.

What you can do as a first attempt is to just create them using mknod. I tried this out with my HTC phone and it sort of worked ( details not relevant here ), simply check the line for the hotplugged device in lsusb:

Bus 003 Device 002: ID 0bb4:0f25 HTC (High Tech Computer Corp.) One M8 

go to the correct folder for the descriptor:

cd /dev/bus/usb/003 

check the major version for the usb driver in your kernel from the existing descriptors:

root@1a11f7c329a9:/dev/bus/usb/003# ls -la total 0 drwxr-xr-x 2 root root      160 Dec 26 13:40 . drwxr-xr-x 6 root root      120 Dec 26 13:30 .. crw-rw-r-- 1 root root 189, 256 Dec 26 13:30 001 crw-rw-r-- 1 root root 189, 258 Dec 26 13:30 003 crw-rw-r-- 1 root root 189, 259 Dec 26 13:30 004 crw-rw-r-- 1 root root 189, 260 Dec 26 13:30 005 crw-rw-r-- 1 root root 189, 261 Dec 26 13:30 006 

=> 189 :) => create the nod and while doing so use minor version 0.

mknod 002 c 189 0 

=> at least lsusb -v is now capable of opening the device. Same should work out for most hardware imo, with some exceptions.

What you could do as an alternative, though possibly slower but certainly safer and more in the spirit of Docker and containerization is to use containers for accessing your devices when you hot-mount them and then share the devices with the main container running your video app via socat tty via tcp.

Say you hotplug /dev/video0 on the host, you could spin up a new container that has this device mounted in that event. This container ( that has socat installed ) could run:

socat tcp-l:54321,reuseaddr,fork file:/dev/video0,nonblock,waitlock=/var/run/video0.lock 

Assuming this thing has the hostname video0-server you could now create the descriptor for video0 on the client via:

socat pty,link=/dev/video0,waitslave tcp:video0-server:54321 

Now you should be able to use the device just fine. For many devices the socat overhead should not be an issue I think. If scripting this via multiple containers that dynamically communicate with your main container via networking is an option and the performance is not affected in any meaningful way by the overhead too, the latter option is cleaner and safer than --privileged mode in my opinion.

like image 26
Armin Braun Avatar answered Sep 20 '22 11:09

Armin Braun