Deploying PHP Applications with Deployer
Deploying PHP Applications with Deployer
Deployer is a deployment tool written in PHP to be used by PHP applications. Deployer ships with out-of-the-box support for various popular PHP frameworks, including Symfony. For a recent project of mine I needed to execute database migrations during deployment, and hence a simple rsync deployment was not enough. That’s where Deployer kicks in.
Getting Started
Add Deployer to your project with composer require deployer/deployer
and then unleash the beast with php vendor/bin/dep
, which starts the deployment pipeline. To configure the deployment pipeline, you’ll need to create a deploy.php
file in the root directory of your project along the lines of:
<?php
require 'recipe/symfony.php';
// Define a server for deployment.
server('prod', $deployHost, $deployPort)
->user($deployUser)
->forwardAgent()
->stage('production')
->env('deploy_path', $deployPath); // Define the base path to deploy your project to, e.g. /var/www/awesome/app
// Specify the repository from which to download your project's code.
set('repository', '[email protected]:org/app.git');
To deploy the application, you’ll use the dep
command and address the respective stage: dep deploy production
. Thats it! Deployer creates the following directory structure on the target server:
/var/www/awesome/app
|--releases
| |--20160508120631
|--shared
| |--...
|--current -> /var/www/awesome/app/20160508120631
Configure your webserver to serve from the current
symlink and you are all set.
Writing Tasks
Deployer allows to easily define tasks which handle the actual deployment logic. Deployer ships pre-configured tasks tailored to specific frameworks and bundled as receipes. Defining a task and hooking it up in the deploment pipeline is straightforward:
task('database:backup', function () {
// Your tasks code...
})->desc('Relax, the backup is safe!');
before('database:migrations', 'database:backup');
Deployer also ships with useful functions that are ready to use in your tasks. For example, I use brunch to build frontend assets on the CI server and then upload the built assets to the production server during deployment:
task('deploy:upload-brunch-assets', function() {
$upload = [
'web/app.css',
'web/app.js',
];
foreach ($upload as $path) {
upload($path, "{{release_path}}/{$path}");
}
})->desc('Deploy assets built with brunch.');
before('deploy:assets', 'deploy:upload-frontend-assets');
The receipe/symfony.php
already defines a database migration task, but the task is not enabled by default. With Deployer and the Symfony receipe, adding the migrations is a breeze by adding the following line to deploy.php
:
after('deploy:vendors', 'database:migrate');
Automating and Debugging Deployments
I use Deployer from within GitLab CI, so successful builds are automatically deployed to production. Once properly configured, things typically work, but just in case something goes wrong it’s better to prepare. Luckily, Deployer allows to adjust the level of output verbosity. Running Deployer with dep deploy production -vv
stores helpful details in the CI log.
The .gitlab-ci.yml
is configured as follows:
job1:
stage: deploy
only:
- master
tags:
- deploy
script: |
# [...] install, build and test
php vendor/bin/dep deploy production -vv
cache:
paths:
# speed up builds by caching dependencies
- vendor/
- node_modules
- bower_components
Conclusion
Deployer is easy and fun to use. Tailor the provided receipes to your project and enjoy that all deployment-related configuration is stored in a single file. Deployer has a nice and concise syntax for writing tasks and ships a ton of helpful features. Be sure to give it a try!