Docker - a way to give access to a host USB or serial device?

Last time I checked, Docker didn't have any means to give container access to host serial or USB port. Is there a trick which allows doing that?


Solution 1:

There are a couple of options. You can use the --device flag that use can use to access USB devices without --privileged mode:

docker run -t -i --device=/dev/ttyUSB0 ubuntu bash

Alternatively, assuming your USB device is available with drivers working, etc. on the host in /dev/bus/usb, you can mount this in the container using privileged mode and the volumes option. For example:

docker run -t -i --privileged -v /dev/bus/usb:/dev/bus/usb ubuntu bash

Note that as the name implies, --privileged is insecure and should be handled with care.

Solution 2:

With current versions of Docker, you can use the --device flag to achieve what you want, without needing to give access to all USB devices.

For example, if you wanted to make only /dev/ttyUSB0 accessible within your Docker container, you could do something like:

docker run -t -i --device=/dev/ttyUSB0 ubuntu bash

Solution 3:

--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.

See details here: Accessing USB Devices In Docker without using --privileged

It's a bit hard to paste, but in a nutshell, you need to get the major number for your character device and send that to cgroup:

189 is the major number of /dev/ttyUSB*, which you can get with 'ls -l'. It may be different on your system than on mine:

root@server:~# echo 'c 189:* rwm' > /sys/fs/cgroup/devices/docker/$A*/devices.allow  
(A contains the docker containerID)

Then start your container like this:

docker run -v /dev/bus:/dev/bus:ro -v /dev/serial:/dev/serial:ro -i -t --entrypoint /bin/bash debian:amd64

without doing this, any newly plugged or rebooting device after the container started, will get a new bus ID and will not be allowed access in the container.