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
- Windows Terminal (Recommended but not required)
- VS Code
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.
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.
- Open up Microsoft Store.
- Search and select Ubuntu 20.04 LTS (or your preferred Linux distro).
- Click GET button. This will download and install Ubuntu on your machine.
- Once finished, click Launch. This will open a command prompt and asks you to setup the user account of the system.
- And that's it! You have now installed and ran Ubuntu on your Windows machine.
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.
- Verify which version of WSL your distro is using by clicking Start, type PowerShell, and select Windows PowerShell. Copy and run the command below.
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.
- 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.
# wsl --set-version <distribution-name> <version-number>
$ wsl --set-version Ubuntu-20.04 2
- And that's it! Running the command again from step 1 should now show version 2.
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.
- Start Docker Desktop via Windows Start menu.
- Open Settings by right-clicking Docker icon located in the System tray.
- Under General, make sure Use the WSL 2 based engine is ticked.
- Next, under Resources > WSL INTEGRATION, enable the Linux distro you would like to be integrated with Docker.
- 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!
- Install Windows Terminal via Microsoft Store.
- Click GET button and it should download and install Windows Terminal.
- 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.
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. Go ahead and install this extension.
If you notice, this is an extension pack meaning it will install the following:
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.
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.
- Open Windows Terminal and connect to your installed distro (Ubuntu-20.04).
- Create a Laravel project on your chosen directory.
$ cd /opt/workspace/
$ curl -s https://laravel.build/example-app | bash
-
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
command to open our project.
$ 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.
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.
- Open Command Palette (F1) and search for Remote-Containers: Add Development Container Configuration Files....
- Select From a predefined container configuration....
- Select PHP & MariaDB. This will create a new folder in your root project directory called
.devcontainer
with the following files. - Since we will be using
artisan serve
, we must add the port8000
as one of theforwardPorts
values.
...
"forwardPorts": [8080, 3306, 8000],
...
- 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.
- Once build, open a new Terminal and start PHP's built-in development server.
$ 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.
- Got ahead and open up localhost:8000. You should see Laravel's welcome route.
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 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.
PS> wsl --shutdown
After this, open your Task Manager and look for Vmmem. The memory consumption should drop around your set values.
Top comments (1)
Hello. I am a noob with docker and have slight experience with php. I have a local website created and I have utilized php mainly for navigation and page file structure. I built it a couple of years ago using homestead on PC and some was built with laravel/valet on Mac. I would like to use docker containers going forward and I believe this article is the way to do it, but I cannot seem to run my website. I can run the sample-app no problem following this tutorial so I am thinking there is something I need to download into my local project which is contained in the curl/laravel sample you download in this. Do I simply go into my local project and run the same curl command (this seems like a little much to download a full sample laravel app into each of my projects)? I think I am close, but just need a little nudge in the right direction. When I get to the part where I try and load my localhost:8000 the page just hangs and does not load, but works great with the sample project in this post. I can share my github repo of my project if it helps. Thanks in advance!