如何在Docker容器中运行的二进制程序操作GPIO?
我有一个简单的 Dockerfile
# syntax=docker/dockerfile:1
FROM oraclelinux:9
RUN useradd --home-dir /home/my_user --uid 1000 --create-home --shell /bin/bash my_user
USER my_user
WORKDIR /home/my_user
RUN mkdir -p /home/my_user/bin
COPY --chown=my_user --chmod=0755 gpio_test /home/my_user/bin/gpio_test
ENTRYPOINT ["tail", "-f", "/dev/null"]
其中 gpio_test 是一个简单的C 应用程序,作为我们CI/CD流水线的一部分进行编译,用来通过 /dev/port 设备操作GPIO引脚:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
const int DO_PORT = 0xA02;
const int DO7_BIT = 6;
int main(int argc, char** argv) {
if (argc < 2) {
printf("missing arg \n");
return -1;
}
int fd = open("/home/my_user/gpio/port", O_RDWR | O_NONBLOCK);
if (fd < 0) {
perror("failed to open port");
return -1;
}
char buff = 0;
lseek(fd, DO_PORT, SEEK_SET);
read(fd, &buff, 1);
printf("read byte: %d\n", (int)buff);
lseek(fd, DO_PORT, SEEK_SET);
if (strcmp(argv[1], "on") == 0) {
printf("on\n");
char val = buff & ~(1 << DO7_BIT);
write(fd, &val, 1);
} else if (strcmp(argv[1], "off") == 0) {
printf("off\n");
char val = buff | (1 << DO7_BIT);
write(fd, &val, 1);
} else {
printf("unsupported arg\n");
}
close(fd);
return 0;
}
如果我在主机上运行这个应用程序,之前给它原始IO能力:
sudo setcap cap_sys_rawio=ep gpio_test
那么我就可以在不需要 sudo 的情况下操作这些引脚,示例输出:
./gpio_test on
read byte: 64
on
然而,当我使用以下Docker compose文件运行我的容器时:
name: foo
services:
bar:
image: nameOfMyDockerImage:1
container_name: test
devices:
- /dev/port:/home/my_user/gpio/port
cap_add:
- SYS_RAWIO
接着在运行中的容器内部
sudo docker exec -it test bash
我得到 Operation not permitted 错误:
./bin/gpio_test on
failed to open port: Operation not permitted
有趣的是,如果我在主机上执行 sudo docker cp gpio_test test:/home/my_user/(此前在主机上对它调用了 setcap),那么我就可以在容器内成功运行它
./gpio_test off
read byte: 0
off
我应该怎么做,才能在运行中的Docker容器内,通过执行镜像中的某个二进制文件来操作主机的GPIO?
在主机上,我又创建了一个额外的udev规则,为相关的gpio文件赋予777的权限
ls -lah /dev/port
crwxrwxrwx 1 root kmem 1, 4 Mar 19 08:18 /dev/port
但这并没有帮助。
解决方案
在构建Docker镜像时,同样需要调用 setcap。为了让我它工作,需要满足的条件完整清单如下:
/dev/port文件需要具备读写权限,通过/etc/udev/rules.d/90-port-chmod.rules获得:KERNEL=="port", MODE="0777";注意777可能有些夸张- docker compose文件需要具备
SYS_RAWIO能力,设备映射是可以的 Dockerfile需要为目标二进制授予原始IO能力;另外如果该二进制链接到用户环境中指定的某些库LD_LIBRARY_PATH那就不再起作用,因此链接器必须进行全局配置
# syntax=docker/dockerfile:1
FROM oraclelinux:9
RUN useradd --home-dir /home/my_user --uid 1000 --create-home --shell /bin/bash my_user
USER my_user
WORKDIR /home/my_user
RUN mkdir -p /home/my_user/bin
COPY --chown=my_user --chmod=0755 gpio_test /home/my_user/bin/gpio_test
USER root
RUN setcap cap_sys_rawio=ep /home/my_user/bin/gpio_test
RUN echo "/home/my_user/lib/" > /etc/ld.so.conf.d/my_user_libs.conf && ldconfig
USER my_user
ENTRYPOINT ["tail", "-f", "/dev/null"]
现在在运行中的容器内调用 gpio_test 二进制文件,可以改变控制GPIO的 /dev/port 的状态。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。