Skip to content

Instantly share code, notes, and snippets.

@freekmurze
Created March 23, 2017 13:50
Show Gist options
  • Save freekmurze/5b52ceb004b9bdfdc383a3ed84fa999e to your computer and use it in GitHub Desktop.
Save freekmurze/5b52ceb004b9bdfdc383a3ed84fa999e to your computer and use it in GitHub Desktop.
Multi server zero downtime Envoy script
@setup
require __DIR__.'/vendor/autoload.php';
(new \Dotenv\Dotenv(__DIR__, '.env'))->load();
$appName = "my-app.com";
$repository = "spatie/{$appName}";
$baseDir = "/home/forge/{$appName}";
$releasesDir = "{$baseDir}/releases";
$currentDir = "{$baseDir}/current";
$newReleaseName = date('Ymd-His');
$newReleaseDir = "{$releasesDir}/{$newReleaseName}";
$user = get_current_user();
$webServerIps = [
'web-1' => 'xxx.xxx.xxx.xxx',
'web-2' => 'xxx.xxx.xxx.xxx',
];
$webServers = array_keys($webServerIps);
$webServersAndWorker = array_merge($webServers, ['worker']);
function logMessage($message) {
return "echo '\033[32m" .$message. "\033[0m';\n";
}
@endsetup
@servers(array_merge($webServerIps, ['persistent' => 'xxx.xxx.xxx.xxx', 'worker' => 'xxx.xxx.xxx.xxx', 'local' => '127.0.0.1']))
@macro('deploy')
startDeployment
cloneRepository
runComposer
runYarn
updateSymlinks
generateAssets
uploadAssetsToS3
optimizeInstallation
updatePermissions
backupDatabase
insertNewFragments
migrateDatabase
updateVarnishRules
blessNewRelease
restartQueues
flushVarnishCache
cleanOldReleases
finishDeploy
@endmacro
@macro('deploy-code')
deployOnlyCode
restartQueues
flushVarnishCache
@endmacro
@task('startDeployment', ['on' => 'local'])
{{ logMessage("\u{1F3C3} Starting deployment...") }}
git checkout master
git pull origin master
@endtask
@task('cloneRepository', ['on' => $webServersAndWorker, 'parallel' => true])
{{ logMessage("\u{1F300} Cloning repository...") }}
[ -d {{ $releasesDir }} ] || mkdir {{ $releasesDir }};
cd {{ $releasesDir }};
# Create the release dir
mkdir {{ $newReleaseDir }};
# Clone the repo
git clone --depth 1 [email protected]:{{ $repository }} {{ $newReleaseName }}
# Configure sparse checkout
cd {{ $newReleaseDir }}
git config core.sparsecheckout true
echo "*" > .git/info/sparse-checkout
echo "!storage" >> .git/info/sparse-checkout
echo "!public/build" >> .git/info/sparse-checkout
git read-tree -mu HEAD
# Mark release
cd {{ $newReleaseDir }}
echo "{{ $newReleaseName }}" > public/release-name.txt
@endtask
@task('runComposer', ['on' => $webServersAndWorker, 'parallel' => true])
{{ logMessage("\u{1F69A} Running Composer...") }}
cd {{ $newReleaseDir }};
composer install --prefer-dist --no-scripts --no-dev -q -o;
@endtask
@task('runYarn', ['on' => 'worker'])
{{ logMessage("\u{1F4E6} Running Yarn...") }}
cd {{ $newReleaseDir }};
yarn config set ignore-engines true
yarn
@endtask
@task('updateSymlinks', ['on' => $webServersAndWorker, 'parallel' => true])
{{ logMessage("\u{1F517} Updating symlinks to persistent data...") }}
# Remove the storage directory and replace with persistent data
rm -rf {{ $newReleaseDir }}/storage;
cd {{ $newReleaseDir }};
ln -nfs {{ $baseDir }}/persistent/storage storage;
# Import the environment config
cd {{ $newReleaseDir }};
ln -nfs {{ $baseDir }}/.env .env;
@endtask
@task('generateAssets', ['on' => 'worker'])
{{ logMessage("\u{1F305} Generating assets...") }}
cd {{ $newReleaseDir }};
yarn run production
@endtask
@task('uploadAssetsToS3', ['on' => 'worker'])
{{ logMessage("\u{2601} Uploading assets to S3...") }}
cd {{ $newReleaseDir }};
php artisan assets:upload
@endtask
@task('optimizeInstallation', ['on' => $webServersAndWorker, 'parallel' => true])
{{ logMessage("\u{2728} Optimizing installation...") }}
cd {{ $newReleaseDir }};
php artisan clear-compiled;
php artisan optimize;
@endtask
@task('updatePermissions', ['on' => $webServersAndWorker, 'parallel' => true])
{{ logMessage("\u{1F512} Updating permissions...") }}
cd {{ $newReleaseDir }};
find . -type d -exec chmod 775 {} \;
find . -type f -exec chmod 664 {} \;
@endtask
@task('backupDatabase', ['on' => 'worker'])
{{ logMessage("\u{1F4C0} Backing up database...") }}
cd {{ $newReleaseDir }}
php artisan backup:run
@endtask
@task('insertNewFragments', ['on' => 'worker'])
{{ logMessage("\u{3299} Inserting new fragments...") }}
cd {{ $newReleaseDir }};
php artisan fragments:import;
@endtask
@task('migrateDatabase', ['on' => 'worker'])
{{ logMessage("\u{1F648} Migrating database...") }}
cd {{ $newReleaseDir }};
php artisan migrate --force;
@endtask
@task('updateVarnishRules', ['on' => $webServers, 'parallel' => true])
{{ logMessage("\u{1F648} Updating varnish rules...") }}
cd {{ $newReleaseDir }}
sudo rm -f /etc/varnish/default.vcl
sudo cp default.vcl /etc/varnish/default.vcl
@endtask
@task('blessNewRelease', ['on' => $webServersAndWorker, 'parallel' => true])
{{ logMessage("\u{1F64F} Blessing new release...") }}
ln -nfs {{ $newReleaseDir }} {{ $currentDir }};
cd {{ $newReleaseDir }}
php artisan cache:clear
php artisan view:clear
sudo service php7.1-fpm restart
@endtask
@task('restartQueues', ['on' => 'worker'])
sudo supervisorctl restart all
@endtask
@task('flushVarnishCache', ['on' => $webServers, 'parallel' => true])
sudo service varnish restart
@endtask
@task('cleanOldReleases', ['on' => $webServersAndWorker, 'parallel' => true])
{{ logMessage("\u{1F6BE} Cleaning up old releases...") }}
# Delete all but the 5 most recent.
cd {{ $releasesDir }}
ls -dt {{ $releasesDir }}/* | tail -n +6 | xargs -d "\n" sudo chown -R forge .;
ls -dt {{ $releasesDir }}/* | tail -n +6 | xargs -d "\n" rm -rf;
@endtask
@task('finishDeploy', ['on' => 'local'])
{{ logMessage("\u{1F680} Application deployed!") }}
@endtask
@task('deployOnlyCode', ['on' => $webServersAndWorker, 'parallel' => true])
{{ logMessage("\u{1F4BB} Deploying code changes...") }}
cd {{ $currentDir }}
git pull origin master
php artisan cache:clear
php artisan view:clear
@endtask
@after
@slack(env('SLACK_DEPLOYMENT_WEBHOOK_URL'), '#deployments', "{$appName}: {$baseDir} release {$newReleaseName} by {$user}: {$task} done")
@endafter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment