I would like to be able to access an FTDI serial-to-usb bridge device plugged into a host computer from within a Docker container. From there, I am using a Python script with the pyusb and libusb libraries to process the USB output. That way, I can plug the FTDI board with its attached devices into some computer, run the docker container, and process the data. The container is built using docker-compose.
How we got here
As an earlier test on my host computer, I wrote the following Python script which will run at the start of my design:
import usb.core
import usb.util
# Find the USB device
device = usb.core.find(idVendor = 0x0403, idProduct = 0x601c)
# Check if the device was found. If not, raise an error. If the device was found, print out its info.
if (device == None):
raise ValueError('Device not found')
else:
print(device)
This printed out all the information on the board as expected - manufacturer, interfaces, endpoints, ect. (I was able to find the vendor and product IDs using lsusb -D /dev/bus/usb/003/007, where the numbers were the bus and device numbers given by lsusb).
I then went into my docker container in vscode, installed the two libraries, and ran the same script. This time, I got an error:
usb.core.NoBackendError: No backend available
I went to the pyusb FAQ at https://github.com/pyusb/pyusb/blob/master/docs/faq.rst
and made sure that I didn't have one of the common causes of the error. The error persisted even after I used usb.backend.libusb1.get_backend(...) to specify the backend library by hand.
I came to the realization that a root cause of the problem was that the docker container had no way to access the FTDI USB device in the first place. With a week's worth of experience in Docker, I think that I need to mount the USB device on my host computer to the container using
What has been tried
In my service in the docker-compose file, I've tried to specify the mounting location of the device using the following:
devices:
- "/dev/serial/by-id/<link>:/dev/ttyUSB0"
privileged: true
To find , I went into the /dev/serial/by-id/ directory and used dmesg | grep tty. It displayed a new entry whenever I plugged in a different USB device (Arduino), but did not have any new entries when I plugged in the FTDI board. Because of this, I doubt that my FTDI board is a TTY device, which most of the existing threads seem to focus around. I am not sure how else to give docker-compose what it needs to mount the device.
Because the pyusb library will find my device if it's given several USB devices, simply mounting all of the host USB ports should also solve my problem. I searched around this set of keywords as well, but didn't find much useful information.
TL:DR
How can I mount either an individual FTDI Serial-to-USB bridge device or all of the USB devices on my host computer to a docker container? I'd like to avoid using privileged if possible. I've been working with Ubuntu, Docker, and Python for about a week so I may need it spelled out. Let me know if any more information is needed.
Thanks!
Related
I am using Docker on Linux with a few USB-serial converters. It is possible to map them to the container using 'device', however when the device is not available during container start, the container does not start.
I was looking into other ways, to be able to use the device as "optional" (runtime detection is not required, but the container should work when the device is not present)
Then I discovered 'device_cgroup_rules' which works with a kind of udev rule. However in the examples I see, the whole /dev/ directory is exposed as volume to the container. From security point of view, this is a bad idea.
Is anyone aware of another solution ?
I'm using various docker containers which, under the covers are built on Debian sid. These images lack /dev/snd and /dev/snd/seq, which pretty much makes sense since they have no hardware audio card.
Several pieces of software I'm using to generate MIDI files require these sequencer devices to be present. They're not necessarily used to send out audio, but the code itself dies in init if the sound devices do not exist. To be clear, I don't need to generate an audio signal within docker, rather I just need these to exist to make other software happy.
So far, what I've tried is endlessly installing various alsa packages (alsa-utils, alsa-oss, and others) and trying to modprobe my way out of this, all with no luck.
Within a docker container, what needs to happen to have valid audio devices even if dummy?
I've had success getting sound through Docker (not the same problem, I know) by adding the devices whe running the container.
docker run -it --device /dev/snd myimage
The permissions can get challenging very quickly, you might want to try initially using --device /dev/snd along with --privileged and then dial back privileges little by little once it works.
I'm trying to build a distributed python application that connects several hosts with android devices over usb. These hosts then connect over TCP to a central broker for job disbursement. I'm currently tackling the problem of supporting multiple python builds for developers (linux/windows) as well as production (runs an older OS which requires it's own build of python). On the surface, docker seems like a good fit here as it would allow me to support a single python build.
However, docker doesn't seem suited well to working with external hardware. There is the --device option to pass a specific device, but that requires that the device be present before the docker run command and it doesn't persist across device reboots. I can get around that problem with --privileged but docker swarm currently does not support that (see issue 24862) so I'd have to manually setup the service on each of the hosts, which would not only be a pain, but I'd lose the niceness of swarm's automatic deployment and rollout.
Does anyone have any suggestions on how to make something like this work with docker, or am I just barking up the wrong tree here?
you can try developing on docker source code, and build docker from source code to support your requirement.
There is a hack, how to do that. In the end of this issue:
https://github.com/docker/swarmkit/issues/1244
Running on a Win7(host) and Virtual Box with Windows Server 2016 TP5(guest vm). On WS2016 i run docker, using the windowsservercore base image for the containers.
I'm trying out kind of a fleet management system where I try to fire up multiple simulated vehicles inside separate docker images.
These vehicle simulators uses a simulated gps which send data to a virtual com port, from which the simulated vehicles read.
In windows XP/7/Server 2016 I have successfully made use of com0com(2.2.2.0 signed) for creating the virtual com ports.
My problem is getting the virtual com ports installed inside a docker container, alternatively accessing them as devices on the host
My first attempt has been running com0com inside docker, installation of the drivers work fine using silent mode, but when creating virtual com port pairs using the installed application I run into problems. The command stalls and if I view the Application eventlog I can see a few rows of this kind for each time I try to run the command.
<date> <time> Information Windows Error Rep. .. 1001 Fault bucket , type 0
When instead trying to create the devices in the host and instead passing the devices I seem to fail to access them
Using com0com --list within the container I can see the devices but not with the same name as I in the host
In the associated Dockerfile I rename them using the com0com setupc.exe to the same name as identified on the host
The mode command issued on the host lists the ports properly, using the mode command from insde the container does on the other hand fail to list them, only showing one item: CON
I then tried passing them using the --device=//./COM128://./COM128 argument to docker run
NOTE!: Is this the correct "path" to the devices?
The noticable result of this is zero, the com0com setupc command gives the same result, same with mode
The strange thing is that when I run powershell and list the serialports i get the expected comports as available on the host, with the correct names, but trying to open one of them gives an exception
PS C:\sims\com0com> [System.IO.Ports.SerialPort]::getportnames()
COM128
COM129
PS C:\sims\com0com> $comports=[System.IO.Ports.SerialPort]::getportnames()
PS C:\sims\com0com> $port= new-Object System.IO.Ports.SerialPort $comports[0],9600,None,8,one
PS C:\sims\com0com> $port.open()
Exception calling "Open" with "0" argument(s): "The port 'COM128' does not exist."
Finally tried just about the same as above but with another virtual com port software(eltima), setting them up in the host, the final result when trying to open the port using ps in the container is the same as for the com0com configured ports
Update:
Tried a new approach, running the container in hyper-v instead, using the -isolation flag to docker run, given the thesis that you would be able to install the com0com drivers in a hyper-v container, not having to try to share them from the host.
Running in hyper-v forced us to change to running the nanoserver base image instead of the windowsservercore base image.
Currently stuck on not being able to run the com0com install tool in nanoserver since the installer(NSIS-based) is a 32bit application, nanoserver only able to run 64bit applications.
Quick glance indicates that a new version(3.0) of NSIS could be used along with the NSIS scripts included in the com0com repo.
All ideas on how to move forward are welcome!
P.S: Same question posted on msdn containers forum
Changed to using named pipes to get it to work since no one else seems to be using docker for windows with serial ports.
I use the following command to attach a disk to a running KVM virtual server:
virsh attach-disk vps_89 /dev/nbd31 --target vdc --driver tap
The disk is attached correctly. However, the disk is not attached as vdc inside the virtual server. I know the documentation says that the --target parameter is only giving a "hint" to the virtual server, but I can't really believe there is NO way to force the disk to be attached as a certain device (at least on Linux).
I am controlling my virtual servers through scripts and I must trust that the disk is attached to the exact device as I tell it to.
When I detach the disk using this:
virsh detach-disk vps_89 --target vdc
Then re-attaching the same disk again, the device-ID seems to be increamented each time, i.e vdc, vdd, vde, vdf etc... (totally ignoring my --target param)
Does anyone know a good (and reliable) way of attaching disks to KVM in a predictable way?
According to RedHat [1] and libvirt [2] this is not a bug, it's a feature:
The actual device name specified is not guaranteed to map to the
device name in the guest OS. Treat it as a device ordering hint.
The only available solution is to use UUID (/dev/disk/by-uuid/) for handling disk inside virtual machine.
https://bugzilla.redhat.com/show_bug.cgi?id=693372
http://libvirt.org/formatdomain.html