非特権モードのDockerコンテナ上でRPi.GPIOを動かしたかった話
マシン: Raspberry Pi4
OS: Raspberry Pi OS(64bit)
ライブラリバージョン: RPi.GPIO 0.7.1
結論
- 動作にはDockerコンテナを特権モードで動作させる必要がある
- 非特権モードで実行したい場合は他のライブラリを検討した方が良い
- 例えば
gpiozeroなど
- 例えば
- ここから下の内容は調査した結果をまとめているだけであり、この先を読んでも問題は解決しない
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点あり、どちらかが成功すれば良い。
ただし、非特権モードのコンテナではどちらも成功しない。
/proc/device-tree/system/linux,revision: アクセスが禁じられているため非特権モードでは参照不可/proc/cpuinfo: /proc/cpuinfoの形式が変更されておりhardwareという文字列にマッチすることがないため条件文がTrueになることはない
ゆえに、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