Setting-up a local development environment using VS Code, Docker, and WSL 2
Tags: tutorial, vscode, docker, windows
Published: 2021-02-07 10:50:50


Developing software within a Windows environment is such a pain especially if you're into writing web applications. In my case, most of the web apps I made are deployed and ran on a Linux machine hosted on the cloud. This means that I can't issue commands on my local machine as I did on the server.

In this post, I'll share how I achieved setting-up my Windows machine to use WSL 2 alongside Docker and VS Code to create a local development environment that runs on a Linux environment (Ubuntu 20.04 LTS).

## Prerequisite
Before you proceed make sure you have already installed the following applications on your machine.
- [Docker Desktop on Windows](https://docs.docker.com/docker-for-windows/install/)
- [Windows Terminal](https://docs.microsoft.com/en-us/windows/terminal/get-started) _(Recommended but not required)_
- [VS Code](https://code.visualstudio.com/docs/setup/windows)

**Note:**
Make sure you have ticked the option to add VS Code to Window's path. We will be needing this to use the `code` command within the WSL environment.

![VS Code installation instructions](https://dev-to-uploads.s3.amazonaws.com/i/zj17eo7bmpu8klxxd0dy.png)

## Getting Started
After you have installed the required applications, you can now start with the steps as detailed below.

### Installing Ubuntu on WSL
The environment I choose to develop to is Ubuntu (20.04 LTS) but you can choose any other Linux distros you prefer. Beware though that not all are free.

1. Open up [Microsoft Store](https://support.microsoft.com/en-us/account-billing/how-to-open-microsoft-store-on-windows-10-e080b85a-7c9e-46a7-8d8b-3e9a42e32de6).
2. Search and select [Ubuntu 20.04 LTS](https://www.microsoft.com/en-us/p/ubuntu-2004-lts/9n6svws3rx71?activetab=pivot:overviewtab) (or your preferred Linux distro).
3. Click **GET** button. This will download and install Ubuntu on your machine.
4. Once finished, click **Launch**. This will open a command prompt and asks you to setup the user account of the system.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/k9jz1slexlmz9p2z2rn2.png)
<ol start="5"><li>And that's it! You have now installed and ran Ubuntu on your Windows machine.</li></ol>

### Setting-up Ubuntu to use WSL 2
By default, Windows installs your distro using WSL 1 but in this case, we will be using WSL 2. WSL 2 is the newest version and is much faster than WSL 1 in terms of file system performance. For comparison, you can check this link [Comparing WSL 1 and WSL 2](https://docs.microsoft.com/en-us/windows/wsl/compare-versions).

1. Verify which version of WSL your distro is using by clicking **Start**, type **PowerShell**, and select **Windows PowerShell**. Copy and run the command below.

```shell
PS> wsl -l -v
```
It should show a similar output as below. If the version of your distro is already 2, feel free to skip this section.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/nfl5v4g4bfjkke21393i.png)

<ol start="2"><li>
To convert to version 2, copy and run the command below substituting the placeholders with your actual values. Note that you can always switch back between versions.
</li></ol>
```shell
# wsl --set-version <distribution-name> <version-number>
$ wsl --set-version Ubuntu-20.04 2
```

<ol start="3"><li>
And that's it! Running the command again from step 1 should now show version 2.
</li></ol>
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3l5h49t90ap02tipkotk.png)

### Configuring Docker for WSL Integration

Configuring Docker Desktop for WSL 2 is quite easy. We just need to enable a few settings and we're good to go.

1. Start **Docker Desktop** via Windows **Start** menu.
2. Open **Settings** by right-clicking Docker icon located in the System tray.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/54p0hixnpdgdkahoovxk.png)
3. Under **General**, make sure **Use the WSL 2 based engine** is ticked.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wizuqscpuxcav7f5ewfh.png)
4. Next, under **Resources > WSL INTEGRATION**, enable the Linux distro you would like to be integrated with Docker.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jgd7u448fcer9kvivk0w.png)
5. Hit **Apply & Restart** button and you're done!

### Installing Windows Terminal

This is an optional step and you're free to skip this section. I highly recommend installing Windows Terminal though as it makes it easy to start and switch between distros (if you have more than one). Plus, compared to CMD, it has a nice UI!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4w1lnnce3qg0n2hklnpj.png)

1. Install Windows Terminal via [Microsoft Store](https://www.microsoft.com/en-ph/p/windows-terminal/9n0dx20hk701?rtc=1&activetab=pivot:overviewtab).
2. Click **GET** button and it should download and install Windows Terminal.
3. To open, simply hit **Start** and search for **Windows Terminal**.

Now, when we want to connect to an installed Linux distro, we can just easily click the dropdown menu located at the top. In my case, using **Ubuntu-20.04**.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cpcm908uokuc0vqelimj.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dbe4owuqajon2zs3exio.png)

### Setting-up VS Code for remote development

We will be using a Docker container as our development environment running in the Ubuntu distro we had previously setup. Inside this container will be our project and its dependencies. But before we can make changes to our code, we need to have VS Code connect to our WSL environment first. To do this, we have to install a VS Code extension called [Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack). Go ahead and install this extension.

If you notice, this is an extension pack meaning it will install the following: 
- [Remote - SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh)
- [Remote - WSL](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl)
- [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)

The important ones are the **Remote - WSL** and **Remote - Containers** as this will allow us to connect inside WSL and in our Docker container.

After the installation, you'll notice that a new status bar located at the bottom-left is now available. Clicking this item will give you different options on how you want to open your project.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/h7byq4pzp1qzaywd1ma6.png)

### Creating our sample project

Now that we have installed the extension, VS Code should now be able to open a project inside WSL. Since we don't have a project yet, let's go ahead and create a sample Laravel project.

1. Open **Windows Terminal** and connect to your installed distro (Ubuntu-20.04).
2. Create a Laravel project on your chosen directory.
```shell
$ cd /opt/workspace/
$ curl -s https://laravel.build/example-app | bash
```
<ol start="3"><li>
Next, we'll open this project in VS Code. Remember I mentioned that you need to tick the option to add VS Code in Windows Path? The reason is we will be using the <code>code</code> command to open our project.
</li></ol>
```shell
$ cd example-app
$ code .
```

You'll know that you're opening a project inside a WSL if you're seeing this in the status bar.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8ubhl9fmejie4b1y1wz5.png)

**TIP:**
It's pretty amazing that we can invoke a Windows application inside our Ubuntu environment. As a matter of fact, you can actually open File explorer in the current directory by typing `explorer.exe .`. Try it!

### Creating a development container
Now that we have our sample project, we just need to bind this into our Docker container. We will be leveraging VS Code's Remote Containers extension.

The power of Remote Containers lies in a file called `devcontainer.json`. This will instruct how VS Code will access or create our Docker container.

1. Open **Command Palette (F1)** and search for **Remote-Containers: Add Development Container Configuration Files...**.
2. Select **From a predefined container configuration...**.
3. Select **PHP & MariaDB**. This will create a new folder in your root project directory called `.devcontainer` with the following files.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/w99gjbz1gak0qcisg7sf.png)
4. Since we will be using `artisan serve`, we must add the port `8000` as one of the `forwardPorts` values.
```json
...
"forwardPorts": [8080, 3306, 8000],
...
```
5. To build this, hit **F1** and search **Reopen in Container**. Note that this might take awhile but will be faster the next time we rebuild.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/g3vl8flifehbkvt1p480.png)
5. Once build, open a new **Terminal** and start PHP's built-in development server.
```shell
$ php artisan serve
```
If you notice, the opened Terminal automatically connects to the container, giving us little hassle as we no longer need to use `Docker exec` commands.

<ol start="6"><li>
Got ahead and open up localhost:8000. You should see Laravel's welcome route.
</li></ol>
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/x4w2bnv5uzegkx9hsjtg.png)

Of course, we wouldn't want to manually issue the `artisan serve` command every time we want to start our project. To automate this, we can use another VS Code feature called [Tasks](https://code.visualstudio.com/docs/editor/tasks) and configure it to run every time our project folder is opened.

And that's it! As we saw, we now have a local development environment running on a container under WSL 2 (Ubuntu-20.04). If you want to add other dependencies to our container like git and composer, you just need to modify the `.devcontainer/Dockerfile` file and rebuild the project once again.

**TIP:**
If you're running low on system memory due to virtualization, we can instruct Windows to only allocate a certain amount of memory for virtualization. To do this, create a file in `%userprofile%` called `.wslconfig` and paste the content below.
```
[wsl2]
processors=4 # Number of processors to allocate.
memory=4GB   # Maximum amount of memory to allocate.
```

Before this takes effect, you may need to shutdown WSL by running the command below on **Powershell** and restarting **Docker Desktop**.
```shell
PS> wsl --shutdown
```

After this, open your **Task Manager** and look for **Vmmem**. The memory consumption should drop around your set values.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/f5jgvennc2alf805f28f.png)