Running Docker on WSL2 without Docker Desktop (the right way)
Tags: docker, linux, windows, wsl
Published: 2021-10-15 13:53:41

So, now that Docker Desktop is paid under certain scenarios, you may want to switch to something else.

This is a straight to the point guide on how to make Docker CE run fully on WSL2.

PS: the title says _right way_, but it is just my personal opinion. I am not claiming that any other guide does it in a wrong way.

## What you will get

- A full-fledged Docker installation on WSL2
- Docker Daemon automatic start without any crazy hacks

## What you will not get

- Docker Daemon sharing between Windows and WSL (i.e. you cannot run docker from Windows PowerShell)
- Docker Daemon sharing between WSL distributions

## Requisites

I will consider that you already have WSL2 working, and you are using Ubuntu as your distribution.

## Guide

1. Install Docker CE on Ubuntu by following the [official guide](https://docs.docker.com/engine/install/ubuntu/):

   ```console
   # Ensures not older packages are installed
   $ sudo apt-get remove docker docker-engine docker.io containerd runc

   # Ensure pre-requisites are installed
   $ sudo apt-get update
   $ sudo apt-get install \
       ca-certificates \
       curl \
       gnupg \
       lsb-release

   # Adds docker apt key
   $ sudo mkdir -p /etc/apt/keyrings
   $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

   # Adds docker apt repository
   $ echo \
       "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
       $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

   # Refreshes apt repos
   $ sudo apt-get update

   # Installs Docker CE
   $ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
   ```

2. Perform the [post-installation steps](https://docs.docker.com/engine/install/linux-postinstall/):

   ```console
   # Ensures docker group exists
   $ sudo groupadd docker

   # Ensures you are part of it
   $ sudo usermod -aG docker $USER

   # Now, close your shell and open another for taking the group changes into account
   ```

3. Make Docker Daemon start on WSL initialization:

   First, make sure you are running a recent version of WSL2 (you can update with `wsl.exe --update`).

   Then, you only need to add:

   ```ini
   [boot]
   systemd=true
   ```

   To your `/etc/wsl.conf` within your WSL distribution.

   Then, restart it with `wsl.exe --shutdown`.

**To verify that docker works**, you can run `docker version`. If you do not receive any permission denied error, you are good to go.

You can also verify that Docker Compose got installed by running `docker compose version`.

## Bonus

1. Installing Docker Compose Switch (to use the legacy `docker-compose` command instead of `docker compose`):

   ```console
   # Finds the latest version
   $ switch_version=$(curl -fsSL -o /dev/null -w "%{url_effective}" https://github.com/docker/compose-switch/releases/latest | xargs basename)

   # Downloads the binary
   $ sudo curl -fL -o /usr/local/bin/docker-compose \
       "https://github.com/docker/compose-switch/releases/download/${switch_version}/docker-compose-linux-$(dpkg --print-architecture)"

   # Assigns execution permission to it
   $ sudo chmod +x /usr/local/bin/docker-compose
   ```

   PS: I suggest to install the `docker-compose` binary to `/usr/local/bin/` because otherwise, the _VS Code - Dev Containers_ extension will not find it.

   To verify it works, you can run `docker-compose version`.

2. Install the Docker Credential Helper:

   You will need this if you want Docker to store your credentials securely when you perform `docker login`. Thanks to the WSL interoperability between Windows, you can install the Windows version of the Docker Credential Helper inside of WSL itself.

   ```console
   # Finds the latest version
   $ wincred_version=$(curl -fsSL -o /dev/null -w "%{url_effective}" https://github.com/docker/docker-credential-helpers/releases/latest | xargs basename)

   # Downloads and extracts the .exe
   $ sudo curl -fL -o /usr/local/bin/docker-credential-wincred.exe \
       "https://github.com/docker/docker-credential-helpers/releases/download/${wincred_version}/docker-credential-wincred-${wincred_version}.windows-$(dpkg --print-architecture).exe"

   # Assigns execution permission to it
   $ sudo chmod +x /usr/local/bin/docker-credential-wincred.exe
   ```

   Then, configure your Docker CLI to use it by assuring that the following is present in your `~/.docker/config.json`:

   ```json
   {
     "credsStore": "wincred.exe"
   }
   ```

   To verify that it works, you can try to `docker login` and if not, Docker will complain about storing credentials in plain text.

## Final considerations

The entire setup process may take some time, but you will have achieved almost everything that Docker Desktop used to provide to you (by the way, I use [`k3d`](https://k3d.io/) as an alternative to Docker Desktop's built-in K8s provisioner).

However, you can achieve a similar (and even higher/better) level of easiness that Docker Desktop provided to you by wrapping all the steps above in your dotfiles installation steps.

For example, in my [dotfiles](https://github.com/felipecrs/dotfiles), all these steps are automated, including [configuring `/etc/docker/daemon.json`](https://github.com/felipecrs/dotfiles/blob/5a47ece0e9457e23ff51e605c2caded1c61da402/home/dot_docker/modify_config.json.tmpl), [changing `~/.profile`](https://github.com/felipecrs/dotfiles/blob/8974f2c741b6cb08295ecaaacb2b6c7c407312df/home/dot_profile.tmpl#L3-L8), and even providing a way to automatically update your extra binaries ([`docker-compose`](https://github.com/felipecrs/dotfiles/blob/f5cff904bc4669f8e77875c06fd72869e6635b04/root/.chezmoiexternal.yaml#L54-L57), or the [`wincred.exe`](https://github.com/felipecrs/dotfiles/blob/f5cff904bc4669f8e77875c06fd72869e6635b04/root/.chezmoiexternal.yaml#L60-L63)) every time you update your dotfiles (by using [a feature](https://www.chezmoi.io/docs/reference/#chezmoiexternalformat) of [chezmoi](https://www.chezmoi.io/) - a dotfiles manager which I totally recommend).