3

I am a complete beginner at Docker, so please do easy on me.

I am trying to deploy a Django project in a Docker container on a Raspberry Pi 3B, but I am running into a problem accessing the GPIO ports.

Every time I try to initialise Docker with “sudo docker-compose up” I get the error: “RuntimeError: No access to /dev/mem. Try running as root!”

From what I have read, in order to get the Docker container to communicate with the GPIO ports the ‘user’ has to be a part of the ‘gpio’ group.

My questions are:

  1. How can make the user a member of the GPIO group from either the Docker file or the docker-compose.yml?
  2. Is there a better way of gaining access to the GPIO ports from Docker?

Docker File:

FROM python:3.8-alpine

ENV PATH="/scripts:${PATH}"

COPY ./requirements.txt /requirements.txt
RUN apk add --update --no-cache --virtual .tmp gcc libc-dev linux-headers
RUN pip install -r /requirements.txt
RUN pip install RPi.GPIO
RUN pip install apscheduler
RUN apk del .tmp

RUN mkdir /poolproject

COPY ./poolproject /poolproject
WORKDIR /poolproject
COPY ./scripts /scripts

RUN chmod +x /scripts/*

RUN mkdir -p /vol/web/media
RUN mkdir -p /vol/web/static

RUN adduser -D user
RUN chown -R user:user /vol

RUN chmod -R 755 /vol/web
USER user

CMD ["entrypoint.sh"]

docker-compose.yml

version: '3.7'

services:
  app:
    privileged: true
    build:
      context: .
    ports:
      - "8000:8000"
    volumes:
      - ./poolproject:/poolproject
    command: sh -c "python manage.py runserver 0.0.0.0:8000"
    environment:
      - DEBUG=1
Radial
  • 342
  • 1
  • 4
  • 14
  • Can you try adding `RUN addgroup user gpio` after `RUN chown -R user:user /vol` in the dockerfile? – Turing85 Sep 06 '20 at 15:57
  • In general programs running in Docker containers can't access host hardware devices. Can you run this program outside a container? – David Maze Sep 06 '20 at 16:11
  • Yes, I've tried adding RUN addgroup user gpio, but it returns: addgroup: unknown group gpio ERROR: Service 'app' failed to build: The command '/bin/sh -c addgroup user gpio' returned a non-zero code: 1 – Radial Sep 06 '20 at 19:55
  • David, the program is part pf a Django project and it works perfectly when run outside the container. – Radial Sep 06 '20 at 19:56

1 Answers1

3

I apologize; I've retracted my earlier answer because I missed the fact that you already have privileged: true in your docker-compose.yml. You have a different problem.

First, the error from RPi.GPIO is misleading: it doesn't really want access to /dev/mem; it wants access to /dev/gpiomem, which on the host has the following permissions:

pi@raspberrypi:~ $ ls -l /dev/gpiomem
crw-rw---- 1 root gpio 246, 0 Sep  7 09:02 /dev/gpiomem

Where the gpio group has gid 997:

pi@raspberrypi:~ $ getent group gpio
gpio:x:997:pi

That means we need to arrange for your web service to run with gid 997 inside your container. We can do that by adding the gpio group inside your Dockerfile, and then making your user a member of that group:

RUN addgroup -g 997 gpio
RUN adduser -D -G gpio user

With this change, I'm able to run some my test code without errors. Additionally, it is no longer necessary to enable privileged mode; we can replace privileged: true in the docker-compose.yml with a devices entry to expose just the /dev/gpiomem device.

Test environment

This is everything I used to test the situation.

This is my Dockerfile:

FROM python:3.8-alpine

RUN apk add --update --no-cache --virtual .tmp gcc libc-dev linux-headers
RUN pip install RPi.GPIO

RUN addgroup -g 997 gpio
RUN adduser -D -G gpio user

RUN mkdir -p /scripts
RUN chown -R user:gpio /scripts
COPY gpiotest.py /scripts/gpiotest.py
RUN chmod 755 /scripts/gpiotest.py

CMD python /scripts/gpiotest.py
USER user

This is my docker-compose.yml:

version: '3.7'

services:
  app:
    build:
      context: .
    devices:
      - /dev/gpiomem:/dev/gpiomem

This is my gpiotest.py script:

#!/usr/bin/python

import sys
import time

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)

while True:
    val = GPIO.input(17)
    print('value:', val)
    sys.stdout.flush()
    time.sleep(1)
larsks
  • 277,717
  • 41
  • 399
  • 399
  • Hi Larsks, many thanks for your detailed explanation. I am having trouble running your example. The "mkdir - p /scripts" does not create the directory and inevitably "docker-compile up" fails with an error. app_1 | python: can't open file '/scripts/gpiotest.py': [Errno 13] Permission denied docker-test_app_1 exited with code 2. – Radial Sep 07 '20 at 18:01
  • I can't envision a situation in which that `mkdir` would fail. If you want to pastebin somewhere the output of `docker-compose build --no-cache` (and I guess also the output of `docker-compose up`) I'd be happy to take a look. – larsks Sep 07 '20 at 19:33
  • Thank you again Larsks, here it is: https://pastebin.pl/view/b8f47c46 – Radial Sep 08 '20 at 05:18
  • I can't reproduce that problem on my Pi. What the result of running `docker-compose run app ls -ld /scripts /scripts/gpiotest.py`? Feel free to put the result in another pastebin, since it's not possible to put multi-line output in a comment. I would suggest we move this conversation to chat, but [that feature appears to be buggy](https://meta.stackexchange.com/questions/353966/unable-to-grant-access-to-a-chatroom-to-a-low-reputation-user-trying-to-move-a). – larsks Sep 08 '20 at 11:58
  • You should be able to use [this room if needed](https://chat.stackoverflow.com/rooms/221153/discussion-on-answer-by-larsks-docker-django-gpio-rasbian-buster). – Jon Clements Sep 08 '20 at 12:10
  • @user12231454 let's move this conversation over to the chat room that Jon has created; this way you can put output and config samples directly in the chat rather than using an external pastebin. – larsks Sep 08 '20 at 12:53
  • The issue was permissions on the `gpiotest.py` script. Adding an explicit `chmod` to the `Dockerfile` corrected the problem. – larsks Sep 08 '20 at 17:05
  • 1
    Larsks, just a quick note to thank you for all of your help, it is very much appreciated. – Radial Sep 09 '20 at 08:12
  • Doesn't work for me, I still get "RuntimeError: This module can only be run on a Raspberry Pi!". I checked the gid of gpio on the host, it's 997. – gucki Dec 06 '20 at 22:28
  • both of those parameters are yielding "... is ambiguous" – lys Nov 24 '21 at 16:23
  • Both of which parameters? – larsks Nov 24 '21 at 18:18