Expose USB dongle to Docker container

Just making the first steps toward setting-up Home assistant on my home network. So far I managed to install HA in a Docker container, though this setup does not automatically detect my Zigbee dongle. I’ve thus been instructed to “pass-through” the dongle to the Docker container. I have instructions on how to do that using docker-container, but my current setup does not run docker-container, as the containers-basic bundle does not include docker-container. Surely enough, I could simply add the docker container bundle, but I’d be much happier if I could avoid having to fiddle with that at this point. As such, I’d very much appreciate some advice as to how to do the “pass-through” of the dongle w/o having to change the setup to docker-container. At this point in time, the Docker daemon is being governed by a systemd service that looks like this below, and methinks that tweaking the ExecStart line might achieve the coveted “pass-through.”

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target docker.socket firewalld.service containerd.service time-set.target
Wants=network-online.target containerd.service
Requires=docker.socket

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always

# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
# Both the old, and new location are accepted by systemd 229 and up, so using the old location
# to make them work for either version of systemd.
StartLimitBurst=3

# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
# this option work for either version of systemd.
StartLimitInterval=60s

# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity

# Comment TasksMax if your systemd version does not support it.
# Only systemd 226 and above support this option.
TasksMax=infinity

# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes

# kill only the docker process, not all processes in the cgroup
KillMode=process
OOMScoreAdjust=-500

[Install]
WantedBy=multi-user.target

find the device id :

ls /dev/serial/by-id/

replace device_id with yours :

docker run -d --name home-assistant --device=/dev/serial/by-id/device_id
docker stop home-assistant
docker start home-assistant

or

sudo systemctl daemon-reload
1 Like

Thanks! Apparently, however, dockerd doesn’t know the --device flag:

Mar 03 18:31:22 MiFiCommander dockerd[103658]: Status: unknown flag: --device

Indeed, I have not been able to find this flag anywhere here.

I’ll try the pure docker solution now, and report back.

Normally, you create or edit :

/etc/udev/rules.d/99-my-device.rules

Then add a rule for a symlink to your device (change vendor and product ID) :

SUBSYSTEM=="tty", ATTRS{idVendor}=="VENDOR_ID", ATTRS{idProduct}=="PRODUCT_ID", SYMLINK+="my_device", MODE="0666"
sudo udevadm control --reload-rules
sudo udevadm trigger

After creating the udev rule, you can access the device inside all your containers using :

/dev/my_device

1 Like

Thanks:

  1. Should I understand that there is no way this can be done just by tweaking the ExecStart=/usr/bin/dockerd line in the .service file?
  2. Also, assuming that I resort to explicitly running the docker run command as above, should I not disable docker.service first? Wouldn’t allowing both of these lead to having two redundant home-assistane containers active? As far as I understand, the ExecStart=/usr/bin/dockerd line in the .service file has two goals: start the Docker daemon, and launch the home-assistant container: I only want the former action to happen, though not the latter, as the latter would have been supplanted by explicitly starting docker via the docker run command.

If you only want the Docker daemon to start and not automatically launch the Home Assistant container, you can modify the ExecStart line in /etc/systemd/system/docker.service to keep it from automatically starting the Home Assistant container.

sudo nano /etc/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --exec-opt native.cgroupdriver=systemd
sudo systemctl daemon-reload
sudo systemctl restart docker.service
1 Like

@Aqua1ung what do you try to do, I would say the daemon itself just need to have permissions to be able to access the device (which it most likely has)

I run this specific docker under an other linux, but its the docker or in my case docker-compose which needs the device mapping.
I do not recall that I needed to do any changes on the service or udev, but sure, you want to make sure
no other process tries to use your device and that docker and your containers auto start if you want them to.

In my case its a Dresden Elektrik Zigbee stick and I run it with a dedicated deconz container.
I map the /dev/ttyACM0 directly, but possibly the link might work as well, anyhow you would find the device

# ls -la /dev/serial/by-id/usb-dresden_elektronik_ingenieurtechnik_GmbH_ConBee_II_XXNNNNNN-zzzz 
lrwxrwxrwx 1 root root 13 Dec 29 00:32 /dev/serial/by-id/usb-dresden_elektronik_ingenieurtechnik_GmbH_ConBee_II_XXNNNNNNzzzz -> ../../ttyACM0

sniplet from the docker-compose.yaml

...
    devices:
      - /dev/ttyACM0:/dev/ttyACM0
    environment:
      - DECONZ_DEVICE=/dev/ttyACM0
...
1 Like

Alright, so let me summarize the “situation”: if you want to pass through a USB device to a Docker container, you will have to do either of the following:

  • run your container using the docker run --device command as shown here or here,
  • create a udev rule, as shown here,
  • use docker-compose (which will have to be installed separately) and whip up a docker-compose.yaml file, as shown here.

Many thanks for your inputs, guys!

3 Likes