Table of Contents
In this tutorial we're going to look at how you can use Envoy to make it very easy to deploy your Laravel applications. Envoy provides a nice blade style syntax way of running commands on your remote servers. You can use it for multiple purposes but the most common way I've found is for deployments. It allows you to enter the command envoy run deploy
to quickly deploy your code.
Installation
Before you start using Envoy on your Laravel application you first need to install it by using composer.
composer global require "laravel/envoy=~1.0"
Introduction
To get started with Envoy you need to create a file at the root level of your project called Envoy.blade.php
Now you can use the normal Laravel blade syntax to define the commands you want to run on the remote server. Everything you do in Envoy needs to be done by tasks. You can also define different servers by using @servers
. So, if you want to run a command on a remote server to list the files on the server you can use the following code.
@servers(['web' => ['[email protected]']])
@task('foo', ['on' => 'web'])
ls -la
@endtask
This defines a new server called web with a task called foo. You can run this command at the root of project by running the command
envoy run foo
If you want to always run some code before you run through the tasks you can use a @setup
directive to define variable you can use in your tasks.
@setup
$now = new DateTime();
$environment = isset($env) ? $env : "testing";
@endsetup
If you want to pass in different variables into your script you can define this on the command line when calling envoy, for the branch of passing the environment you want to deploy you can use the command.
envoy run deploy --env=production
You'll now be able to pick up this variable in your Envoy script by using the PHP syntax $env
. You can also group tasks together by creating stories, for example when you run a deploy script you want to get the code from git and then run an install on composer to bring in the dependencies and you will define them with the following.
@servers(['web' => '192.168.1.1'])
@story('deploy')
git
composer
@endstory
@task('git')
git pull origin master
@endtask
@task('composer')
composer install
@endtask
Creating A Deployment Script
Now that we have an understanding of how Envoy works we can create a deployment script, the deployment script will need to do multiple activities. - Clone git repository into a new folder
- Change permissions on storage folder
- Apply the correct environment file
- Install composer dependencies
- Run migration files
- Restart any queue runners
- Run artisan optimize
- Symlink the new release folder with the current version of the site
- Clean up old code
Setup The Deployment
In the setup section, we need to define the server we want to use, the repository we want to use, the path to deploy into, the timestamp of the deployment, the environment, the branch of the repository and the release folder.
@setup
if(!isset($user))
{
throw new Exception('User option not set.');
}
$server = $user . '@10.0.4.54';
$repo = '[email protected]:paulund/vagrant-ubuntu-nginx.git';
$path = '/var/www/website';
if ( substr($path, 0, 1) !== '/' ) throw new Exception('Careful - your deployment path does not begin with /');
$date = ( new DateTime )->format('YmdHis');
$env = isset($env) ? $env : "production";
$branch = isset($branch) ? $branch : "master";
$path = rtrim($path, '/');
$release = $path.'/'.$date;
@endsetup
Create Deploy Story
We're going to create a deploy story which will perform all the tasks that we need to do during the deployment.
@story('deploy')
deployment_start
deployment_links
deployment_composer
deployment_migrate
deployment_queue
deployment_cache
deployment_optimize
deployment_finish
deployment_cleanup
@endstory
At the start of the deployment, we need to clone the repository from the required branch into the release folder.
@task('deployment_start')
cd {{ $path }};
echo "Deployment ({{ $date }}) started";
git clone {{ $repo }} --branch={{ $branch }} --depth=1 -q {{ $release }} ;
echo "Repository cloned";
@endtask
After the code has been cloned into the new folder then we can change the permissions of the bootstrap and the storage folder. We'll then take the env variable and copy the required environment to the .env file.
@task('deployment_links')
cd {{ $release }};
chmod 777 bootstrap/*
echo "Bootstrap permissions done";
chmod 777 -R {{ $release }}/storage
echo "Changed storage permission"
cp {{ $release }}/.env.{{ $env }} {{ $release }}/.env
echo "Change Environment link"
@endtask
Then we can install the composer dependencies inside the release folder.
@task('deployment_composer')
cd {{ $release }};
composer install --no-interaction --quiet;
@endtask
We're able to update the database with any new changes by running the migration files for the correct environment.
@task('deployment_migrate')
php {{ $release }}/artisan migrate --env={{ $env }} --force --no-interaction;
@endtask
If you're running any queue workers then you may need to restart the queues.
@task('deployment_queue')
php {{ $release }}/artisan queue:restart --no-interaction;
@endtask
You will need to clear your application cache to make sure everything has refreshed correctly.
@task('deployment_cache')
php {{ $release }}/artisan view:clear --quiet;
php {{ $release }}/artisan cache:clear --quiet;
php {{ $release }}/artisan config:cache --quiet;
echo 'Cache cleared';
@endtask
You can optimize the class loader by running the following command.
@task('deployment_optimize')
php {{ $release }}/artisan optimize --quiet;
@endtask
At the end of the deployment you can add the symlink from the release folder to the current folder
@task('deployment_finish')
ln -nfs {{ $release }} {{ $path }}/current;
echo "Deployment ({{ $date }}) finished";
@endtask
As you clone into a new release folder these can add up over time and you can use the following command to remove any old folders.
@task('deployment_cleanup')
cd {{ $path }};
find . -maxdepth 1 -name "20*" -mmin +2880 | head -n 5 | xargs rm -Rf;
echo "Cleaned up old deployments";
@endtask
To run this envoy script you can use the command
envoy run deploy --env=production --user=paulund
To deploy your application onto your server, if you also want to use this for your UAT server then you simply need to add the server to the web server array and change the environment variable you pass into the script.