Search code examples
dockerraspberry-pinode-redazure-iot-edge

Having trouble accessing /dev/serial0 on a Raspi from within a Module in Azure IoT Edge


I'm trying to set up a Module which will interact with /dev/serial0 on a Raspberry Pi B+ running Raspian Stretch. I've used dtoverlay=pi3-miniuart-bt in /boot/config.txtto restore UART0/ttyAMA0 to GPIOs 14 and 15 (which is what my Raspi-based HW needs me to do).

I have attempted to make that device accessible to the Module using the following Container Create Options:

{
  "HostConfig": {
    "PortBindings": {
      "1880/tcp": [
        {
          "HostPort": "1880"
        }
      ]
    },
    "Privileged": true,
    "Devices": [
      {
        "PathOnHost": "/dev/serial0",
        "PathInContainer": "/dev/serial0",
        "CgroupPermissions": "rwm"
      },
      {
        "PathOnHost": "/dev/ttyAMA0",
        "PathInContainer": "/dev/ttyAMA0",
        "CgroupPermissions": "rwm"
      },
      {
        "PathOnHost": "/dev/ttyS0",
        "PathInContainer": "/dev/ttyS0",
        "CgroupPermissions": "rwm"
      }
    ]
  }
}

I can see /dev/serial0 when I ssh in, but I can't see it from within the running Module:

pi@azure-iot-test:~ $ ls -l /dev/ser*
lrwxrwxrwx 1 root root 7 Sep 24 21:17 /dev/serial0 -> ttyAMA0
lrwxrwxrwx 1 root root 5 Sep 24 21:17 /dev/serial1 -> ttyS0
pi@azure-iot-test:~ $ sudo docker exec hub-nodered ls -l /dev/ser*
ls: /dev/serial0: No such file or directory
ls: /dev/serial1: No such file or directory

Any ideas?

Followup:

Additional things I have tried the following ideas gleaned from here:

  • Adding "User": "node-red" to the root of the Container Create Options
  • Adding "User": "root" to the root of the Container Create Options
  • Adding "GroupAdd": "dialout" to "HostConfig": {...} in the Container Create Options

Followup #2

While I still can't interact with /dev/serial0, I am able to interact with /dev/ttyAMA0 using the following Container Create Options:

{
  "HostConfig": {
    "GroupAdd": [
      "dialout"
    ],
    "PortBindings": {
      "1880/tcp": [
        {
          "HostPort": "80"
        }
      ]
    },
    "Devices": [
      {
        "PathOnHost": "/dev/serial0",
        "PathInContainer": "/dev/serial0",
        "CgroupPermissions": "rwm"
      },
      {
        "PathOnHost": "/dev/ttyAMA0",
        "PathInContainer": "/dev/ttyAMA0",
        "CgroupPermissions": "rwm"
      }
    ]
  }
}

The noteworthy items appear to be:

  • I didn't need "Privileged": true in "HostConfig"
  • I don't seem to need a "User" added
  • I needed "GroupAdd": ["dialout"] in "HostConfig"

So, while it's satisfying that I can interact with a serial device as I wanted to, it seems odd that I can't interact with /dev/serial0, which seems like it's "the recommended way" from the reading I've done.


Solution

  • Thanks to help and insight from Raymond Mouthaan over on the very helpful Node-RED Slack channel, I found my way to this Container Create Options providing me access to /dev/serial0:

    {
      "User": "node-red:dialout",
      "HostConfig": {
        "PortBindings": {
          "1880/tcp": [
            {
              "HostPort": "80"
            }
          ]
        },
        "Devices": [
          {
            "PathOnHost": "/dev/serial0",
            "PathInContainer": "/dev/serial0",
            "CgroupPermissions": "rwm"
          }
        ]
      }
    }
    

    This is different than the partial solution I found in "Followup #2" above in that I now do get access to /dev/serial0 as desired.

    UPDATE: I originally posted this answer using "User": "root:dialout" rather than the "User": "node-red:dialout" you currently see above.

    The first working solution was with "User": "root:root", but it seemed good to me to constrain to just the devices that are called out in Devices, which root:dialout seemed to do.

    But I wondered whether I should be concerned security-wise with running as root at all.

    Then I tried using node-red:dialout and it seems to be working perfectly, so I've updated the Container Create Options above to be what I think is the best answer.