nunofgs / docker-octoprint

Dockerfile to set up Octoprint with x86, armv6, armv7 and arm64 support!
https://hub.docker.com/r/nunofgs/octoprint/
GNU Affero General Public License v3.0
58 stars 32 forks source link

Handling ephemeral serial device file #29

Closed rueckix closed 5 years ago

rueckix commented 5 years ago

When using udev on the docker host, the serial connection to the printer (/dev/ttyUSB0 in my case) is created on demand when the printer is switched on (connected) and it is deleted when the printer is switched off (disconnected).

Docker containers apparently cannot handle this. Neither via '--privileged' nor via '--device' because the character device does not exist upon container start.

Several solutions are described here. All require extra scripting or custom udev rules.

@nunofgs do you know of a different solution that will work best in the case of octoprint?

nunofgs commented 5 years ago

🤔 I've had that happen to me multiple times but honestly didn't spend the time to investigate. I simply restarted the container every time I unplugged/replugged my camera.

I'll play around a bit with this. If I get a working solution this would be a great addition to the image. Thanks!

rueckix commented 5 years ago

Oh, note that I was not talking about the camera but the printer.

I have a working solution in the meantime. It involves adding and removing ttyUSB0 (in the container) on demand, plus adding read/write/mknod privileges via cgroups.

1) container needs mknod via cap-add. Using --privileged is not required. Passing along a --device is also not required.

2) The host needs two scripts a) addDev.sh

#!/bin/ash

# assumes that only one container is running with that name
# get container ID
ID=$(docker ps --no-trunc -aqf "name=^octoprint_octoprint*")

# set cgroups permissions for accessing USB serial devices
echo 'c 188:* rwm' >  /sys/fs/cgroup/devices/docker/${ID}/devices.allow

#create USB device node
docker exec  octoprint_octoprint_1 mknod /dev/ttyUSB0 c 188 0

b) removeDev.sh

#!/bin/ash

docker exec  octoprint_octoprint_1 rm -f /dev/ttyUSB0

3) A custom udev rules file that will trigger those scripts upon plug/unplug events

ACTION=="add", SUBSYSTEM=="tty", KERNEL=="ttyUSB0", RUN+="path/to/addDev.sh"
ACTION=="remove", SUBSYSTEM=="tty", KERNEL=="ttyUSB0", RUN+="path/to/removeDev.sh"

It is working for my setup as of a few hours ago. Probably needs to be made more robust and generalized for others to work. I know that the cgroups part can be handled via docker compose v2.3 as well, but using portainer gui, I am confined to compose v2.

rueckix commented 5 years ago

Forgot to mention one limitation of my current setup. If the container restarts, /dev/ttyUSB0 is gone and you need to power cycle the printer to have it re-added by the udev rule.

nunofgs commented 5 years ago

I played around with this a bit but I can't seem to find a solution that doesn't depend on changing something in the host.

I'd really like to keep this image self-contained and hassle-free. I'll monitoring a few issues in the Docker issue tracker but doesn't seem like this will be fixed/supported any time soon, sorry :(

Closing for now but will reopen if something new comes up.

ModischFabrications commented 5 years ago

In case someone else is searching for this problem I fixed it with a workaround, I simply added the following segment to the docker-compose file.

    privileged: true
    # privileged needed because the printer USB connection slot
    # is created only *after* the image is started and PSU Control turns on.
    devices:
    - /dev/

It's not nice and certainly not secure to expose every /dev/ like that but it at least worked for me.