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.
Related
TD;DR
I would like to know if there is a way to get AP_NETLINK/NETLINK_KOBJECT_UEVENT messages in a docker container without using --net host. So I can make libusb hotplug feature to work...
Partially answer, read Edit 1 and Edit 2
I am trying to dockerize an app (DSView) which uses libusb to detect when a device is connected. It uses the libusb hotplug capabilities to do so.
After analyse libusb code I can see that, on Linux, the hotplug capabilities are based on libudev monitors, which relies on AP_NETLINK/NETLINK_KOBJECT_UEVENT messages coming from the kernel to detect new USB devices connections.
I have read other post suggesting to run docker with this:
--net host -v /run/udev/control:/run/udev/control
This works perfectly, the problem is this creates a lot of security concerns.
After a deeper inspection of libudev monitors implementation, I can say that -v /run/udev/control:/run/udev/control is not needed since libudev monitors doesn't use that socket at all. libudev only check if that file is accessible, which means I can just do -v $HOME/dummy:/run/udev/control or even create an empty /run/udev/control file in the container to bypass this check.
On the other hand --net host is required to keep the container in the same namespace than the host (main namespace). This is required because AP_NETLINK/NETLINK_KOBJECT_UEVENT messages are only send to the main namespace (← WRONG!!!) probably is a udev requirement.
Again this is far from being ideal because by adding --net host we are presenting all host network resources to the container.
I was considering to patch libusb to add NETLINK_LISTEN_ALL_NSID option to the socket used by the libudev monitor (udev_monitor.monitor.sock) but I would like to know if there is any easier way to get AP_NETLINK/NETLINK_KOBJECT_UEVENT messages in all namespaces (← Not needed, see Edit 1).
PS: -v /run/udev/control:/run/udev/control would be required in case we want to control host udev from the container (reset,add rules?, etc) which looks not that much safe at all.
PS2: In case you are curious this is the project github
EDIT 1: I have written a proof of concept reading the netlink socket directly and my surprise was that I can see AP_NETLINK/NETLINK_KOBJECT_UEVENT messages in the container without adding NETLINK_LISTEN_ALL_NSID and without --net host.
EDIT 2: Ok I manage to find a work around to my problem. I have compiled libusb without udev support (../configure --disable-udev) and now DSView works.
It looks like udev doesn't play nice with docker. Reading libudev code I can see that there is plenty of staff preventing you to run it on a container but I really cannot see which part prevent libudev to show up the hotplug event on the monitor and/or why it does that when using the host network....
I say that this is partially answer because I would like to know why.
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!
Suppose I have a docker application (such as this one). The standard usage is using the CLI to run docker run, in this case, for macOS users it would be:
docker run -it --rm bigdeddu/nyxt:2.2.1
Now, I would like to produce an app bundle or something so that users can double click to launch this docker application as a desktop application. It would be kind of a GUI shortcut to launch docker.
How can I achieve that?
1 - Is there a solution already done for it? If so, which one?
2 - If there is not a solution already done for it, what would be a rough sketch on how to build one?
Thanks!
Docker was designed to encapsulate server processes. For servers, the CLI is a reasonable and often satisfactory interface.
If you want users to run their possibly interactive application, you may want to look for https://appimage.org/. Although I am unsure whether that is available for MacOS.
To get around these limitations, you could either think of creating an end user targeting GUI for docker, or an implementation of AppImage for MacOS.
I use jack to route audio between multiple sound cards in my pc.
To record the audio i use a very convenient FFmpeg command which creates a writable jack client:
ffmpeg -f jack -i <client_name> -strict -2 -y <output_file_name>.
so far this works very well.
The problem starts here:
I also have an nginx docker which records my data and makes it available for streaming. when trying to use the same command inside the docker i get the following error:"Unable to register as a JACK client".
I started to look in to the FFmpeg code and found out that the FFmpeg command calls the jack_client_open command from the jack API, which fails.
Seems like there is some kind of a problem in the connection between the FFmpeg request from inside the docker to the jackd server running on the host.
Is there a simple way to create a connection between the two [exposing ports]?
(I saw some solutions like netjack2, but before creating a more complex server-client architecture i'd like to find a more elegant solution).
Thanks for the help!
I've just got this working, and I required the following in my docker run commands:
--volume=/dev/shm:/dev/shm:rw
--user=1000
So that the container is running a user which can access files in /dev/shm from a jackd spawned from my host user account. This wouldn't be required if your jackd and the container are both running as user root.
You can confirm its working by running jack_simple_client in the container, you should get a beep.
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