# Setup Docker Engine in WSL 2 On Windows, **Docker Desktop** is too bloated, memory hoggy and slow. Let's install **Docker Engine** directly in WSL 2 instead! 1. Modify the following configuration files to add the indicated entries. * `%USERPROFILE%/.wslconfig` Use cgroup v2 only by disabling cgroup v1 entirely. ``` [wsl2] kernelCommandLine=cgroup_no_v1=all systemd.unified_cgroup_hierarchy=1 ``` * `/etc/wsl.conf` Enable systemd. ``` [boot] systemd=true ``` [Advanced settings configuration in WSL](https://learn.microsoft.com/en-us/windows/wsl/wsl-config) [cgroups(7) - Linux manual page](https://man7.org/linux/man-pages/man7/cgroups.7.html) 2. Install Docker from its official `apt` repository. These steps are all excerpted from the [official documents](https://docs.docker.com/engine/install/debian). They are concentrated here for my own convenience. * Configure package repository. ```bash # For Debian sudo curl -fsSL "https://download.docker.com/linux/debian/gpg" -o /etc/apt/keyrings/docker.asc echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # For Ubuntu sudo curl -fsSL "https://download.docker.com/linux/ubuntu/gpg" -o /etc/apt/keyrings/docker.asc echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null ``` * Install Docker. ```bash sudo apt update sudo apt install -y dbus-user-session uidmap sudo apt install -y docker-ce docker-ce-cli docker-ce-rootless-extras containerd.io docker-buildx-plugin docker-compose-plugin # Install the latest version of `fuse-overlayfs` # Repository version is very old sudo wget "https://github.com/containers/fuse-overlayfs/releases/latest/download/fuse-overlayfs-$(uname -m)" -O /usr/bin/fuse-overlayfs sudo chmod 0755 /usr/bin/fuse-overlayfs # Install the latest version of `slirp4netns` # Repository version is very old and see notes below sudo wget "https://github.com/rootless-containers/slirp4netns/releases/latest/download/slirp4netns-$(uname -m)" -O /usr/bin/slirp4netns sudo chmod 0755 /usr/bin/slirp4netns ``` Notes: In WSL 2, `/etc/resolv.conf` is a symbolic link to `/mnt/wsl/resolv.conf`, which is automatically generated. This default behavior breaks DNS for `slirp4netns`, which rootless Docker relies on for container networking. The [manual page](https://github.com/rootless-containers/slirp4netns/blob/master/slirp4netns.1.md) of `slirp4netns` actually explicitly states that: > `--enable-sandbox` (since v0.4.0) enter the user namespace and create a new mount namespace where only `/etc` and `/run` are mounted from the host. > > Requires `/etc/resolv.conf` **not** to be a symlink to a file outside `/etc` and `/run`. The proper solution is to update `slirp4netns` to version [1.2.1](https://github.com/rootless-containers/slirp4netns/releases/tag/v1.2.1) or later, where this bug is [fixed](https://github.com/rootless-containers/slirp4netns/pull/318). Another possible workaround is to disable automatic generation of `/etc/resolv.conf` and write it manually. * Enable and start Docker services. ```bash sudo systemctl enable --now containerd.service sudo systemctl enable --now docker.service ``` 3. Configure rootless Docker for better security. Samely, these steps are all excerpted from the [official documents](https://docs.docker.com/engine/security/rootless). They are concentrated here for my own convenience. ```bash sudo systemctl restart "user@*" dockerd-rootless-setuptool.sh install --skip-iptables # Allow automatic startup sudo loginctl enable-linger "$(whoami)" # Allow binding privileged ports sudo setcap cap_net_bind_service=ep "$(which rootlesskit)" systemctl --user restart docker ``` 4. Confirm Docker is running in rootless mode. ```bash docker info ``` 5. (WORKAROUND) If WSL 2 is previously shutdown (e.g., due to timeout, `wsl --shutdown`, etc.), the systemd user instance may have to be restarted before rootless Docker works again. ```bash sudo systemctl restart "user@*" ```