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
- Install Docker CE on Ubuntu by following the official guide:
# 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
- Perform the post-installation steps:
# 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
- 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:
[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
- Installing Docker Compose Switch (to use the legacy
docker-compose
command instead ofdocker compose
):
# 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
.
- 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.
# 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
:
{
"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
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, all these steps are automated, including configuring /etc/docker/daemon.json
, changing ~/.profile
, and even providing a way to automatically update your extra binaries (docker-compose
, or the wincred.exe
) every time you update your dotfiles (by using a feature of chezmoi - a dotfiles manager which I totally recommend).
Latest comments (39)
Docker not starting in wsl2 arm machine. Getting Iptables related issues.
ERROR:
Unable to detect if iptables supports xlock: 'iptables --wait -L -n ': 'iptables v1.8.7 (legacy): can't initialize iptables table 'filter': Table does not exist (do you need to insmod?)
I have tried the switching from iptables-nft to iptables-legacy as well but still seeing the same issue can someone help please.
Very good guide, thank you very much. It solved our issue.
Note that if wsl2 is set to
networkingMode=mirrored
, you will might run into issues trying to connect to the container from your Windows host (on the same local machine). Connecting from other host within the network worked but ymmv depending on your setup. A workaround from on gist.github.com/shigenobuokamoto/b... and github.com/microsoft/WSL/issues/10... finally addressed the issue for me.Create a new file as root
/etc/systemd/system/network-mirrored.service
When you have created the file, run it by
$ sudo systemctl --now enable network-mirrored
. This may or may not resolve the issue. If it doesn't, add the following to your ** .wslconfig**, the one found in **Windows **host, not the Linux distro (wsl.config).So that your full file could look something like this:
Reboot your wsl2 instance from powershell and open a new wsl2 instance:
Hi Felipe,
Thanks for the article, I am on ubuntu 22 I am able to start docker but unable to pull images from docker.io I get an error
When I run
docker pull hello-world
i get the error:
Using default tag: latest
Error response from daemon: unknown:
408 Request Time-out
Your browser didn't send a complete request in time.
any idea? My proxies are fine since I can run curl docker.io -v
I also tried docker login and it didnt work
I get errors like
docker: Error response from daemon: Get "registry-1.docker.io/v2/": dial tcp: lookup registry-1.docker.io on [::1]:53: read udp [::1]:56718->[::1]:53: read: connection refused.
Excelente conteúdo! Me ajudou demais.
Any idea how to get rootless working on WSL2? I can get the rootless daemon running successfully, but it won't connect to the docker registry when trying to pull images - 'no such host'.
I managed to get it working on WSL2 Ubuntu 20.04 then stupidly upgraded it (and WSL2). Something somewhere obviously broke and now I can't get it working again.
OK just found the solution: github.com/microsoft/WSL/issues/74...
I'm using WSL2 on Windows 10, Ubuntu 22.04 LTS.
You don't need to change iptables to legacy anymore either, you can leave them on the newer nft setting.
You can run the commands in Powershell. You need to add proxy functions to your $PROFILE.
Replace the {} tokens with the relevant distribution and the username you use in that distribution.
Thanks for the tip, I would also recommend using PowerShell-WSL-Interop to achieve this.
Thank you for this tutorial @felipecrs . Will this work together with an Azure Client installed on windows?
For example:
$ which az
/mnt/c/Program Files (x86)/Microsoft SDKs/Azure/CLI2/wbin/az
with az acr login?
Thanks
Martin
If it delegates to the docker cli I see no reason for it not to work. Let me know if you ended up testing it, though.
I couldn't get it to do it, but worked around by taking the token from az and passing it to docker login
Felipe,
First let me say thank you for sharing this with us! It is a very good help.
I do have one small issue. Today when I attempted to get the credential helper setup I get the following error:
curl: (22) The requested URL returned error: 404
I can see the .exe file for v0.7.0 but not seeing a .zip file though. So, I downloaded the .exe file and copied it to the
/usr/local/bin
location, issued thechmod
command and tried thedocker login
and it was successful.Hey, thanks for reporting it.
You're right about copying the file to
/usr/local/bin
, but don't forget to give it execution permission as well.I updated the guide to point the new changes.
This is an excellent replacement except I haven't been able to get K8s clusters from the WSL side to connect on the devcontainer side. Docker Desktop offers its built-in cluster API at a special address that resolves correctly back out of the devcontainer. Any other cluster: kind, k3d, minikube, created on the WSL side will not resolve inside the devcontainer.
This is the devcontainer feature I'm using to enable cluster access on the devcontainer side using its kubeconfig copy script to copy my local kubeconfig in.
Have you tried this? Is Docker Desktop somehow blessed in its operation?
In all my devcontainers, I add
--network=host
to therunArgs
of it, so that it does not suffer of this issue.However, have you tried Rancher Desktop? It may work for you.