# 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@*"
```