Skip to content

Instantly share code, notes, and snippets.

@andypost
Last active December 17, 2019 14:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andypost/ad3699148bdcad99f2fa16e4d5554268 to your computer and use it in GitHub Desktop.
Save andypost/ad3699148bdcad99f2fa16e4d5554268 to your computer and use it in GitHub Desktop.
<?php
/**
* @file
* Backup tasks for Deployer.
*/
namespace Deployer;
/**
* Create db backup.
*/
task('backup:db', function () {
$stage = get('stage');
$php_id = get('php_container_id');
cd('{{deploy_path}}');
run('mkdir -p ./backup');
run('
export $(cat .env | xargs) &&
docker exec -tu www-data ' . $php_id . ' ash -c "cd /var/www/html && drush sql-dump --structure-tables-key=common" | gzip > ./backup/dbdump--' . $stage . '--$(date +"%Y-%m-%d_%H-%M-%S")--TAG-$DEPLOY_TAG.sql.gz',
['tty' => TRUE]
);
});
/**
* Create files backup.
*/
task('backup:files', function () {
$stage = get('stage');
cd('{{deploy_path}}');
run('mkdir -p ./backup');
run('
export $(cat .env | xargs) &&
tar -czf ./backup/files--' . $stage . '--$(date +"%Y-%m-%d_%H-%M-%S")--TAG-$DEPLOY_TAG.tar.gz *.yml data .env',
['tty' => TRUE]
);
});
/**
* Remove old backups, leave only N latest.
*/
task('backup:remove_old_backups', function () {
cd('{{deploy_path}}');
$keep_amount = ask('How many backups to keep?', 5);
run("
rm `ls -t ./backup/*.tar.gz | awk 'NR>$keep_amount'` &&
rm `ls -t ./backup/*.sql.gz | awk 'NR>$keep_amount'` &&
docker system prune -af
");
});
<?php
/**
* @file
* Main deploy recipe for Deployer.
*/
namespace Deployer;
/**
* Ask user which tag to deploy.
*/
task('deploy:set_tag', function () {
$deploy_tag = ask('Enter tag name you you want to deploy. Make sure you have php image in registry with this tag.');
set('deploy_tag', $deploy_tag);
});
/**
* Find php container ID.
*/
task('deploy:set_php_container_id', function () {
cd('{{deploy_path}}');
// Find php container name.
$containers = run('docker-compose ps php');
$containers = explode("\n", $containers);
$php_id = explode(' ', array_pop($containers))[0];
set('php_container_id', $php_id);
});
/**
* Update docker configuration files if needed.
*/
task('deploy:update_docker_config', function () {
// Ask user if we need to update docker config.
if (!askConfirmation('Do you want to update Docker configuration files?
Warning! It will cause project downtime during containers rebuild')) {
set('docker_config_updated', FALSE);
return;
}
// Set env variables.
$stage = get('stage');
$namespace = get('namespace');
$projectName = $namespace . $stage;
$deploy_tag = get('deploy_tag');
// Drop running containers if there are any.
cd('{{deploy_path}}');
if (test('[ -f {{deploy_path}}/docker-compose.yml ]')) {
run("docker-compose down --remove-orphans", [
'timeout' => NULL,
'tty' => TRUE,
]);
}
// Replace docker configuration.
upload('docker/deploy/docker-compose.yml', '{{deploy_path}}/docker-compose.yml');
$compose_override = 'docker-compose.others.yml';
if (in_array($stage, ['prod', 'prod_cn'])) {
$compose_override = 'docker-compose.' . $stage . '.yml';
}
upload('docker/deploy/' . $compose_override, '{{deploy_path}}/docker-compose.override.yml');
upload('docker/deploy/conf', '{{deploy_path}}/', ['options' => '-avh --delete']);
run("
echo COMPOSE_PROJECT_NAME=$projectName > .env &&
echo DEPLOY_TAG=$deploy_tag >> .env &&
docker-compose pull --parallel &&
docker-compose up -d &&
sleep 30
",
[
'timeout' => NULL,
'tty' => TRUE,
]
);
set('docker_config_updated', TRUE);
});
/**
* Switch to new php container, without full rebuild.
*/
task('deploy:switch_tag', function () {
// Run in case docker config was not updated.
if (!get('docker_config_updated')) {
cd('{{deploy_path}}');
$stage = get('stage');
$namespace = get('namespace');
$projectName = $namespace . $stage;
$deploy_tag = get('deploy_tag');
$container_name = $projectName . '_php_';
$first_num = run('docker ps | awk \'{print $NF}\' | grep ' . $container_name . ' | awk -F "_" \'{print $NF}\' | sort | head -1');
$outdated_container = $container_name . $first_num;
run("
sed -i '/DEPLOY_TAG=.*/c\\DEPLOY_TAG=$deploy_tag' .env &&
docker-compose up -d --scale php=2 --no-recreate &&
sleep 60 &&
docker stop $outdated_container &&
docker rm $outdated_container &&
docker-compose restart nginx
", [
'timeout' => NULL,
'tty' => TRUE,
]);
}
});
/**
* Run Drupal update.
*/
task('deploy:update_drupal', function () {
cd('{{deploy_path}}');
$php_id = get('php_container_id');
run("docker exec -itu www-data $php_id sh scripts/deploy.sh", [
'timeout' => NULL,
'tty' => TRUE,
]);
});
task('deploy:sync_files', function () {
// Set env variables.
$stage = get('stage');
// Sync files to Chinese and Preprod env from production server.
if (!in_array($stage, ['prod_cn', 'preprod'])) {
return;
}
$uid = run('id -u');
$gid = run('id -g');
$file_dir = get('deploy_path') . '/data/sites/default/files/';
$hostname = $stage == 'preprod' ? 'internal_ip' : 'hostname';
$host = get($hostname);
$user = get('user');
$port = get('port');
$php_id = get('php_container_id');
run('docker exec ' . $php_id . ' /bin/sh -c "chown ' . $uid . ':' . $gid . ' /var/www/html/web/sites -R"');
// Push files from prod server to this env.
$production = Deployer::get()->hosts['prod'];
$production->set('push_to_dir', $file_dir);
$production->set('push_to_host', $host);
$production->set('push_to_user', $user);
$production->set('push_to_port', $port);
on(host('prod'), function ($production) {
$file_dir = $production->get('push_to_dir');
$host = $production->get('push_to_host');
$user = $production->get('push_to_user');
$port = $production->get('push_to_port');
run(
"rsync -avh --delete -e " . "'" . "ssh -p$port" . "'" . " {{deploy_path}}/data/sites/default/files/ $user@$host:$file_dir",
[
'timeout' => NULL,
'tty' => TRUE,
]
);
});
});
// Set correct permissions to files directory.
task('deploy:chown', function () {
// Run deploy jobs.
cd('{{deploy_path}}');
$php_id = get('php_container_id');
run('docker exec ' . $php_id . ' /bin/sh -c "chown www-data: /var/www/html/web/sites/default/files -R"');
});
<?php
/**
* @file
* Deployment script for Deployer.
*/
namespace Deployer;
require 'recipe/common.php';
require 'docker/deploy/recipe/backup.php';
require 'docker/deploy/recipe/rollback.php';
require 'docker/deploy/recipe/deploy.php';
inventory('hosts.yml');
set('namespace', 'my');
task('deploy', [
'backup:db',
'backup:files',
'deploy:update',
'backup:remove_old_backups',
]);
task('deploy:update', [
'deploy:update_docker_config',
'deploy:switch_tag',
'deploy:update_drupal',
'deploy:sync_files',
]);
before('deploy:update', 'deploy:set_tag');
before('deploy:update_drupal', 'deploy:set_php_container_id');
before('rollback:db', 'deploy:set_php_container_id');
before('rollback:files', 'deploy:set_php_container_id');
before('backup:db', 'deploy:set_php_container_id');
before('deploy:sync_files', 'deploy:set_php_container_id');
before('deploy:chown', 'deploy:set_php_container_id');
after('deploy:sync_files', 'deploy:chown');
after('rollback:files', 'deploy:chown');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment