How to make Docker work inside WSL on Windows
Posted 5/27/2022
I ended up in a rabbit hole while trying to make Testcontainers work on my Windows computer. I really didn't want to install Docker Desktop since I've had bad experiences with it before. I tried installing the Windows version of dockerd and the docker CLI and it didn't work very well either.
Here are my notes on how to set up Docker inside WSL on Windows and making it work with Testcontainers as well as being able to run from PowerShell. I gathered this from various sources around the web and tried to summarize it as concisely as possible.
Basic setup
- Install WSL2
- Run the following inside WSL:
sudo apt-get update && sudo apt install -y docker.io
- Create a file at
C:\Users\<user>\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
with the following content:
function docker {
wsl docker @Args
}
- When you want to use Docker, open a WSL shell and run
sudo dockerd
. Let it run in the background. - You could set dockerd up to run on startup. But since I don't use Docker that often I don't want it using resources when not in use, so I'm fine with having to do this extra step before use.
- Now you can run
docker
from PowerShell as if it were a native application.
Testcontainers / TLS for dockerd
Because Testcontainers communicate directly with the Docker daemon rather than using the CLI, you must do the following to expose dockerd over TCP so testcontainers can find it. For security, you should use TLS when exposing dockerd over TCP.
- I use 10 000 days validity time for the generated certificates. You can use a shorter validity time if you want (replace
-days 10000
below with-days 365
or whatever). Since this is for my personal computer I don't feel the need to rotate certificates that often and would rather avoid the inconvenience of needing to redo these steps. - Run this in WSL:
cd ~
sudo sh -c 'echo {\"hosts\": [\"tcp://127.0.0.1:2376\", \"unix:///var/run/docker.sock\"]} > /etc/docker/daemon.json'
# Generate CA
openssl genrsa -aes256 -out ca-key.pem 4096
openssl req -new -x509 -days 10000 -key ca-key.pem -sha256 -out ca.pem
# Generate server cert
openssl genrsa -out server-key.pem 4096
openssl req -subj "/CN=localhost" -sha256 -new -key server-key.pem -out server.csr
echo subjectAltName = DNS:localhost,IP:10.10.10.20,IP:127.0.0.1 >> extfile.cnf
echo extendedKeyUsage = serverAuth >> extfile.cnf
openssl x509 -req -days 10000 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf
# Generate client cert
openssl genrsa -out key.pem 4096
openssl req -subj '/CN=client' -new -key key.pem -out client.csr
echo extendedKeyUsage = clientAuth > extfile-client.cnf
openssl x509 -req -days 10000 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile-client.cnf
# Configure docker to use TLS by default
echo DOCKER_HOST=tcp://localhost:2376 >> ~/.profile
echo DOCKER_TLS_VERIFY=1 >> ~/.profile
mkdir -pv ~/.docker
cp -v {ca,cert,key}.pem ~/.docker
- From now on you must start dockerd with the following command:
sudo dockerd --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem
- Maybe make a script for it or something so you remember it.
- Set the following environment variables (replace
<distro>
and<user>
with your WSL distribution and Linux user name):
DOCKER_CERT_PATH=\\wsl$\<distro>\home\<user>\.docker
DOCKER_HOST=tcp://127.0.0.1:2376
DOCKER_TLS_VERIFY=1
- Restart your computer (it might be enough to sign out and in again)
Conclusion
You should now be able to run Linux-based Docker containers from PowerShell and Java Testcontainers should just work.