Introduction
Why rootless docker?
“Rootless” Docker refers to running Docker containers without granting the Docker daemon full root privileges on the host system. This can provide added security, as it reduces the potential attack surface and damage that could be caused by a malicious or compromised Docker daemon.
In normal Docker usage, the Docker daemon runs as the root user, which means it has complete access to the host system. While this is necessary for many Docker features and functionality, it can also represent a significant security risk, especially when running untrusted or unknown containers.
By using rootless Docker, you can reduce the level of privileged access that the Docker daemon has on your system, making it harder for attackers to exploit vulnerabilities in the Docker software or its containers.
It’s worth noting that some features and functionality may not be available in a rootless Docker setup, as they require full root access. However, for many users and use cases, rootless Docker provides a good balance between security and functionality.
In summary, the main difference between normal Docker and rootless Docker is the level of privileged access that the Docker daemon has on the host system. While normal Docker requires full root access, rootless Docker operates with reduced privileges for added security.
How to install
These instructions are for Linux. Similar instructions might exist for macOS. But certainly, Windows does not have a root concept, and I haven’t explored the Windows side of rootless docker. If you write a follow up post on Windows side, please left it in the comments section for other to view.
I am following these instructions on Ubuntu. If you are using the same, you might not be aware that docker command is provided by 2 different packages. One is from docker’s official repo which is available as docker-ce. Another one is from Debian’s official repository which is available as docker.io.
If you want to proceed, please uninstall docker.io if you are using it:
sudo apt remove docker docker-engine docker.io containerd runc
Install docker-ce. If you are already using docker-ce, you’re good to go:
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io
I am assuming that your docker service is running, stop them using the following command:
sudo systemctl disable --now docker.service docker.socket
There is one dependency that is remaining, it’s uidmap
. Do it like this:
sudo apt install uidmap
Now we are ready to do the final step:
curl -fsSL https://get.docker.com/rootless | sh
You can see the installation progressing, here is my log:
# Installing stable version 23.0.0
# Executing docker rootless install script, commit: 6647403
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 63.7M 100 63.7M 0 0 143M 0 --:--:-- --:--:-- --:--:-- 143M
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 19.1M 100 19.1M 0 0 85.1M 0 --:--:-- --:--:-- --:--:-- 85.4M
+ PATH=/home/ubuntu/bin:/home/ubuntu/.local/bin:/home/ubuntu/.vscode-server/bin/e2816fe719a4026ffa1ee0189dc89bdfdbafb164/bin/remote-cli:/home/ubuntu/.local/bin:/home/ubuntu/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin:/home/ubuntu/go/bin:/var/lib/snapd/snap/bin:/usr/local/go/bin:/home/ubuntu/go/bin:/var/lib/snapd/snap/bin:/usr/local/go/bin:/home/ubuntu/go/bin:/var/lib/snapd/snap/bin /home/ubuntu/bin/dockerd-rootless-setuptool.sh install
[INFO] Creating /home/ubuntu/.config/systemd/user/docker.service
[INFO] starting systemd service docker.service
+ systemctl --user start docker.service
+ sleep 3
+ systemctl --user --no-pager --full status docker.service
● docker.service - Docker Application Container Engine (Rootless)
Loaded: loaded (/home/ubuntu/.config/systemd/user/docker.service; disabled; vendor preset: enabled)
Active: active (running) since Sat 2023-02-11 10:27:47 UTC; 3s ago
Docs: https://docs.docker.com/go/rootless/
Main PID: 1523 (rootlesskit)
Tasks: 35
Memory: 31.3M
CPU: 535ms
CGroup: /user.slice/user-1000.slice/[email protected]/app.slice/docker.service
├─1523 rootlesskit --net=slirp4netns --mtu=65520 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run --propagation=rslave /home/ubuntu/bin/dockerd-rootless.sh
├─1532 /proc/self/exe --net=slirp4netns --mtu=65520 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run --propagation=rslave /home/ubuntu/bin/dockerd-rootless.sh
├─1546 slirp4netns --mtu 65520 -r 3 --disable-host-loopback --enable-sandbox --enable-seccomp 1532 tap0
├─1554 dockerd
└─1574 containerd --config /run/user/1000/docker/containerd/containerd.toml --log-level info
Feb 11 10:27:47 ip-10-2-1-39 dockerd-rootless.sh[1554]: time="2023-02-11T10:27:47.220314464Z" level=warning msg="WARNING: No io.max (wbps) support"
Feb 11 10:27:47 ip-10-2-1-39 dockerd-rootless.sh[1554]: time="2023-02-11T10:27:47.220323424Z" level=warning msg="WARNING: No io.max (riops) support"
Feb 11 10:27:47 ip-10-2-1-39 dockerd-rootless.sh[1554]: time="2023-02-11T10:27:47.220336374Z" level=warning msg="WARNING: No io.max (wiops) support"
Feb 11 10:27:47 ip-10-2-1-39 dockerd-rootless.sh[1554]: time="2023-02-11T10:27:47.220346775Z" level=warning msg="WARNING: bridge-nf-call-iptables is disabled"
Feb 11 10:27:47 ip-10-2-1-39 dockerd-rootless.sh[1554]: time="2023-02-11T10:27:47.220355915Z" level=warning msg="WARNING: bridge-nf-call-ip6tables is disabled"
Feb 11 10:27:47 ip-10-2-1-39 dockerd-rootless.sh[1554]: time="2023-02-11T10:27:47.220391885Z" level=info msg="Docker daemon" commit=d7573ab graphdriver=overlay2 version=23.0.0
Feb 11 10:27:47 ip-10-2-1-39 dockerd-rootless.sh[1554]: time="2023-02-11T10:27:47.220586509Z" level=info msg="Daemon has completed initialization"
Feb 11 10:27:47 ip-10-2-1-39 dockerd-rootless.sh[1554]: time="2023-02-11T10:27:47.261491765Z" level=info msg="[core] [Server #10] Server created" module=grpc
Feb 11 10:27:47 ip-10-2-1-39 systemd[919]: Started Docker Application Container Engine (Rootless).
Feb 11 10:27:47 ip-10-2-1-39 dockerd-rootless.sh[1554]: time="2023-02-11T10:27:47.269415389Z" level=info msg="API listen on /run/user/1000/docker.sock"
+ DOCKER_HOST=unix:///run/user/1000/docker.sock /home/ubuntu/bin/docker version
Client:
Version: 23.0.0
API version: 1.42
Go version: go1.19.5
Git commit: e92dd87
Built: Wed Feb 1 17:43:29 2023
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 23.0.0
API version: 1.42 (minimum version 1.12)
Go version: go1.19.5
Git commit: d7573ab
Built: Wed Feb 1 17:46:24 2023
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.6.16
GitCommit: 31aa4358a36870b21a992d3ad2bef29e1d693bec
runc:
Version: 1.1.4
GitCommit: v1.1.4-0-g5fd4c4d
docker-init:
Version: 0.19.0
GitCommit: de40ad0
rootlesskit:
Version: 1.1.0
ApiVersion: 1.1.1
NetworkDriver: slirp4netns
PortDriver: builtin
StateDir: /tmp/rootlesskit896353388
slirp4netns:
Version: 1.0.1
GitCommit: 6a7b16babc95b6a3056b33fb45b74a6f62262dd4
+ systemctl --user enable docker.service
Created symlink /home/ubuntu/.config/systemd/user/default.target.wants/docker.service → /home/ubuntu/.config/systemd/user/docker.service.
[INFO] Installed docker.service successfully.
[INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service`
[INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger ubuntu`
[INFO] Creating CLI context "rootless"
Successfully created context "rootless"
[INFO] Use CLI context "rootless"
Current context is now "rootless"
[INFO] Make sure the following environment variables are set (or add them to ~/.bashrc):
export PATH=/home/ubuntu/bin:$PATH
Some applications may require the following environment variable too:
export DOCKER_HOST=unix:///run/user/1000/docker.sock
We have finally installed docker. And what we have basically done is installed it on the user level.
At the end of the installation, you’ll be asked to stick some exports in your .bashrc. You need to do that in order to experience a flawless switch.
Things you should know
Start/Stop Container
To start or stop the docker daemon, you need same old systemctl command. But you’re going to pass --user
flag after the command.
systemctl --user stop docker
systemctl --user start docker
Connect from Client
There are a few ways you can interact with docker daemon.
The most common way is the command line way, another is docker desktop. There are also different SDKs available in different languages.
When you use rootful docker, you do not have to explicitly DOCKER_HOST
becuase it is already set. But after switching to rootless docker, you might need to specify this environment variable when you intend to connect to the host.
Value of this environment variable can be found by using this string:
unix://$XDG_RUNTIME_DIR/docker.sock
You may want to expand the XDG_RUNTIME_DIR
when you are trying to