Getting Up And Running With Laravel Sail
Docker is one of the best ways to have a consistent environment across multiple computers, but for new developers (and even not-so-new developers), it can be hard to understand and set up. Thankfully, the Laravel team has created Laravel Sail to make Docker a much easier tool to use when we’re working on Laravel projects.
In this article, we’ll discuss what Laravel Sail is, how to install and configure it, and then go through some common tasks.
What is Laravel Sail?
The Laravel Sail library provides a lightweight command-line interface for interacting with Docker development environments in a Laravel project. Sail provides a starting point for developing a Laravel application using PHP, MySQL, and Redis without requiring us to learn Docker or most of its complex processes.
Sail provides a docker-compose.yml file and the sail script. The sail script provides a command line interface (CLI) with methods for interacting with the Docker containers defined in the docker-compose.yml file.
How To Install Laravel Sail
To demo how to use Sail, we’re going to create a new Laravel project. This will require you to have Docker and Docker Compose installed or Docker Desktop. You’ll also need composer installed either locally or globally. If you have questions about this, please see our articles about docker and composer, respectively.
If this is an existing project you’re adding Sail to, it’s done using composer require laravel/sail --dev
.
We’re going to create a new project using php composer.phar create-project laravel/laravel example-app
and then cd example-app
.
Either way, we need to install the sail into our project using php artisan sail:install
As part of the process, we’ll get to pick what services we want to use for development. In this case, we’re just going to select MySQL, but we could have used a different database provider, a key/value store like Memcached or Redis, and several others. Sail will then build our Docker images.
The output of this is too long to post, but what changed in our project?
The first thing is that there is now a docker-compose.yml file at the root of our project.
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.2
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: sail-8.2/app
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
IGNITION_LOCAL_SITES_PATH: '${PWD}'
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- mysql
mysql:
image: 'mysql/mysql-server:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_HOST: '%'
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 1
volumes:
- 'sail-mysql:/var/lib/mysql'
- './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
networks:
- sail
healthcheck:
test:
- CMD
- mysqladmin
- ping
- '-p${DB_PASSWORD}'
retries: 3
timeout: 5s
networks:
sail:
driver: bridge
volumes:
sail-mysql:
driver: local
This sets up all of the containers, networks, and volumes that we need.
If you have this directory underversion control like I do, you’ll also see that the phpunit.xml file was edited to change the database information.
git diff
diff --git a/phpunit.xml b/phpunit.xml
index f112c0c..7fb08b5 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -21,8 +21,7 @@
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
- <!-- <env name="DB_CONNECTION" value="sqlite"/> -->
- <!-- <env name="DB_DATABASE" value=":memory:"/> -->
+ <env name="DB_DATABASE" value="testing"/>
<env name="MAIL_MAILER" value="array"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
Create an alias
Now to interact with sail we need to run ./vendor/bin/sail
but that’s a lot of typing so we’re going to set up an alias to make it easier to work with. This is taken directly from the Sail documentation
alias sail='[ -f sail ] && sh sail || sh vendor/bin/sail'
“Up”ing Our Environment
We’re finally ready to create our containers and see how they work. To get the environment up we’re going to run sail up
root@ubuntu-s-1vcpu-1gb-amd-nyc3-01:~/sail-example/example-app# sail up
Creating network "example-app_sail" with driver "bridge"
Creating volume "example-app_sail-mysql" with local driver
Creating example-app_mysql_1 ... done
Creating example-app_laravel.test_1 ... done
Attaching to example-app_mysql_1, example-app_laravel.test_1
...
laravel.test_1 |
laravel.test_1 | INFO Server running on [http://0.0.0.0:80].
laravel.test_1 |
laravel.test_1 | Press Ctrl+C to stop the server
Should be able to access the site now.
Use ctl+c to cause Sail to exit.
What if we didn’t want to keep the shell open?
We can run Sail using sail up -d
to run in detached mode so it will continue to run in the background so we can do other tasks using the same terminal.
root@ubuntu-s-1vcpu-1gb-amd-nyc3-01:~/sail-example/example-app# sail up -d
Creating network "example-app_sail" with driver "bridge"
Creating example-app_mysql_1 ... done
Creating example-app_laravel.test_1 ... done
To shut it down we’ll use sail down
.
root@ubuntu-s-1vcpu-1gb-amd-nyc3-01:~/sail-example/example-app# sail down
Stopping example-app_laravel.test_1 ... done
Stopping example-app_mysql_1 ... done
Removing example-app_laravel.test_1 ... done
Removing example-app_mysql_1 ... done
Removing network example-app_sail
Running Artisan Commands Inside The Container
Because we’re running our Laravel application inside of a container, we need to run our artisan commands inside the same container. To do so, we can run sail artisan <command>
which will open a connection to the container and run the artisan command.
For example, we can run artisan migrate
:
root@ubuntu-s-1vcpu-1gb-amd-nyc3-01:~/sail-example/example-app# sail artisan migrate
INFO Preparing database.
Creating migration table .................................................................. 61ms DONE
INFO Running migrations.
2014_10_12_000000_create_users_table ...................................................... 45ms DONE
2014_10_12_100000_create_password_reset_tokens_table ...................................... 52ms DONE
2019_08_19_000000_create_failed_jobs_table ................................................ 49ms DONE
2019_12_14_000001_create_personal_access_tokens_table ..................................... 69ms DONE
Accessing the Running Container
Eventually, you’re going to need to access the running container to perform some kind of troubleshooting. To do this we have two options. The first is sail shell
which will create a shell for us logged in as the “sail” user. We can also use sail root-shell
to create a shell logged in as the root user.
Customizing the Docker Image
If you use sail shell
to access the container you might quickly notice that it’s a little devoid of tools that would help to troubleshoot problems and you might need additional packages for your application
sail@621f8b751f57:/var/www/html$ vi index.php
bash: vi: command not found
sail@621f8b751f57:/var/www/html$ vim index.php
bash: vim: command not found
sail@621f8b751f57:/var/www/html$ nano index.php
bash: nano: command not found
To resolve this we need to publish the sail files using sail artisan sail:publish
root@ubuntu-s-1vcpu-1gb-amd-nyc3-01:~/sail-example/example-app# sail artisan sail:publish
INFO Publishing [sail-docker] assets.
Copying directory [vendor/laravel/sail/runtimes] to [docker] ................................... DONE
INFO Publishing [sail-database] assets.
Copying directory [vendor/laravel/sail/database] to [docker] ................................... DONE
This creates several files in the “docker” directory.
root@ubuntu-s-1vcpu-1gb-amd-nyc3-01:~/sail-example/example-app# tree docker
docker
├── 8.0
│ ├── Dockerfile
│ ├── php.ini
│ ├── start-container
│ └── supervisord.conf
├── 8.1
│ ├── Dockerfile
│ ├── php.ini
│ ├── start-container
│ └── supervisord.conf
├── 8.2
│ ├── Dockerfile
│ ├── php.ini
│ ├── start-container
│ └── supervisord.conf
├── 8.3
│ ├── Dockerfile
│ ├── php.ini
│ ├── start-container
│ └── supervisord.conf
├── mysql
│ └── create-testing-database.sh
└── pgsql
└── create-testing-database.sql
If we look in our docker-compose.yml we can see that we’re currently running version 8.2.
services:
laravel.test:
build:
context: ./docker/8.2
dockerfile: Dockerfile
To add additional packages to our container, we’re going to edit “docker/8.2/Dockerfile”. This file is again not worth publishing the entire contents of, but there will be a large group of commands that start with RUN apt-get update \
and are strung together using “&&” and “\”. We need to edit the section that starts with && apt-get install -y
and add our packages.
I’m going to add Vim.
Before:
&& apt-get install -y php8.2-cli php8.2-dev \
php8.2-pgsql php8.2-sqlite3 php8.2-gd php8.2-imagick \
After:
&& apt-get install -y php8.2-cli php8.2-dev \
vim \
php8.2-pgsql php8.2-sqlite3 php8.2-gd php8.2-imagick \
Now we need to rebuild our containers using sail build
.
After that has completed we sail up -d
and sail shell
to get back into the container.
Then we can use vim.
Trying PHP 8.3
One of the amazing parts about using docker containers is how easy it is to swap out one container for another. Sail comes with Dockerfiles for 8.0, 8.1, 8.2, and 8.3, and switching between them is fairly simple.
To do so we just need to edit our docker-compose.yml file and change “context: ./docker/8.2” to “context: ./docker/8.3”. Then we can run sail build
and sail up
to quickly switch our laravel.test container to use 8.3.
We can even check our website to see if it is running 8.3 and not 8.2
Maybe we’re not yet ready to update our servers, so to swap back, we just edit our docker-compose.yml file and change it back to “context: ./docker/8.2”. Running sail build
takes almost no time because the operations are still cached so we can quickly switch back and forth.
What You Need to Know
- The Laravel Sail provides a light-weight CLI for interacting with Docker development environment
- Highly customizable
- Allows us to quickly spin up a development environment
Leave a comment
Use the form below to leave a comment: