Simplify Your PHP Deployment Needs with Deployer

Simplify Your PHP Deployment Needs with Deployer September 3rd, 2015, by Matthew Setter

Choice can be a good thing, but often too much choice is worse than too little. You risk becoming overwhelmed, confused, even paralyzed. Come learn about the simplest deployment tool for PHP.

Phing, Jenkins, Capistrano, Capifony, Deploybot, PHPCI, Rocketeer, Teamcity, Envoyer.. How long can this list get?

I read this on Reddit recently, and was honestly taken aback, because I've been looking for a simple method for deploying an application of my own.

It's a small project, one which doesn't, yet, bring in any revenue. So I can only justify limited time on it. So I've been on the look out for something which I can integrate quickly, and start deploying.

Too Much Choice Can Be a Bad Thing

Don't get me wrong, choice can be a good thing, but sometimes too much choice is worse than too little, as you become overwhelmed, confused, and ultimately paralysed - the net result being that you do nothing.

Some of these tools are fully featured, which can result in both a large learning curve and delay in getting to the first deployment, and some of the others come at a financial price.

What I was keen to find, was a solution which was capable, yet required both a minimal investment of time and money to get up and running. Ideally, it'd be a solution which was also written in PHP, and one I could highly configure and customize as I went along.

Then I Found the Solution

Thanks to a colleague, I heard about deployer, which is an open source deployment management tool, written in PHP. Deployer is a fast, modular deployment tool for PHP; one which supports rollbacks, atomic deploys, parallel tasks, and consistent deployments across multiple servers - whether local or remote.

What's more, it creates a series of releases, with a current directory pointing to the latest release. This way, if there's any issues, you can always, quickly, rollback to an earlier release.

How awesome is that?!

Sure, there's a bit to learn, starting from installing, configuring servers to deploy to, deployment tasks, and environment settings. But the deployer config file's written in such a way that it's easy to learn, and doesn't require a lot of configuration.

If your needs are simple, then your configuration file is also simple. What's more, you can start off with a minimalist configuration file, and build it up as your needs grow.

You Don't Need a Lot of Software

That's another great part about deployer, you don't need a lot of infrastructure to get started. All you need are three things:

  1. A server to deploy to: Naturally, you'll need to have these setup, ready to deploy to
  2. PHP 5.4: Whilst I always encourage the latest version, that being 5.6 at the time of writing, 5.4's the minimum supported version, available almost anywhere
  3. Git: You need to grab the latest code, which will be under version control - right?

 Everything Else is Optional

That's right, everything else is an optional extra, or could reasonably be expected to be available with your Linux hosting account.

Sure, in more sophisticated setups, you're likely going to be clearing and warming caches, whether filesystem or external server such as Redis and Memcached, ensuring directories exist and are writable, and so on.

But these, can all be reasonably be handled by tools on the operating system, which should already be available.

 Let's Create a Deployment

If this sounds like a tool for you, then here's how to get up and running - now! Let's work through a simple deployer configuration example, which you can take and use for your own needs and be up and running in the next 30 mins. Sound good?

Assuming you've got a project ready, grab a copy of deployer by running composer require deployer/deployer:~3.0 in the root of your project directory.

Next, create a new file called deployer.php. In it, add the following configuration, which we'll step through. Before we do, the end result will be a local and a remote deployment. I'm assuming that you're running Nginx on your remote server. If you're running Apache, please substitute it as necessary.

<?php

require 'vendor/autoload.php';
require 'recipe/composer.php';

First we include Composer's auto-generated autoload file and a Composer recipe file. In deployer parlance, a recipe is a pre-written set of tasks, which you can make use of, instead of writing your own.

localServer('testing')
    ->user('my_user')
    ->stage('testing')
    ->env('deploy_path', '/path/to/local/deployment/directory');

server('production', 'staging.example.com', '22')
    ->user('username')
    ->password('password')
    ->stage('production')
    ->env('deploy_path', '/path/to/remote/deployment/directory');

Next, we create two server configurations, a local server for testing, and a remote server for production. Through the use of the fluent interface, it's almost trivial to set all of the options required in each case.

For the local server, we've specified the username, the stage name and the deployment path. For the remote server, we've specified the hostname and port to connect on, the username and password, the stage name and deployment path.

There's a range of further options, which you can find in the servers documentation.

set('repository', 'https://github.com/settermjd/some.repository.git');

Next we add some deployer configuration settings, specifically the Git repository which contains the project code. You can set a number of other global variables, as suits your needs.

task('deploy:done', function () {
    write('Deploy done!');
})->desc("When deployment's completed");

task('reload:php-fpm', function () {
    run('sudo /usr/sbin/service php5-fpm reload');
})->desc('Reload PHP5 FPM');

Now we get to the meat of the configuration, the deployment tasks. You can see that a task requires a name and a closure, or callable - handy if you're building a library of tasks.

The first task simply prints out a message that deployment's finished, and the second reloads the PHP5 FPM service. You can add in anything here, which you might normally run from the command line.

after('deploy', 'reload:php-fpm');
after('deploy', 'deploy:done');

Almost done. Now we hook in to some events. These can be either before or after. Here we've hooked in to the deploy event, setting our two custom tasks to run after the deploy's completed. In this case, FPM will reload and the "Deploy done!" message will print out the console.

task('deploy', [
    'deploy:prepare',
    'deploy:release',
    'deploy:update_code',
    'deploy:vendors',
    'deploy:symlink',
    'cleanup'
])->desc("Main deployment process");

One final thing, and we're ready to run - the core deploy task. In this example, deploy is composed of a series of other tasks. In short, this pulls the latest version of the code from the nominated repository, runs a Composer install, and symlinks to the latest release.

Running the Deploy

With everything installed and configured, to run the deploy, from the command line, run the following command:

vendor/bin/dep deploy production

That will deploy your application to your production server.

That's It

Could you ask for anything simpler than that? In just 30 mins, you could have your first deployment running, with just a few lines of PHP code. There's no complicated server setup, no other services to have configured and running, almost nothing. How does it compare to your existing deployment solution?

Share your thoughts in the comments.


Like That?

Don’t miss my next post. Drop your email in the box below, and get it straight to your inbox, PLUS exclusive content only available by email. No spam, and you can unsubscribe at any time.