I have a containerized application for processing data from a sensor. The sensor has one of several possible serial-to-USB converters, each with their own path (/dev/path/to/deviceA
, etc.). I'd like the container to detect which converter is plugged in (and not tied to an existing container) and mount that one (without the user explicitly telling it). Only the mount path changes for different converters; the rest of the application behaves the same.
When starting the container, check each possible device mount to see if it finds a device at /dev/path/to/device
. Mount to the first one in the list found and ignore the rest. If no devices are found, build error. In other words,
if (/dev/path/to/deviceA exists and available) {
mount "/dev/path/to/deviceA:/dev/tty/USB0"
} else if (/dev/path/to/deviceB exists and available) {
mount "/dev/path/to/deviceB:/dev/tty/USB0"
} else if (...
...
} else { // No known devices are plugged in
fail to build
}
Current docker-compose.yml
has
devices:
- "/dev/path/to/deviceA:/dev/ttyUSB0"
- "/dev/path/to/deviceB:/dev/ttyUSB0"
- "/dev/path/to/deviceC:/dev/ttyUSB0"
However, my use case is for detecting one of several possible devices. In such a case, attempting to build the container gives error gathering device information while adding custom device
because deviceA
, deviceB
, and deviceC
are not all plugged in at the same time.
It seems like one possibility is to volume mount the entire /dev
directory:
If you want to allow the container to manage devices, you can use the volumes sestion and mount
/dev
and also add privileged: true or set proper capabilities.
but this is only a partial solution. How would I get it to "select" a correct device from the entire /dev
once it's mounted?
Another possibility might putting a path (according to the devices present) into an environment variable, then passing that variable to devices
. But when/how would one manipulate the environment variable before it is used with docker compose build name-of-service
/docker compose run name-of-service
?
Ubuntu 22.04 (host and container) (would like to be deployable to other OS's)
Client/Server: Docker Engine - Community Version: 27.3.1
Docker Compose version v2.29.7
Compose has no ability to run dynamic checks, and extremely limited ability to do any sort of conditional logic. The best you'll be able to do here is to use its environment-variable substitution to fill in the device path
devices:
- ${DEVICE_PATH}:/dev/ttyUSB0
You'll need some sort of script or program outside of Compose to detect this. I might write a shell script like
#!/bin/sh
is_device_available() {
# not a character-special device
if [ ! -c "$1" ]; then return 1; fi
# ... your logic here ...
return 0
}
for d in /dev/path/to/deviceA /dev/path/to/deviceB /dev/path/to/deviceC; do
if is_device_available "$d"; then
DEVICE_PATH="$d"
break
fi
done
if [ ! "$DEVICE_PATH" ]; then
echo could not detect a device
exit 1
fi
export DEVICE_PATH
exec "$@"
The end of this script will run the command it's given, so you could run it like
detect-device docker compose up
You could also use it to change the current shell's environment, like
. detect-device
docker compose up
Note that each time it's run it will try to detect devices again, and if running a container makes one of the devices be "in use" then it will change the device path, which will recreate the container.
detect-device docker-compose up -d
# If that makes the first device be "in use" then this will
# recreate the container on the second device
detect-device docker-compose up -d