I take feedback from your comments and my own recent experience to develop a more advanced Envoy deployment script.
We'll grab from GitHub quicker, use ACL permissions, see how to allow our deploy user to use sudo securely, persist log files and more edge cases.
The improved script will handle environment files, the log directory, allowing the deploy user to reload PHP-FPM and more!Here are all the tweaks we make to our Envoy configuration.
The Original
Here's what we're starting from:
@servers(['web' => 'deploy-ex'])
<?php
$repo = 'git@github.com:Servers-for-Hackers/deploy-ex.git';
$release_dir = '/var/www/releases';
$app_dir = '/var/www/app';
$release = 'release_' . date('YmdHis');
?>
@macro('deploy', ['on' => 'web'])
fetch_repo
run_composer
update_permissions
update_symlinks
@endmacro
@task('fetch_repo')
[ -d {{ $release_dir }} ] || mkdir {{ $release_dir }};
cd {{ $release_dir }};
git clone {{ $repo }} {{ $release }};
@endtask
@task('run_composer')
cd {{ $release_dir }}/{{ $release }};
composer install --prefer-dist;
@endtask
@task('update_permissions')
cd {{ $release_dir }};
chgrp -R www-data {{ $release }};
chmod -R ug+rwx {{ $release }};
@endtask
@task('update_symlinks')
ln -nfs {{ $release_dir }}/{{ $release }} {{ $app_dir }};
chgrp -h www-data {{ $app_dir }};
@endtask
And now we'll go over the changes in the video.
Always clone into the master branch
Change
git clone {{ $repo }} {{ $release }};
to:
git clone -b master {{ $repo }} {{ $release }};
ACL's over group permissions
In the production server:
Check setfacl
exists:
which setfacl
# If doesn't exist:
sudo apt-get install -y acl
Then use it:
# Inspect current ACL's
getfacl /var/www
# Set current and default ACL's for /var/www
sudo setfacl -Rm g:www-data:rwx,d:g:www-data:rwx /var/www
Now user deployer
(which is part of group www-data
) can read, write and execute directories in files in /var/www
despite current group settings and permissions.
Visudo
Allow group www-data
to run sudo service php5-fpm [reload|restart]
without requiring a password:
# Run as super user
sudo visudo
Add:
%www-data ALL=(ALL:ALL) NOPASSWD:/usr/sbin/service php5-fpm restart,/usr/sbin/service php5-fpm reload
Or we can create and edit file
/etc/sudoers.d/wwwdata
and add that same line.
Then lastly have the deploy user reload PHP-FPM after deployment. Add the following to the bottom of the update_symlinks
section:
sudo service php5-fpm reload
Handle .env File:
We don't want our .env
file in our code repository. We'll put it on our server and symlink to it, so it's available to each deployed version of our application.
On the production server:
# Create and edit the .env file as needed
vim /var/www/.env
Then in the Envoy configuration, update the update_symlinks
section:
cd {{ $release_dir }}/{{ $release }};
ln -nfs ../../.env .env;
chgrp -h www-data .env;
Handle Composer with correct environment
Make sure the post-install commands, as defined in Laravel's composer.json
, run in the correct environment. Add the following into the run_composer
section:
composer install --prefer-dist --no-scripts;
php artisan clear-compiled --env=production;
php artisan optimize --env=production;
Persist Log Files
The directory storage/logs
will get overwritten every time we deploy. We want our logs to be in a central place, however. We can use symlinks to accomplish this.
On the production server:
sudo mkdir /var/www/logs
sudo chown www-data:www-data /var/www/logs
Then in the Envoy configuration, under update_symlinks
, add the following:
rm -r {{ $release_dir }}/{{ $release }}/storage/logs;
cd {{ $release_dir }}/{{ $release }}/storage;
ln -nfs ../../../logs logs;
chgrp -h www-data logs;
Final Product:
@servers(['web' => 'deploy-ex'])
<?php
$repo = 'git@github.com:Servers-for-Hackers/deploy-ex.git';
$release_dir = '/var/www/releases';
$app_dir = '/var/www/app';
$release = 'release_' . date('YmdHis');
?>
@macro('deploy', ['on' => 'web'])
fetch_repo
run_composer
update_permissions
update_symlinks
@endmacro
@task('fetch_repo')
[ -d {{ $release_dir }} ] || mkdir {{ $release_dir }};
cd {{ $release_dir }};
git clone -b master {{ $repo }} {{ $release }};
@endtask
@task('run_composer')
cd {{ $release_dir }}/{{ $release }};
composer install --prefer-dist --no-scripts;
php artisan clear-compiled --env=production;
php artisan optimize --env=production;
@endtask
@task('update_permissions')
cd {{ $release_dir }};
chgrp -R www-data {{ $release }};
chmod -R ug+rwx {{ $release }};
@endtask
@task('update_symlinks')
ln -nfs {{ $release_dir }}/{{ $release }} {{ $app_dir }};
chgrp -h www-data {{ $app_dir }};
cd {{ $release_dir }}/{{ $release }};
ln -nfs ../../.env .env;
chgrp -h www-data .env;
rm -r {{ $release_dir }}/{{ $release }}/storage/logs;
cd {{ $release_dir }}/{{ $release }}/storage;
ln -nfs ../../../logs logs;
chgrp -h www-data logs;
sudo service php5-fpm reload;
@endtask
Resources
- Original Deploying with Envoy cast
- Notes on safely editing sudoers configuration