Slav Kirilov
Slav Kirilov

Reputation: 83

docker-compose devices map all devices from local to container

I have this docker-compose service that i am trying to make work.

  app:
    build: ./
    volumes:
      - .:/app:delegated
    devices:
      - ${DEVICE:-/dev/null}:-/dev/ttyUSB*

Response when running docker-compose up app

Error response from daemon: error gathering device information while adding custom device "/dev/ttyUSB*": no such file or directory

The idea here is to get all devices that match /dev/ttyUSB* from local and create them inside the container. This way i can have 0-N devices in the container, handling scenarios when no devices are connected. Also I do not have to know each device's tty<id>

I have read some old answers like this one : mapping all available devices in docker-compose but these either use

--privileged or do not answer the question of how to get (all | no devices) copied and accessible.

I am aware that:

app:
    build: ./
    volumes:
      - .:/app:delegated
    devices:
      - ${DEVICE:-/dev/null}:-/dev/ttyUSB0

works but not when the device is assigned a different number, hence the need to map them all.

Upvotes: 5

Views: 8572

Answers (2)

Slav Kirilov
Slav Kirilov

Reputation: 83

Actually with time i found another solution to the problem. If you want to have your devices mounted, without exactly knowing their names, you can use:

services:
  service:
    devices:
      - /dev:/dev

This simple solution allows all devices to be mounted but you would need to change their permissions beforehand or add privileged. Another fun part is that once you mount it if the device is disconnected, then you start your container and then connect the device, the container will not know about this device and you would need to restart for it to pick it up.

Upvotes: 2

rzlvmp
rzlvmp

Reputation: 9402

docker-compose able to read YAML from STDIN so just generate it on the fly.

Let's say that our original file is:

abc:
  container_name: abc
  image: alpine
  entrypoint: ["watch", "-n", "5", "ls"]

And devices are:

$ ls -l /dev/ttyS*
crw-rw-rw- 1 root root 4, 64 Nov 11 09:34 /dev/ttyS0
crw-rw-rw- 1 root root 4, 65 Nov 11 09:34 /dev/ttyS1
crw-rw-rw- 1 root root 4, 66 Nov 11 09:34 /dev/ttyS2
crw-rw-rw- 1 root root 4, 67 Nov 11 09:34 /dev/ttyS3

So, let's add these device to YAML:

$ printf '%s\n%s' "$(cat docker-compose.yml)" "$(if [ "$(ls /dev/ttyS*)x" != "x" ]; then echo -e "  devices:"; for D in /dev/ttyS*; do echo "    - ${D}:${D//ttyS/ttyUSB}"; done; fi )"

will print:

abc:
  container_name: abc
  image: alpine
  entrypoint: ["watch", "-n", "5", "ls"]
  devices:
    - /dev/ttyS0:/dev/ttyUSB0
    - /dev/ttyS1:/dev/ttyUSB1
    - /dev/ttyS2:/dev/ttyUSB2
    - /dev/ttyS3:/dev/ttyUSB3

Now let's try to run docker container using STDIN:

$ printf '%s\n%s' "$(cat docker-compose.yml)" "$(if [ "$(ls /dev/ttyS*)x" != "x" ]; then echo -e "  devices:"; for D in /dev/ttyS*; do echo "    - ${D}:${D//ttyS/ttyUSB}"; done; fi )" | docker-compose -f /dev/stdin -f docker-compose.yml up -d
Creating abc ... done

Let's attach to container and check devices:

$ docker exec -it abc sh
# ls -l /dev
...
crw-rw-rw-    1 root     root        4,  64 Nov 11 11:06 ttyUSB0
crw-rw-rw-    1 root     root        4,  65 Nov 11 11:06 ttyUSB1
crw-rw-rw-    1 root     root        4,  66 Nov 11 11:06 ttyUSB2
crw-rw-rw-    1 root     root        4,  67 Nov 11 11:06 ttyUSB3
...

Profit

Also, you can check this answer

Upvotes: 3

Related Questions