非特権モードのDockerコンテナ上でRPi.GPIOを動かしたかった話

マシン: Raspberry Pi4
OS: Raspberry Pi OS(64bit)
ライブラリバージョン: RPi.GPIO 0.7.1

結論

Step1 特権モードで実行

docker runコマンド実行時に--privilegedオプションをつけて実行。この場合はコンテナ内からGPIOの読み書きができることを確認している。

Step2 権限を絞って実行→不可能

RPi.GPIOライブラリは/proc/device-tree/system/linux,revisionと/proc/device-treeの値を参照して、実行環境がRaspberry Piでない場合はエラーを出力して終了するような実装になっている。
Dockerの非特権モードの場合、/sys/firmware/**へのアクセスを禁止しているため、/proc/device-tree/**へのアクセスができない。

if ((fp = fopen("/proc/device-tree/system/linux,revision", "r"))) {
  uint32_t n;
  if (fread(&n, sizeof(n), 1, fp) != 1) {
     fclose(fp);
     return -1;
  }
  sprintf(revision, "%x", ntohl(n));
  found = 1;
} else if ((fp = fopen("/proc/cpuinfo", "r"))) {
  while(!feof(fp) && fgets(buffer, sizeof(buffer), fp)) {
     sscanf(buffer, "Hardware	: %s", hardware);
     if (strcmp(hardware, "BCM2708") == 0 ||
         strcmp(hardware, "BCM2709") == 0 ||
         strcmp(hardware, "BCM2711") == 0 ||
         strcmp(hardware, "BCM2835") == 0 ||
         strcmp(hardware, "BCM2836") == 0 ||
         strcmp(hardware, "BCM2837") == 0 ) {
        found = 1;
     }
     sscanf(buffer, "Revision	: %s", revision);
  }
}

引用: RPi.GPIO 0.7.1

RPi.GPIOが実行ハードウェアがRaspberry Piだと判断するために、確認しているファイルは2点あり、どちらかが成功すれば良い。
ただし、非特権モードのコンテナではどちらも成功しない。

ゆえに、RPi.GPIOを非特権モードで動作するDockerコンテナ上で動作させようとするのは諦めたほうが良さそうと結論付けた。

付録

検証で利用したDockerfileと起動コマンドは下記の通り。

FROM arm64v8/python:3.9.16-slim-bullseye

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN groupadd -g ${GPIO_GID} gpio
RUN usermod -aG gpio root

RUN apt-get update && apt-get install -y gcc build-essential
RUN pip install --upgrade pip && \
    pip install --no-cache-dir -r requirements.txt


COPY . .

ENV PYTHONUNBUFFERED 1
CMD ["/bin/bash"]
sudo docker run -it \
    --device /dev/mem:/dev/mem \
    --device /dev/gpiomem:/dev/gpiomem \
    --group-add $(getent group gpio | cut -d ":" -f 3) \
    -v /proc/device-tree:/proc/device-tree:ro \
    -v /sys/firmware/devicetree/base:/sys/firmware/devicetree/base:ro \
    -v /proc/cpuinfo:/proc/cpuinfo:ro \
    gpio:0.0.1