WSL 2 and Docker
Tags: wsl, docker, beginners, tutorial
Published: 2021-04-09 08:24:42



My [previous post](https://dev.to/paddymorgan84/wsl-2-and-vs-code-3jnf) focussed on getting WSL 2 integrated with VS Code, so at this point, you should have a fully-fledged WSL 2 distro that plays nicely with VS Code.

The next step is to get WSL 2 working with [Docker](https://www.docker.com/).

---

## What is Docker (and why it's great)

Docker, in a nutshell, is a tool for deploying and managing containers. [Containers](https://docs.docker.com/get-started/#what-is-a-container) are loosely isolated environments that allow you to package your application into a standardised "unit". They allow you to abstract away your application from the environment you're running them on. You create containers from an [image](https://docs.docker.com/get-started/#what-is-a-container-image), which in turn is created through a set of steps defined through a [Dockerfile](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/).

I've been using Docker increasingly over the last couple of years, and the more I use it, the more uses I find for it:

- I've worked with Docker as part of projects; providing consistent, repeatable and scalable environments for use by others. 

- I've used it to run tooling; meaning that I don't have to clutter my machine with a multitude of packages as I jump between projects, I can simply pull an image, run it, and trash it once I'm done. 

- More recently, I've started to use it as a fully functioning development environment, thanks in no small part to the [VS Code Remote Container extension](https://code.visualstudio.com/docs/remote/containers). @benmatselby has written a great tutorial on getting up and running with VS Code dev containers, I'd wholeheartedly recommend that you [give it a read](https://dev.to/benmatselby/setting-up-a-vs-code-dev-container-5fjk).

---

## Installing Docker Desktop for Windows

First things first, you're going to need to install [Docker Desktop Stable 2.3.0.2](https://hub.docker.com/editions/community/docker-ce-desktop-windows/) or later. Docker Desktop is the application that will allow us to build and run our containers on both Windows and WSL.

During the installation, you'll be prompted to enable any Windows components necessary for WSL 2. You want to do this.

Provided you've followed the steps from my [first post](https://dev.to/paddymorgan84/getting-started-with-wsl-2-ja) in the series, you should be ready to go with Docker Desktop :whale:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d8h7hud5kg4xbssapf81.png)

---

## Configuring Docker Desktop for WSL 2

Now we've got Docker Desktop installed, there's a two-step checklist we'll need to run through to integrate with WSL 2.

**Step 1**: Enable the WSL 2 based engine

Theoretically, this option should be enabled by default; Docker Desktop will recognise the fact that you have WSL 2 enabled and assume that you want this feature switched on, which you do. It's always good to confirm these things though, so open up Docker Desktop, then select `Settings -> General`.


![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/04jsi0ejeg0a11fadl31.png)

If for whatever reason you did need to enable the WSL 2 engine, be sure to "Apply & Restart" Docker Desktop.

If we have a little peek under the hood at what's happened here, you'll notice that we now have a couple of extra WSL distros.
 
```powershell
> wsl -l -v

  NAME                   STATE           VERSION
* Ubuntu-18.04           Running         2
  docker-desktop-data    Running         2
  docker-desktop         Running         2
```

These are installed by Docker Desktop when you enabled the WSL 2 engine. At the risk of horribly exposing my lack of knowledge around the architecture of Docker Desktops WSL 2 backend, I'll keep this short and sweet:

- `docker-desktop` replaces the Hyper-V VM implementation Docker Desktop previously used. This handles bootstrapping and management of containers.
- `docker-desktop-data` is where your images and configuration are stored; this is essentially a direct replacement of the Virtual Hard Disk that was used previously by Hyper-V.

This is great for a couple of reasons. Firstly, it solves the odd restriction Microsoft placed on Windows Home users, for whom Hyper-V (and by extension, Docker) is not available. Although as [Jeff](https://www.youtube.com/watch?v=dMjQ3hA9mEA) says, [life finds a way](https://www.itechtics.com/enable-hyper-v-windows-10-home/).

Secondly, because your WSL distros get [full access to all of your CPU cores and 80% of your RAM](https://docs.microsoft.com/en-us/windows/wsl/wsl-config#wsl-2-settings), resource allocation is far more dynamic, which on the whole helps to improve a Windows users' Docker experience. 

**Step 2**: Enable WSL integration for your distro

Now we have the WSL 2 Engine running, we need to make sure our distro has access to the Docker server running in `docker-desktop`. Open up Docker Desktop, then select `Settings -> Resources -> WSL Integration`.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/psntbu0jf107xs6etgua.png)

Any WSL 2 distro will appear in this list. Select whatever distros you'd like to have access to Docker, then select "Apply & Restart".

---

## Kicking the tyres

All that's left to do now is give Docker a go in our WSL 2 distro of choice:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0wk5ixjcde7lulhuouby.png)


---

## Bonus Content: Docker with WSL 1

Although I'm a [strong advocate of using WSL 2](https://dev.to/paddymorgan84/getting-started-with-wsl-2-ja), there may be reasons why this is either unavailable or impractical for you.

There's a little more legwork involved (and a lot less documentation) in getting WSL 1 working with Docker, so here's a quick guide on how I got this working before I migrated to WSL 2:

**Step 1**: Install Docker Desktop

If you don't already have it, you're going to need to install [Docker Desktop for Windows](https://docs.docker.com/docker-for-windows/install/).

**Step 2**: Expose the Docker daemon on Docker Desktop

Docker Desktop has an option that allows you to open a port to expose the Docker daemon to other clients. You're going to need to have this setting selected:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4wvn5ppxdju3qxs59o1t.png)

**Step 3**: Install the Docker CLI on WSL 1

Follow the [instructions for installing Docker on Ubuntu](https://docs.docker.com/engine/install/ubuntu/), right up until you get to this point:

```bash
sudo apt-get install docker-ce docker-ce-cli containerd.io
```

You need only install `docker-ce-cli`, as you're going to connect to the exposed port on your Windows machine to access the Docker daemon.

```bash
sudo apt-get install docker-ce-cli
```

**Step 4**: Update `DOCKER_HOST`

The Docker CLI has a [list of environment variables](https://docs.docker.com/engine/reference/commandline/cli/#environment-variables) that it looks for when it runs. One of these is `DOCKER_HOST`. 

We want to update `DOCKER_HOST` in WSL so that the Docker CLI knows that we want to connect to the exposed Docker daemon on your Windows machine:

```
export DOCKER_HOST=tcp://localhost:2375
```

If you want to make this change a little more permanent, you can add it to a shell config file of your choosing:

```
echo "export DOCKER_HOST=tcp://localhost:2375" >> ~/.zshrc && . ~/.zshrc
```

With those 4 steps complete, you'll be able to run Docker commands from WSL 1.

---

## That's a wrap

Part 3 of the series is complete! The next item I'll discuss is using a standalone terminal with WSL 2, and how to configure it.

---

## Resources

- [Getting started with Docker](https://docs.docker.com/get-started/overview/)
- [Docker Desktop - User Manual](https://docs.docker.com/docker-for-windows/)
- [Installing Docker Desktop on Windows](https://docs.docker.com/docker-for-windows/install/)
- [Docker Desktop - WSL 2 Backend Architecture](https://www.docker.com/blog/new-docker-desktop-wsl2-backend/)

---

## Credit

[Jexo](https://unsplash.com/@jexo) for the photo :camera: