Based on your Dockerfile it seems you added the UID and GID at the build stage, not at the run stage. That should still work, but Dockerfile has a USER keyword you can use to specify/create a placeholder user and group. You don’t have to adduser/addgroup unless you need to chown some files in the image to the user/group.
You can probably remove all of this:
ARG uid
ARG gid
ARG gid_gpio
RUN groupadd -f -r -g $gid_gpio gpio
RUN groupadd -f -r -g 1000 user
# gpio needs to be main group, otherwise we get permission problems
RUN useradd -M --uid $uid -g $gid_gpio user --groups uucp,$gid,user \
&& echo 'user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/user \
&& echo 'Defaults exempt_group+=user' >> /etc/sudoers.d/user \
&& chmod a=r,o= /etc/sudoers.d/user
#RUN useradd -M --uid $uid --user-group user --groups uucp,$gid,$gid_gpio \
# && echo 'user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/user \
# && echo 'Defaults exempt_group+=user' >> /etc/sudoers.d/user \
# && chmod a=r,o= /etc/sudoers.d/user
Just build your image as root, if that’s necessary, and drop all caps with USER just before your entrypoint.
It may be your permissions error is because you aren’t mapping the parts of /sys that are needed, and --privileged gives access to everything, so it’ll work for sure (but perhaps also in ways you don’t want). You should only need to specify --group-add and mount the appropriate parts of /sys and /dev . Try this and see if it works (based on my reading of the udev rules):
docker run --rm -v /sys/class/gpio:/sys/class/gpio -v /sys/class/pwm:/sys/class/pwm --device /dev/spidev0.0:/dev/spidev0.0:rw --group-add $(cut -d: -f3 < <(getent group gpio)) yourimagenamehere
Note that I’ve never tried specifically to get gpio to work in Docker on the nano, but I have used this technique to access other devices on other platforms without using --privileged.