Deployer - Capistrano for PHP projects

You want to build your custom VPS and deploy your code easily?

You can consider building git deploy solution with git hooks and scripts on your server or you can go with something Ruby developers do for a while, execute a bunch of commands over ssh.

As someone who is developing in Ruby I'm in contact with capistrano pretty much every day, and I must admit it's great tool for deploying your code to live servers.

Deployer is exact match written in PHP. I discovered it few months ago, and finally tested it, and I'm happy to share some thoughts.

It's absolutely possible to use capistrano for deploying PHP project, because tool actually runs on your local machine, and execute shell commands over ssh on the server. But it is interesting to have deployment configuration in same language as project, it has less dependencies in development environment.

First thing I noticed is syntax that recalls Capistrano 2.x memories. For example running deploy task on servers marked as production:

capistrano 2.x cli command:

cap deploy production

capistrano 3.x cli command:

cap production deploy

deployer cli command:

dep deploy production

Other than that, everything else is similar too. So dep expects deploy.php file in current working directory, and it will use that file for configuration.

Keep in mind your server must have all dependencies for running specified tasks, e.g. git for fetching code from the repo.

Installation

Install globally and use it anywhere:

curl -sO http://gordalina.github.io/cachetool/downloads/cachetool.phar
mv deployer.phar /usr/local/bin/dep
chmod +x /usr/local/bin/dep

Or install it as a project's dependencie:

composer require deployer/deployer:^3.0

This way you can even put it in "require-dev" block and get functions recognized by your IDE or editor of choice, and avoid installing it on live servers too.

Configuration

Consult official documentation and discover how to define variables and use existing recipes.

This is configuration I've used during this test:

<?php
require 'recipe/laravel.php';
set('repository', 'git@example.com:user/repo.git');
set('http_user', 'deploy');server('production', '127.0.0.1')
    ->user('deploy')
    ->env('deploy_path', '/home/deploy/apps/djordjekovacevic.com')
    ->identityFile()
    ->stage('production')
    ->forwardAgent();

So I pulled existing recipes for laravel, which will do those things for you:

  • create directories structure
  • pull latest code from your git repo
  • pull composer
  • install dependencies
  • symlink storage/ and .env from shared/ dir
  • symlink current to release dir if everything went well

By default deployer will deploy mater branch, but you can override that with optional param tag:

dep deploy production --tag=my-test-branch

I used my ssh key to identify myself instead of password, and I also forwarded my identity agent to enable pulling from my git repo with same key instead of having one more key sitting on the server. Keep in mind that this setup require correct configuration of ssh agent on your server, your public key inside .ssh/authorization_keys file on the server and your git repo inside .ssh/known_hosts file.

Reset you OPcache after deploy

I used PHP-FPM 7, and by default it has Zend OPcache enabled. So after deployment you have to reset cache, or you won't be able to see changes for a while!

There are two possibilities, reloading FPM process (this operation require sudoing), or running reset via PHP. I've chose second, because I have correct privileges to execute that code without sudo.

I did it with gordalina/cachetool package. You install it on the server and create additional task that looks like this:

task('opcache:reset', function () {
    run('php cachetool.phar opcache:reset --fcgi=/run/php/php7.0-fpm.sock');
});
after('deploy', 'opcache:reset');

I mean it's so fun for me, I'll consider VPS instead of PaaS solutions :)