Docker Community Forums

Share and learn in the Docker community.

How to run Docker rootless in a container?

Hi,

I was wondering if it’s possible to run docker rootless in a docker container? I’m not even sure if it’s possible.

I want to be able to run an ubuntu docker image in kubernetes via

docker run -i -t ubuntu /bin/bash

Then I execute the following trying to install it.

adduser dockerUser
su - dockerUser
$ curl -sSL https://get.docker.com/rootless | sh 
# Installing stable version 20.10.2
sh: 153: lsmod: not found
cat: /lib/modules/4.19.76-linuxkit/modules.builtin: No such file or directory
# Missing system requirements. Please run following commands to
# install the requirements and run this installer again.
# Alternatively iptables checks can be disabled with SKIP_IPTABLES=1
cat <<EOF | sudo sh -x
apt-get install -y uidmap
apt-get install -y iptables
modprobe ip_tables
EOF

The issue is you can’t install execute modprobe ip_tables since ip_tables does not exist. From my understanding ip_tables does not exist when you run it in a container like this.

Any help appreciated,
Thanks,
Derek

In order to run docker in docker you will typically use 2 containers:

  • one for the docker server
  • one for the client

Using the official images and the docker cli it will be something like that:

Start the server container in background :

docker run  --rm -d -v client-certs:/certs/client --privileged --name docker docker:dind-rootless

Start the client in foreground

docker run  --rm -it  --link docker -v client-certs:/certs/client --name client docker

Then using the client you can interact with the server:

/ # docker version
Client: Docker Engine - Community
 Version:           20.10.2
 API version:       1.41
 Go version:        go1.13.15
 Git commit:        2291f61
 Built:             Mon Dec 28 16:11:26 2020
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.2
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       8891c58
  Built:            Mon Dec 28 16:15:23 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.4.3
  GitCommit:        269548fa27e0089a8b8278fc4fc781d7f65a939b
 runc:
  Version:          1.0.0-rc92
  GitCommit:        ff819c7e9184c13b7c2607fe6c30ae19403a7aff
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
/ # 
/ # docker info
Client:
 Context:    default
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 20.10.2
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: false
 Logging Driver: json-file
 Cgroup Driver: none
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 269548fa27e0089a8b8278fc4fc781d7f65a939b
 runc version: ff819c7e9184c13b7c2607fe6c30ae19403a7aff
 init version: de40ad0
 Security Options:
  seccomp
   Profile: default
  rootless
 Kernel Version: 5.4.0-60-generic
 Operating System: Alpine Linux v3.12 (containerized)
 OSType: linux
 Architecture: x86_64
 CPUs: 8
 Total Memory: 15.62GiB
 Name: 9f6fa32c60fa
 ID: MABS:6BLZ:ZC6Z:KHIA:YFWT:CTNV:IJWU:MFOD:EEZQ:O4FW:GBMZ:HPIB
 Docker Root Dir: /home/rootless/.local/share/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false
 Product License: Community Engine

/ # 
/ # docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete 
Digest: sha256:31b9c7d48790f0d8c50ab433d9c3b7e17666d6993084c002c2ff1ca09b96391d
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

/ #

a lot of Linux features that Docker needs require privileged capabilities. So how does rootless mode work around that?
The key to the solution is to take advantage of user namespaces. User namespaces map a range of user ID-s so that the root user in the inner namespace maps to an unprivileged range in the parent namespace. A fresh process in user namespace also picks up a full set of process capabilities.
The user namespaces feature has been present in Docker for a long time with the --userns-remap flag that maps the users inside containers to a different range in the host, providing better security in the case where the container has access to the same external resources. The rootless mode works in a similar way, except we create a user namespace first and start the daemon already in the remapped namespace. The daemon and the containers will both use the same user namespace that is different from the host one.
Image for post
Although Linux allows creating user namespaces without extended privileges these namespaces only map a single user and therefore do not work with many current existing containers. To overcome that, rootless mode has a dependency on the uidmap package that can do the remapping of users for us. The binaries in uidmap package use setuid bit (or file capabilities) and therefore always run as root internally.
To make the launching of different namespaces and integration with uidmap simpler Akihiro created a project called rootlesskit. Rootlesskit also takes care of setting up networking for rootless containers. By default rootless docker uses networking based on moby/vpnkit project that is also used for networking in the Docker Desktop products. Alternatively, users can install slirp4netns and use that instead.
— -
We want to thank Akihiro Suda again for all the outstanding work he has done to make this feature happen. Make sure to also check out his Usernetes project that aims to provide Kubernetes support without requiring root.
If you find any undocumented issues or problems with the install script let us know in the issue trackers at https://github.com/moby/moby or https://github.com/docker/docker-install.