How to create tun interface inside Docker container image?

14.6k Views Asked by At

I'm trying to create a Docker image with a /dev/net/tun device so that the image can be used across Linux, Mac and Windows host machines. The device does not need access to the host's network interface.

Note that passing --device /dev/net/tun:/dev/net/tun to docker run is undesirable because this only works on Linux.

Once the container is started, I can manually add the device by running:

$ sudo mkdir /dev/net
$ sudo mknod /dev/net/tun c 10 200
$ sudo ip tuntap add mode tap tap

but when I add these lines to the Dockerfile it results in an error:

Step 35/46 : RUN mkdir /dev/net
 ---> Running in 5475f2e4b778
Removing intermediate container 5475f2e4b778
 ---> c6f8e2998e1a
Step 36/46 : RUN mknod /dev/net/tun c 10 200
 ---> Running in fdb0ed813cdb
mknod: /dev/net/tun: No such file or directory
The command '/bin/sh -c mknod /dev/net/tun c 10 200' returned a non-zero code: 1

I believe the crux here is creating a filesystem node from within a docker build step? Is this possible?

2

There are 2 best solutions below

0
On

I managed to work around this by programmatically creating the TUN device in our software that needs it (which are mostly unit tests). In the setup of the program we can create a temporary file node with major/minor code 10/200:

        // Create a random temporary filename. We are not using tmpfile() or the
        // usual suspects because we need to create the temp file using mknod(),
        // below.
        snprintf(tmp_filename_, IFNAMSIZ, "/tmp/ect_%d_%d", rand(), rand());

        // Create a temporary file node for use as a TUN interface.
        // Device 10, 200 is the device code for a TAP/TUN device.
        // See https://www.kernel.org/doc/Documentation/admin-guide/devices.txt
        int result = mknod(tmp_filename_, S_IFCHR | 0644, makedev(10, 200));
        if (result < 0) {
            perror("Failed to make temporary file");
        }
        ASSERT_GE(result, 0);

and then in the tear-down of the program we close and delete the temporary file.

One issue remaining is this program only works when run as the root user because the program doesn't have cap_net_admin,cap_net_raw capabilities. Another annoyance that can be worked-around.

0
On

The /dev directory is special, and Docker build steps cannot really put anything there. That also is mentioned in an answer to question 56346114.

Apparently a device in /dev isn't a file with data in it, but a placeholder, an address, a pointer, a link to driver code in memory that does something when accessed. Such driver code in memory is not something that a Docker image would hold.

I got device creation working in a container by putting your command line code in an .sh script wrapping the app we really want to run.