How to Dockerize Laravel using Laravel Sail with Docker Desktop WSL 2 backend in windows

Muhammad Bilal Naeem
8 min readAug 4, 2021

Environment Setup is a crucial part of every project, especially when working in teams. Each team member can have a different operating system with other versions of dependencies installed. With different versions of dependencies and operating system core software, the application may not work correctly.

Then the question arises, how to solve this problem. The answer is a standard general environment for every team member no matter what operating system. Let’s take a look at how to use Laravel’s new command-line tool Laravel Sail to get up and running with Laravel in no time and add additional support like PhpMyAdmin for the database in our environment.

Prerequisites

  1. Windows 10, version 1903 or higher
  2. Windows Subsystem for Linux (WSL) 2
  3. Windows Terminal
  4. Docker Desktop Installed in windows

Prerequisites Installation Guides

You can skip this step if you have prerequisites installed. Otherwise, follow the following steps.

  1. If you have windows ten but a version less than 1903, you can update your windows 10.
  2. To install WSL2 and Windows Terminal, please read this article Windows Subsystem for Linux Installation Guide for Windows 10
  3. To Install Docker Desktop, Click here.

To check Docker is successfully installed on your WSL2, Open Windows terminal, default tab will pe PowerShell and run this command below.

wsl -l -v

The output should be something like this

Check WSL Windows Terminal

To make sure Docker Desktop configurations are using the WSL2 backend.

1. Start Docker Desktop from the Windows Start menu.

2. From the Docker menu, select Settings > General.

3. Select the Use WSL 2 based engine checkbox If not already checked.

Docker General Settings

4. Click Apply & Restart.

5. WSL can run distributions in both v1 or v2 modes, so Ensure the distribution runs in WSL 2 mode.

6. To set v2 as the default version for future installations, open window terminal and run on PowerShell tab:

wsl --set-default-version 2

7. After Docker Desktop restarts, go to Settings > Resources > WSL Integration. The Docker-WSL integration may be enabled on your default WSL distribution.

To list down available distros, run

wsl --list

The output will be something like this

WSL List

To change your default WSL distro, run command

wsl --set-default <distro name>

For example, to set WSL default distro to Ubuntu, run command

wsl --set-default Ubuntu-20.04

Optionally, select any additional distributions you would like to enable the Docker-WSL integration on.

Docker Resources

8. Click Apply And Restart

What is Laravel Sail?

According to Laravel Documentation

Laravel Sail is a lightweight command-line interface for interacting with Laravel’s default Docker development environment. Sail provides a great starting point for building a Laravel application using PHP, MySQL, and Redis without requiring prior Docker experience.

In short, Sail is the development environment for Laravel. It is based on docker technology which makes application services run in a defined background to run effortlessly without any hustle in any operating system.

How to Use Laravel Sail?

When creating a Laravel 8 new application, the sail is also included (so jump to step 3), but if you don’t install a new Laravel 8 or add a sail to the Laravel existing project, you have to perform several steps.

1. Require Sail using composer

composer require laravel/sail --dev

2. Run the sail install Artisan command, which will publish the docker-compose.yml file to the root of your project.

php artisan sail:install

Please note, if you have other web server software installed on Windows, such as Wamp, Xampp, etc. It would be best to shut them down first because they use port 80 as default, and your docker Laravel application also requires port 80.

3. Run sail up Artisan command, which will start the docker container

./vendor/bin/sail up

When you sail it up for the first time, this process will take a while because it will download and install several docker images.

When it is finished, you can see the installed images in Docker Desktop.

Docker Images

Now you should be able to see your application at localhost or http://127.0.0.1.

Default docker-compose.yml

Installing Sail will create a default docker-compose.yml file to the root of your application. It will look like this

# For more information: https://laravel.com/docs/sail
version: '3'
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.0
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: sail-8.0/app
ports:
- '${APP_PORT:-80}:80'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- mysql
mysql:
image: 'mysql:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
volumes:
- 'sailmysql:/var/lib/mysql'
networks:
- sail
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
retries: 3
timeout: 5s
networks:
sail:
driver: bridge
volumes:
sailmysql:
driver: local

This is the default docker-compose.yml file that Laravel Sail creates for you. It contains two services named MySQL and laravel.test. MySQL for the application database and laravel.test for running our application.

laravel.test service is based on the default dockerfile in the folder ./vendor/laravel/sail/runtimes/8.0, which uses Ubuntu as a base image and requires extensions and software for running the Laravel project.

These all services are different from each other, but the network connects these services. As in our case, under each service, you can see networks sail that connects these services.

networks:
- sail

also, you can see it in laravel.test service a depends_on attribute which tell that service is dependent on MySQL service

Important To Understand

After making the Laravel Sail development Environment, We must know how to run commands in our application.

According to Laravel Documentation

When using Laravel Sail, your application executes within a Docker container and is isolated from your local computer. However, Sail provides a convenient way to run various commands against your application, such as arbitrary PHP, Artisan, Composer, and Node / NPM.

When you run any command as php artisan migrate, it is run on a project on your local system, not in the environment we create using Laravel Sail, so it will not affect our project running via Sail.

So how to run commands in our application running via Sail?

For that, we have to use the sail keyword before the command to tell the system to run this command inside the running sail environment like as follow

./vendor/bin/sail artisan migrate

PHP commands can be executed using the php command.You can learn more about the PHP versions available to Laravel Sail, consult the PHP version documentation:

./vendor/bin/sail php --version

Composer commands may be executed using the composer command.

./vendor/bin/sail composer require laravel/sanctum

Problems Or Confusions

After Running Project via docker, some problems or questions arise for newcomers like

1- how to access the database of your project?

2- How to import the initial dump of your project into your project database?

Solutions

Q1- How to access a database of your project?

Ans: Laravel Sail creates a database with the name and password you define in the .env file. You can access your project database in various ways.

1- You can access your project database with MySQL command via CLI using command

./vendor/bin/sail mysql

2- You can use a graphical database management application like TablePlus. The MySQL database can be accessed at localhost port 3306 by default.

3- If you are not familiar with TablePlus or CLI and you want PHPMyAdmin for the database. For that, we can extend the default docker-compose.yml file and add a service for PHPMyAdmin in docker-compose.yml as follow

# For more information: https://laravel.com/docs/sail
version: '3'
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.0
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: sail-8.0/app
ports:
- '${APP_PORT:-80}:80'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- mysql
mysql:
image: 'mysql:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
volumes:
- 'sailmysql:/var/lib/mysql'
networks:
- sail
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
retries: 3
timeout: 5s
phpmyadmin:
image: phpmyadmin/phpmyadmin
links:
- mysql:mysql
ports:
- 8080:80
environment:
MYSQL_USERNAME: "${DB_USERNAME}"
MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}"
PMA_HOST: mysql
UPLOAD_LIMIT: 300M
networks:
- sail
networks:
sail:
driver: bridge
volumes:
sailmysql:
driver: local

A new service, PHPMyAdmin, will also be created linked to MySQL service and exists on the same network sail. Now you have to run the sail down command to remove the previous container to create it again with new configurations.

./vendor/bin/sail down -v

-v flag tells that delete previously created volumes so that when we create container again, it will be created with new volume configurations. Now again, run sail up command

./vendor/bin/sail up

Now you can access PHPMyAdmin on localhost:8080

Q2- How to import the initial dump of your project into your project database?

Ans- Let’s say you have a MySQL file that you want to import into your database when your project started initially, or you wish to have your MySQL some custom configurations. For that purpose, create a folder named sail in the root of your project with the following directory structure

sail/
dump/
initialDump.sql
conf/

dump folder will contain a single SQL file of your project that needed to be imported initially. The conf folder will have a custom configuration file if you want custom configurations or leave this directory empty.

Now change MySQL service in docker-compose.yml as follows

mysql:
image: 'mysql:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
volumes:
- ./sail/dump:/docker-entrypoint-initdb.d
- ./sail/conf:/etc/mysql/conf.d
- 'sailmysql:/var/lib/mysql'
networks:
- sail
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
retries: 3
timeout: 5s

Conclusion

By building apps this way using containers, you can make sure every developer on your team is working with the same environment as you are and on the identical versions of PHP, MySQL, NPM, and so on. This Will save you from issues caused by different settings and different versions of software.

References

  1. Windows Subsystem for Linux Installation Guide for Windows 10
  2. Install Docker Desktop
  3. Docker Desktop WSL 2 Backend
  4. Laravel Sail

--

--