Search code examples
dockergpio

Docker Django GPIO Rasbian buster


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

Solution

  • 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)