I’m running this little project on my Raspberry Pi to control some GPIO pins of the Raspi. I’ve been doing so for years and recently, I started playing around with the new rootless .NET Docker images.
Unfortunately, I’m struggling with the permissions inside the Docker container - I simply have no write access to /dev/gpiomem.
Here’s what I tried:
Create new user app_raspi with UID 64200 on the host: sudo adduser --uid 64200 --disabled-password --no-create-home app_raspi
Add the newly created user app_raspi to the gpio group: sudo usermod -a -G gpio app_raspi
However, when starting my container with the newly created user, the underlying library of my project still cannot access the GPIO pins. So I checked the following things on the host:
So I started the container with bash as entrypoint: docker run -it --rm --user=64200 -v /dev/gpiomem:/dev/gpiomem --entrypoint /bin/bash mu88/raspifancontroller:latest
Here’s some output as well:
I have no name!@9218798747ed:/app$ whoami
whoami: cannot find name for user ID 64200
I have no name!@9218798747ed:/app$ id
uid=64200 gid=0(root) groups=0(root)
I have no name!@9218798747ed:/app$ test -r /dev/gpiomem; echo "$?"
1
I have no name!@9218798747ed:/app$ test -w /dev/gpiomem; echo "$?"
1
I have no name!@9218798747ed:/app$ test -r RaspiFanController.dll; echo "$?"
0
I have no name!@9218798747ed:/app$ test -x RaspiFanController.dll; echo "$?"
0
I have no name!@9218798747ed:/app$ ls -lh /dev/gpiomem
crw-rw---- 1 root 997 245, 0 Jan 6 11:00 /dev/gpiomem
I would have assumed that it should now work as app_raspi is a member of the gpio group on the host with r/w permissions and the container runs as 64200 - but I’m still missing something
That will not affect the container. That has a different database of groups and users. Only the IDs will be the same. Since gpiomem is a device, you could try --device /dev/gpiomem instead of bind mounting.
You could also try --priveleged or capabilities I wouldn’t change the permissions of a device file.
That’s how I used it before, but the guys from Microsoft recommended binding it as a volume. Anyhow, binding it as a device doesn’t change anything, the GPIO pins cannot be accessed.
Isn’t using --privileged similar to using a root user as before?
Privileged mode would allow the container to communicate with the kernel without restrictions so it is usually not recommended, but you can test it and if it works, then figure out which capability you need to set.
Thank you for sharing the GitJHub issue. Make sure you share it in your first post next time so we understand the history of the issue and what people already suggested…
Once again, setting group memberships on the host won’t help. You are running a process in a container. If the file has to be written by a specific group, that group has to be assigned to the user in the container. You can set groups similarly to setting a user id fo the container process. The username and the groupname don’t have to exist in the container. It is all about IDs.
docker run --group-add 997 ...
You could also add the group id after the user id, but that would completely override the group memberships in case the user actually existed in the container and was member of groups.
docker run --user 64200:997 ...
In your case , since the user is not the owner of the file, you don’t even need to create one. But if you create one, don’t do it on the host. That won’t help in the container. Create a user only if you know that some aplications want to refer to its name. Otherwise a name is basically useless.
You shared checking file permissions and you ran the “id” command as well, which clearly shows that the user in the container is not a member of any group excep the root group. That is because you defined only the user, but not the group.
Because you shared the GitHub issue, I also see how someone suggested using bind mounts instead of the device option. Note that a device is not a regular file and certainly not a folder as it was suggested on GitHub. Bind mounts are mainly for regular files and the device options was created for devices. One day I will have to check what that does exactly, but in your case the problem seems to be the lack of group membership in the container.
Wow, super impressive how quickly you found the solution - thank you very much! Now I can successfully control the GPIO pins again
This is my current docker-compose.yaml:
As you can see, I’m also mounting the volume /usr/bin/vcgencmd into the container. I need this tool to access the current temperature (see here).
Calling /usr/bin/vcgencmd measure_temp currently fails with the following error:
vcgencmd: error while loading shared libraries: libvchiq_arm.so.0: cannot open shared object file: No such file or directory
Some time ago, somebody helped me here. So I tried doing the same:
But when trying to start a container, bash cannot be started anymore:
myAdmin@myRaspi:~/Docker/RaspiFanController $ docker run -it --rm --user="64198:997" -v /usr/bin/vcgencmd:/usr/bin/vcgencmd -v /lib/aarch64-linux-gnu:/lib/aarch64-linux-gnu -e LD_LIBRARY_PATH=/lib/aarch64-linux-gnu --entrypoint /bin/bash mu88/raspifancontroller:latest
/bin/bash: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found (required by /bin/bash)
/bin/bash: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.36' not found (required by /bin/bash)
/bin/bash: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by /bin/bash)
As soon as I remove -v /lib/aarch64-linux-gnu:/lib/aarch64-linux-gnu -e LD_LIBRARY_PATH=/lib/aarch64-linux-gnu, it is working again, but without this volume binding I cannot test what’s missing to for vcgencmd.
Never mount a binary into a container. Binaries can have dependencies which won’t exist in the container and libraries can be different on each platform. For example Alpine uses “musl libc”. If you need a binary in a container, always install it properly in the container or make sure you built the binary for the target container.
I see, thx. That means that I have to switch back to a Dockerfile and install vcgencmd in there, right? Because some time ago (see here), I switched over to an (IMHO simpler) approach provided by Microsoft to build the image (AKA SDK Container Building Tools).
Yes. Mounting binaries are possible and sometimes even required when you build an image from scratch and there is no linux distribution in the container, but even then I wouldn’t mount something that was installed on the host, only files I built locally for the target architecture and distribution and I stored it in a local folder not in a system folder.