Docker Django GPIO Rasbian buster

Viewed 759

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
1 Answers

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