Accessing the GPU in rootless docker in docker on Jetson Orin Nano

This is a follow up question to this topic: "NvRmMemInitNvmap failed with Permission denied" error when running nvidia-docker in rootless mode on Jetson Orin Nano

Thanks to Nvidia’s support we are now able to access the GPU in a rootless docker container (running on a rootless user). However, for our very specific application we need to be able to access the GPU in rootless docker in docker.

To achieve this I created a docker image based on http://nvcr.io/nvidia/l4t-cuda:12.6.11-runtime and install docker and add the executable “deviceQuery” to check the availability of the GPU: create_nvidia_dind.zip (9.4 KB)

When running this image in rootful docker with “docker run --runtime=nvidia --mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock -it image_name”, I can then start a docker container inside the container using the same image with “docker run --runtime=nvidia -it image_name” and checking with “deviceQuery” shows that the GPU can be accessed in rootful docker in docker.

However, this does not work for rootless docker:
I start the outer container using “docker run -it --mount type=bind,src=/var/run/user/1001/docker.sock,dst=/var/run/docker.sock --rm --net=host --runtime nvidia --group-add=video --group-add=104 image_name” and can access the gpu in this container. However, when starting the docker container in the container (again using the same image) with “docker run --runtime=nvidia -it image_name”, the “deviceQuery” executable returns:
cudaGetDeviceCount returned 801
→ operation not supported
Result = FAIL

What configurations do I need to set in the outer docker container or how do I need to run the inner docker conainer, such that the GPU is accessible in rootless docker in docker?

Hi,

We need to discuss this internally.
Will provide more info to you shortly.

Thanks.

Hi,

Since running rootless docker inside docker is not a common usage we expect.
You will need to try it on your own.

Maybe other users can share their experience.
Thanks.

Hi,

We are going to test this issue internally.
Will provide more info with you later.

Thanks.

Hi,

Sorry for the late update.

We test your Dockerfile and it installs the default docker inside the rootless docker.

$ docker run -it --rm --runtime=nvidia -v /var/run/docker.sock:/var/run/docker.sock dind:latest 
..
root@c5327f106d29:/# docker info
Client: Docker Engine - Community
 Version:    28.2.2
 Context:    default
 Debug Mode: false

Suppose default docker requires more system permission compared to the rootless docker.
Could you try to install a rootless docker inside the rootless docker to see if it can work?

Thanks.

Hi!

I ran the following command:
$ docker run -it --rm --runtime=nvidia -v /var/run/user/1001/docker.sock:/var/run/docker.sock docker:latest

which gives me the following error:

Certificate request self-signature ok
subject=CN=docker:dind server
/certs/server/cert.pem: OK
Certificate request self-signature ok
subject=CN=docker:dind client
/certs/client/cert.pem: OK
cat: can’t open ‘/proc/net/arp_tables_names’: No such file or directory
ip: can’t find device ‘nf_tables’
modprobe: can’t change directory to ‘/lib/modules’: No such file or directory
ip: can’t find device ‘ip_tables’
ip_tables 32768 2 iptable_nat,iptable_filter
x_tables 45056 9 xt_conntrack,xt_MASQUERADE,ip6table_nat,ip6table_filter,ip6_tables,iptable_nat,xt_addrtype,iptable_filter,ip_tables
modprobe: can’t change directory to ‘/lib/modules’: No such file or directory
ip: can’t find device ‘ip6_tables’
ip6_tables 32768 2 ip6table_nat,ip6table_filter
x_tables 45056 9 xt_conntrack,xt_MASQUERADE,ip6table_nat,ip6table_filter,ip6_tables,iptable_nat,xt_addrtype,iptable_filter,ip_tables
modprobe: can’t change directory to ‘/lib/modules’: No such file or directory
iptables v1.8.11 (nf_tables)
mount: permission denied (are you root?)
Could not mount /sys/kernel/security.
AppArmor detection and --privileged mode might break.
mount: permission denied (are you root?)

So it cannot even start the container, not to mention accessing to the GPU. Note that we want to use the rootless docker, therefore I try to mount the rootless socket into the container.

Hi,

Do you install a rootless docker inside the container?
If so, could you share the Dockerfile with us to try?

The previous one used the standard docker.

Thanks.

True, I install standard Docker in the container. But rootless docker inside the container does not really make sense, as there is only a root user in the container.

Or do I misunderstand your point?

So the setup we aim for is: have a non-sudo user with a rootless docker engine installed, be able to mount the gpu inside a rootless docker container and be able to start a docker container insider the rootless docker container and mount the gpu into the container in the container. So we want to mount the gpu into a (rootful) docker container inside a rootless docker container.

Hi,

Thanks for your patience.

Sorry that we don’t have much experience with the dind use case so need to investigate further.
Will update more info with you once we have progress.

Thanks.

Let’s break down the problem with docker-in-docker a bit.

Build the following image:

docker build -t test-dind - <<EOF
FROM ubuntu

RUN apt-get update && \
    apt-get -y install ca-certificates curl && \
    install -m 0755 -d /etc/apt/keyrings && \
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc && \
    chmod a+r /etc/apt/keyrings/docker.asc

RUN echo \
    "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
    $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
    tee /etc/apt/sources.list.d/docker.list > /dev/null && \
    apt-get update

RUN apt-get -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
EOF

Start an outer docker-in-docker container using this image:

docker run --rm -d --name outer \
    --mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
    --runtime=nvidia \
    -e NVIDIA_VISIBLE_DEVICES=all \
        test-dind \
            sleep infinity
$ docker ps
CONTAINER ID   IMAGE       COMMAND            CREATED         STATUS         PORTS     NAMES
920fa4ede65c   test-dind   "sleep infinity"   3 seconds ago   Up 2 seconds             outer

Note that this same container is visible from the container itself.

$ docker exec -ti outer docker ps
CONTAINER ID   IMAGE       COMMAND            CREATED              STATUS              PORTS     NAMES
920fa4ede65c   test-dind   "sleep infinity"   About a minute ago   Up About a minute             outer

If we now start a new container in the outer container (note that we don’t mount the docker socket and we’re running a standard ubuntu container):

docker exec -ti outer \
    docker run --rm -d --name inner \
        --runtime=nvidia \
        -e NVIDIA_VISIBLE_DEVICES=all \
            ubuntu \
                sleep infinity

We see the following on the host:

$ docker ps
CONTAINER ID   IMAGE       COMMAND            CREATED         STATUS         PORTS     NAMES
a973c2e7ec22   ubuntu      "sleep infinity"   4 seconds ago   Up 3 seconds             inner
920fa4ede65c   test-dind   "sleep infinity"   3 minutes ago   Up 3 minutes             outer

and once again this is visible to the outer container:

$ docker exec -ti outer docker ps
CONTAINER ID   IMAGE       COMMAND            CREATED          STATUS          PORTS     NAMES
a973c2e7ec22   ubuntu      "sleep infinity"   53 seconds ago   Up 52 seconds             inner
920fa4ede65c   test-dind   "sleep infinity"   4 minutes ago    Up 4 minutes              outer

Note that even containers started on the host will be visible in the outer container:

$ docker run --rm -d --name external ubuntu sleep infinity
$ docker exec -ti outer docker ps
CONTAINER ID   IMAGE       COMMAND            CREATED         STATUS         PORTS     NAMES
d6b7bc11b5e2   ubuntu      "sleep infinity"   5 seconds ago   Up 4 seconds             external
a973c2e7ec22   ubuntu      "sleep infinity"   2 minutes ago   Up 2 minutes             inner
920fa4ede65c   test-dind   "sleep infinity"   5 minutes ago   Up 5 minutes             outer

This is to say, for the setup you’re describing, it is still the docker daemon on the host
that is running the inner container. Here I would expect the arguments that you pass to the
inner container to match the ones that you would pass on the host – although I
don’t have a definitive answer here in the rootless case.

What may be an option is to start the outer container WITHOUT injecting the
docker socket and then install docker in this container and start the docker
daemon there. (This is something similar to what kind does, but in the container
runtime that is installed is containerd specifically).

Note that at least the DEFAULT configuration requires a --privileged container:

docker run --privileged --rm -d --name outer \
    --runtime=nvidia \
    -e NVIDIA_VISIBLE_DEVICES=all \
        test-dind \
            dockerd

One can then start other containers in the outer container, but note that
in order to enable GPU support, the NVIDIA Container Toolkit needs to be installed
in this container. In the case of Tegra-based systems, the CSV files from
/etc/nvidia-container-runtime/host-files-for-container.d/ (or the whole folder)
would also need to be mounted into the outer container (or added through some other mechanism)
for device detection to work properly

Thank you for encouraging me to simple use the same arguments to start the inner container, against all odds this simply worked:

Using a rootless docker engine, the docker image I described at the beginning, starting the outer container using “docker run -it --mount type=bind,src=/var/run/user/1001/docker.sock,dst=/var/run/docker.sock --rm --net=host --runtime nvidia --group-add=video --group-add=104 image_name” and starting the inner container using “docker run -it --rm --net=host --runtime nvidia --group-add=video --group-add=104 image_name” I was able to access the GPU in the inner container.