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.
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've got a docker container running a service, and I need that service to send logs to rsyslog. It's an ubuntu image running a set of services in the container. However, the rsyslog service cannot start inside this container. I cannot determine why.
Running service rsyslog start (this image uses upstart, not systemd) returns only the output start: Job failed to start. There is no further information provided, even when I use --verbose.
Furthermore, there are no error logs from this failed startup process. Because rsyslog is the service that can't start, it's obviously not running, so nothing is getting logged. I'm not finding anything relevant in Upstart's logs either: /var/log/upstart/ only contains the logs of a few things that successfully started, as well as dmesg.log which simply contains dmesg: klogctl failed: Operation not permitted. which from what I can tell is because of a docker limitation that cannot really be fixed. And it's unknown if this is even related to the issue.
Here's the interesting bit: I have the exact same container running on a different host, and it's not suffering from this issue. Rsyslog is able to start and run in the container just fine on that host. So obviously the cause is some difference between the hosts. But I don't know where to begin with that: There are LOTS of differences between the hosts (the working one is my local windows system, the failing one is a virtual machine running in a cloud environment), so I wouldn't know where to even begin about which differences could cause this issue and which ones couldn't.
I've exhausted everything that I know to check. My only option left is to come to stackoverflow and ask for any ideas.
Two questions here, really:
Is there any way to get more information out of the failure to start? start itself is a binary file, not a script, so I can't open it up and edit it. I'm reliant solely on the output of that command, and it's not logging anything anywhere useful.
What could possibly be different between these two hosts that could cause this issue? Are there any smoking guns or obvious candidates to check?
Regarding the container itself, unfortunately it's a container provided by a third party that I'm simply modifying. I can't really change anything fundamental about the container, such as the fact that it's entrypoint is /sbin/init (which is a very bad practice for docker containers, and is the root cause of all of my troubles). This is also causing some issues with the docker logging driver, which is why I'm stuck using syslog as the logging solution instead.
I wish to test code that may have trouble on file systems that do not support d_type.
In order to do so I would like to create two small xfs file systems that respectively have ftype=0 which does not support d_type, and ftype=1 which does.
I'd like to run these tests in a Docker container as that is how our testing is set up.
It looks like I might be able to take advantage of the Docker devicemapper https://docs.docker.com/storage/storagedriver/device-mapper-driver/ .
I do not necessarily control the Docker Engine, that is I don't want to rely on creating these filesystems on the underlying machine and then exposing them to my container - so I would want to be able to do this in my Dockerfile or one I am running in the container.
But maybe there are other or better ways to do this.
I'm not sure this is a complete answer but hopefully a step towards it.
I am trying to do something similar. I want to do some tests using at least xfs, tmpfs & sshfs. I was hoping to find a fuse solution to emulate xfs as well.
You could definitely put a tmpfs, fuse-sshfs and even nfs inside a docker.
I have no experience with nbd but I think you could it within docker to provide xfs via a loopback device. See this blog for example.
This might not be necessary though as you can mount an image as a partition E.g.
mount -t <fs type> -o loop file.img /mnt
Assuming this works in docker we have our solution. I haven't tried this myself yet. If you get there first please post your solution
(perhaps you did as this question is a year old).
See also Emulate a hard drive in Linux
Otherwise vagrant is probably good solution for this kind of problem.
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 have experimented with packaging my site-deployment script in a Docker container. The idea is that my services will all be inside containers and then using the special management container to manage the other containers.
The idea is that my host machine should be as dumb as absolutely possible (currently I use CoreOS with the only state being a systemd config starting my management container).
The management container be used as a push target for creating new containers based on the source code I send to it (using SSH, I think, at least that is what I use now). The script also manages persistent data (database files, logs and so on) in a separate container and manages back-ups for it, so that I can tear down and rebuild everything without ever touching any data. To accomplish this I forward the Docker Unix socket using the -v option when starting the management container.
Is this a good or a bad idea? Can I run into problems by doing this? I did not read anywhere that it is discouraged, but I also did not find a lot of examples of others doing this.
This is totally OK, and you're not the only one to do it :-)
Another example of use is to use the management container to hande authentication for the Docker REST API. It would accept connections on an EXPOSE'd TCP port, itself published with -p, and proxy requests to the UNIX socket.
As this question is still of relevance today, I want to answer with a bit more detail:
It is possible to work with this setup, where you pass the docker socket into a running container. This is done by many solutions and works well. BUT you have to think about the problems, that come with this:
If you want to use the socket, you have to be root inside the container. This allows the execution of any command inside the container. So for example if an intruder controlls this container, he controls all other docker containers.
If you expose the socket with a TCP Port as sugested by jpetzzo, you will have the same problem even worse, because now you won't even have to compromise the container but just the network. If you filter the connections (like sugested in his comment) the first problem stays.
TLDR;
You could do this and it will work, but then you have to think about security for a bit.