WSL2 Docker Development Environment

5th June 2021

Coding

Introduction

Join me on my journey of setting up Docker development environments on Windows using WSL2.

A quick bit of background, I used to use a Ubuntu VM to develop my projects on.

This was ok for me (and still would be), but spinning up a VM every time I want to do some development work is slow and resource demanding, there must be a better way.

There is a better way and that way is Docker!

For this blog post I am assuming you know a bit about Docker and WSL2, before we look at how I set it all up, I want to comment on an issue I had with this setup on Windows.

Issues with Windows

Yeah there are issues with Windows and Docker, but to be fair in 99% of cases it's all fine.

The main issue I had was after getting a working Docker compose file setup, I found loading my projects in the browser was incredibly slow, like multiple seconds per request!!!

This was unacceptable for me so I started to dig around on the web for a solution.

After some testing, it turned out that mounting volumes from the Windows file system to the Containers Linux file system was the cause of the slowdown.

The solution was to copy the project files to the WSL2 file system and work from there, this means that both sides are using Linux file systems.

To access your WSL2 container filesystems via Windows Explorer use this network path \\wsl$

Now that I have talked about my issues, lets see what I did.

The Plan

The plan was to replace my Ubuntu VM with Docker containers, this has the benefits of being super quick to spin up, light on resources and also allows each project to have its own version dependencies.

The two main frameworks I work with are Drupal and Laravel and luckily both use the same core items:

  • Webserver
  • PHP
  • MySQL Database
  • Composer
  • Node.JS

I will be aiming for a one service, one container approach. 

Docker Compose

Here is the docker-compose.yml file I used on my AccountBooks.Online project.

It defines 6 services and 1 network.

I can run them with the docker-compose up command, stop them with docker-compose stop and destroy them with docker-compose down.

This makes it incredibly quick and easy to pull the repo and get working.

# https://www.digitalocean.com/community/tutorials/how-to-install-and-set-up-laravel-with-docker-compose-on-ubuntu-20-04

# docker compose up -d
# docker compose exec composer composer install
# docker compose exec node npm install
# docker compose exec node npm run prod
# docker compose exec app php artisan key:generate
# docker compose exec app php artisan migrate
# docker compose exec app php artisan storage:link
# docker compose exec app php artisan db:seed

version: "3"
services:
    node:
        image: node:14-alpine
        container_name: accountbooks-node
        working_dir: /var/www
        command: tail -f /dev/null
        volumes:
            - ./:/var/www
        networks:
            - accountbooks

    composer:
        image: composer:latest
        container_name: accountbooks-composer
        working_dir: /var/www
        command: tail -f /dev/null
        volumes:
            - ./:/var/www
        networks:
            - accountbooks

    phpmyadmin:
      build:
        context: ./
        dockerfile: Dockerfiles/phpMyAdmin.Dockerfile
      image: accountbooks-phpmyadmin
      container_name: accountbooks-phpmyadmin
      restart: unless-stopped
      depends_on:
          - db
      ports:
          - 4443:443
      networks:
          - accountbooks
      environment:
          PMA_HOST: db

    app:
        build:
            context: ./
            dockerfile: Dockerfiles/app.Dockerfile
        image: accountbooks-app
        container_name: accountbooks-app
        restart: unless-stopped
        working_dir: /var/www/
        depends_on:
            - db
        volumes:
            - ./:/var/www
        networks:
            - accountbooks

    db:
        image: mariadb:10.5
        container_name: accountbooks-db
        restart: unless-stopped
        environment:
            MYSQL_DATABASE: ${DB_DATABASE}
            MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
            MYSQL_PASSWORD: ${DB_PASSWORD}
            MYSQL_USER: ${DB_USERNAME}
        networks:
            - accountbooks

    nginx:
      build:
        context: ./
        dockerfile: Dockerfiles/nginx.Dockerfile
      image: accountbooks-nginx
      container_name: accountbooks-nginx
      restart: unless-stopped
      ports:
          - 443:443
      volumes:
          - ./:/var/www
          - ./docker-compose/nginx:/etc/nginx/conf.d
      networks:
          - accountbooks

networks:
    accountbooks:
        driver: bridge

Node

This service will be used to run things like npm install and npm run prod, this will compile CSS and JS files for me.

Composer

This service will be used to run things like composer install and composer update, this will allow me to manage dependencies.

phpMyAdmin

This service will allow me to inspect the database via a web browser.

App

This service will run the PHP code and it ties into the next two services.

Database

This service will host a MySQL database to store all the information for the site.

Nginx

This service will host a web server, it will take in requests and then pass them to the app service via fastcgi.

Other Supporting Bits

Along with the docker-compose.yml file, I also have a docker-compose and Dockerfiles folder which contain supporting files.

In the docker-compose folder there is another folder called nginx, this contains a file accountbooks.conf, this file contains nginx configuration.

In the Dockerfiles folder there are three files that define the Docker images for the app, nginx and phpMyAdmin services.

My Template Repos

I have made my template repos public, so please feel free to have a nose around them.

https://github.com/samsmithcodes/LaravelTemplate

https://github.com/samsmithcodes/DrupalTemplate