Deploying with Idephix¶
Deploying a PHP application can be done in many ways, this recipe shows you our best strategy for a generic PHP application, and it is composed of several steps:
- Preparing the local project
- Preparing the remote server
- Syncing the project to the server
- Linking shared files across releases (configuration files, cache, logs, etc)
- Switching the symlink for the new release, finalizing the deploy
The recipe organize your code on the server using a directory hierarchy borrowed from Capistrano:
├── current -> /var/www/my_app_name/releases/20150120114500/
├── releases
│ ├── 20150080072500
│ ├── 20150090083000
│ ├── 20150100093500
│ ├── 20150110104000
│ └── 20150120114500
└── shared
└── <linked_files and linked_dirs>
So you can keep multiple releases on the server and switch the current release just creating a symlink to the actual one you want to make current. This allows you to easily rollback from one release to another.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | <?php
function deploy(Idephix\Context $context, $go = false)
{
$sharedFiles = $context->get('deploy.shared_files', array());
$sharedFolders = $context->get('deploy.shared_folders', array());
$remoteBaseDir = $context->get('deploy.remote_base_dir');
$rsyncExclude = $context->get('deploy.rsync_exclude');
$repository = $context->get('deploy.repository');
$deployBranch = $context->get('deploy.branch');
$nextRelease = "$remoteBaseDir/releases/" . time();
$linkedRelease = "$remoteBaseDir/current";
$localArtifact = '.deploy';
$context->prepareArtifact($localArtifact, $repository, $deployBranch, $go);
$context->prepareSharedFilesAndFolders($remoteBaseDir, $sharedFolders, $sharedFiles, $go);
try {
$context->remote("cd $remoteBaseDir && cp -pPR `readlink {$linkedRelease}` $nextRelease");
} catch (\Exception $e) {
$context->output()->writeln('<info>First deploy, sending the whole project</info>');
}
$dryRun = $go ? '' : '--dry-run';
$context->rsyncProject($nextRelease, $localArtifact . '/', $rsyncExclude, $dryRun, $go);
$context->linkSharedFilesAndFolders($sharedFiles, $sharedFolders, $nextRelease, $remoteBaseDir, $go);
$context->switchToNextRelease($remoteBaseDir, $nextRelease, $go);
}
function prepareArtifact(Idephix\Context $context, $localArtifact, $repository, $deployBranch, $go = false)
{
$context->local(
"
rm -Rf {$localArtifact} && \\
git clone {$repository} {$localArtifact} && \\
cd {$localArtifact} && \\
git fetch && \\
git checkout --force {$deployBranch} && \\
composer install --no-dev --prefer-dist --no-progress --optimize-autoloader --no-interaction
",
!$go
);
}
function prepareSharedFilesAndFolders(Idephix\Context $context, $remoteBaseDir, $sharedFolders, $sharedFiles, $go = false)
{
$context->remote(
"mkdir -p {$remoteBaseDir}/releases && \\
mkdir -p {$remoteBaseDir}/shared",
!$go
);
foreach ($sharedFolders as $folder) {
$context->remote("mkdir -p {$remoteBaseDir}/shared/{$folder}", !$go);
}
foreach ($sharedFiles as $file) {
$sharedFile = "{$remoteBaseDir}/shared/{$file}";
$context->remote("mkdir -p `dirname '{$sharedFile}'` && touch \"$sharedFile\"", !$go);
}
}
function linkSharedFilesAndFolders(Idephix\Context $context, $sharedFiles, $sharedFolders, $nextRelease, $remoteBaseDir, $go = false)
{
foreach (array_merge($sharedFiles, $sharedFolders) as $item) {
$context->remote("rm -r $nextRelease/$item", !$go);
$context->remote("ln -nfs $remoteBaseDir/shared/$item $nextRelease/$item", !$go);
}
}
function switchToNextRelease(Idephix\Context $context, $remoteBaseDir, $nextRelease, $go = false)
{
$context->remote(
"
cd $remoteBaseDir && \\
ln -nfs $nextRelease current",
!$go
);
}
|
These tasks are based on several configuration options that you can define in your idxrc.php file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <?php
$environments = array(
'prod' => array(
'hosts' => array('127.0.0.1'),
'ssh_params' => array(
'user' => 'ideato',
// 'password' => '',
// 'public_key_file' => '',
// 'private_key_file' => '',
// 'private_key_file_pwd' => '',
// 'ssh_port' => '22'
),
'deploy' => array(
'repository' => './',
'branch' => 'origin/master',
'shared_files' => array('app/config/parameters.yml'),
'shared_folders' => array('app/cache', 'app/logs'),
'remote_base_dir' => '/var/www/testidx',
'rsync_exclude' => './rsync_exclude.txt',
)
),
);
return
array(
'envs' => $environments,
'ssh_client' => new \Idephix\SSH\SshClient(),
'extensions' => array(
'rsync' => new \Idephix\Extension\Project\Rsync(),
),
);
|