Docker - a way to give access to a host USB or serial device?
I wanted to extend the answers already given to include support for dynamically connected devices that aren't captured with /dev/bus/usb
and how to get this working when using a Windows host along with the boot2docker VM.
If you are working with Windows, you'll need to add any USB rules for devices that you want Docker to access within the VirtualBox manager. To do this you can stop the VM by running:
host:~$ docker-machine stop default
Open the VirtualBox Manager and add USB support with filters as required.
Start the boot2docker VM:
host:~$ docker-machine start default
Since the USB devices are connected to the boot2docker VM, the commands need to be run from that machine. Open up a terminal with the VM and run the docker run command:
host:~$ docker-machine ssh
docker@default:~$ docker run -it --privileged ubuntu bash
Note, when the command is run like this, then only previously connected USB devices will be captures. The volumes flag is only required if you want this to work with devices connected after the container is started. In that case, you can use:
docker@default:~$ docker run -it --privileged -v /dev:/dev ubuntu bash
Note, I had to use /dev
instead of /dev/bus/usb
in some cases to capture a device like /dev/sg2
. I can only assume the same would be true for devices like /dev/ttyACM0
or /dev/ttyUSB0
.
The docker run commands will work with a Linux host as well.
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.
--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:
188 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 188:* 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.
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