AlCapON

Give your eZ Publish installation the power of Capistrano

Features | Install | Doc | Contribute

View the Project on GitHub alafon/alcapon

Capistrano recipe for eZ Publish.

AlCapON is a simple recipe for Capistrano, the well-known deployment toolbox. It helps you dealing with simple task such as pushing your code to your webserver(s), clearing cache, etc.

Features

AlCapON has to be installed only once on your system and can be used multiple times with different configuration, depending on each project's needs.

How does to it works ?

On each of your remote servers, Capistrano will create a tree which looks like this :

$ tree -L 2 application
application
|-- current -> /path/to/application/releases/20120717151916
|-- releases
|   |-- 20120704165734
|   |-- 20120704183051
|   |-- 20120706135251
|   |-- 20120709074137
|   |-- 20120712083257
|   |-- 20120717151704
|   `-- 20120717151916
`-- shared
    |-- cached-copy
    |-- log
    |-- pids
    |-- system
    `-- var

/path/to/application/current will be known by your webserver (Apache, Nginx, whatever) as the document root

Each time you deploy :

Capistrano requirements

Even if the gemspec says that it requires capistrano >= 2.12, it might be compatible with older version. If you've successfully used it on such versions please fell free to give us some feedback.

Note regarding dependencies checks made by the recipe

The `deploy:check` task will make sure that the following are installed :

However, it does not check the followings requirements :

To be honest, I did not investigate more on Capistrano capabilities regarding this kind of features, and it was more a proof of concept. I think that dedicated tasks should be created to really check what we need, so feel free to contribute on this topic.

Installation

$ gem install alcapon

Setting it up

Initialisation

From /path/to/ezpublish, run

$ capezit .

This is a simple initialisation script that will create

Troubleshooting

If the capezit or the cap commands are not found on your system, this is more likely that the Ruby's bin directory has not been added to your PATH env. variable. You can do this by editing ~/.bashrc and add this code at the end :

PATH=$PATH:/var/lib/gems/1.8/bin
export PATH

Common configuration file

config/deploy.rb a common file you might find within any Capistrano recipe. It controls default settings known by Capistrano itself. A sample one has been created for you by the capezit command :

# Comment this if you don't want to use a multistage setup
set :stages, %w(devel production )
set :default_stage, "devel"
require 'capistrano/ext/multistage'

set :application, "myapp"
set :repository,  "git@github.com:username/myapp.git"

set :deploy_to, "/var/www/#{application}"
# The user connecting your server through ssh
set :user, "deploy"

# The default branch used (can be overridden on multistage setup)
set :branch, "master"

# Need if you want to deploy somewhere where sudo is needed
default_run_options[:pty] = true

# Use this to use your ssh keys
# (you might need to run ssh-add /path/to/your/deploy_key before)
ssh_options[:forward_agent] = true
# Or if you want to use a specific key
#ssh_options[:keys] = %w(/home/username/.ssh/id_rsa)

# Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none`
set :scm, :git

# Comment this if you don't use submodules
set :git_enable_submodules, 1

# Prevents you from cloning the whole rep. each deploy but your remote servers
# must be able to get connected to your scm server
set :deploy_via, :remote_cache

# Your Primary HTTP server
# (Use config/deploy/*.rb files instead if you need a multisage setup)
role :web, "domain.com", :primary => true
# Another HTTP server, for instanced when using the clustered mode
#role :web, "server2"

#role :db,  "your primary db-server here", :primary => true # This is where Rails migrations will run
#role :db,  "your slave db-server here"

Important : the multistage ext. is enabled by default. If you don't want to use it, simply comment the first three settings at the top of this file.

eZ Publish configuration files

Because I did not want to use the default deploy.rb file for eZ Publish related stuff, I putted this in a dedicated one in config/ezpublish.rb

# This file contains eZ Publish adjustable variables depending on your custom setup

# Your webserver user and group, used to chmod directories just after deploy:setup
set :webserver_user, "apache"
set :webserver_group, "apache"

# If true, will always turn your webserver offline
# Requires a specific rewrite rule (see documentation)
set :always_turnoff, false

# Array taking all the values given by php bin/php/ezcache.php --list-tags
#
# If you want to clear all caches use :
#set :cache_list, "all"
set :cache_list, [ "template", "ini", "content" ]

# If true, adds '--purge' to the ezcache.php command
# Be careful with that one, some versions are known to completely delete
# your var directory (2012.5 for instance)
set :cache_purge, false

# Set this if you want to be able to sync your remote shared directory
#set :storage_dir, 'var/ezflow_site/storage'
# Set this to tell Capistrano with which host you want to sync your local storage dir
#set :shared_host, "domain.com"

# Which autoloads to generate. By default, regenerates extensions and
# kernel-override autoloads
# Possible values : see bin/php/ezpgenerateautoloads.php --help
set :autoload_list, [ "extension", "kernel-override" ]

# TODO : use yml files to manage database credentials securely
# See http://www.simonecarletti.com/blog/2009/06/capistrano-and-database-yml/
set :database_uname, "dbuname"
set :database_passd, "dbpasswd"
set :database_name, "dbname"

# Not implemented
set :ezpublish_separated_core, false
set :ezpublish_base, "community"
set :ezpublish_version, "2012.5"

# Check-list (used by cap setup:check)
depend :remote, :command, "php"
depend :remote, :match, "php -r \\"echo(version_compare(PHP_VERSION,'5.2.14')?'ok':'ko');\\"", "ok"
depend :remote, :match, "php -m | grep curl", "curl"

# TODO
#Check : PHP memory_limit >= 128
#Check : PHP date.imezone = "something"
#Check : eZ Components (must be bundled if eZ Publish >= 20??.? since there's a patch for Archive)
#Check : If deploy_via remote_cache => check of the remote servers have access to the scm

If you use the multisage feature, then you need to create overrides in order to set different settings for each of your environment. Pretty useful isn't it ?
Fortunately, these files can be generated through a task provided by the multistage ext. (and taking care of the stage names you used in deploy.rb :

$ cap multistage:prepare

devel.rb example :

# This one is used to run command as a specific user with `sudo -u .... command`
set :admin_runner, 'sudoer_user'
set :webserver_user, 'www-data'
set :webserver_group, 'www-data'
set :branch, 'devel'
set :shared_host, 'devel.domain.fr'
role :web, 'devel.domain.fr', :primary => true           # Your Primary HTTP server
role :db,  'devel.domain.fr', :primary => true

production.rb example :

# This one is used to run command as a specific user with `sudo -u .... command`
set :admin_runner, 'sudoer_user'
set :webserver_user, 'apache'
set :webserver_group, 'apache'
set :branch, 'master'
set :shared_host, 'www.domain.fr'
role :web, 'www.domain.fr', :primary => true           # Your Primary HTTP server
role :db,  'www.domain.fr', :primary => true

Deployment

Important : make sure the users have the needed sudo rights so that the needed command ca be run. For instance, you must give your deployment user (set by :user) the ability to run command as your webserver user :

Cmnd_Alias DEPLOY_SHELLS  = /bin/mkdir, /bin/chmod, /bin/chown, /bin/chgrp, /bin/ln, /usr/bin/php

user ALL=(user) NOPASSWD: DEPLOY_SHELLS
user ALL=(apache) NOPASSWD: DEPLOY_SHELLS
so that user can execute command as if he was 'apache'

See a sudo sample here

If you do not have sudo rights on the target env. you can also tell Capistrano not to use sudo by setting use_sudo to false in one of your config file (deploy.rb or deploy/env.rb) :

set :use_sudo, false

In order to setup your remote environements, simply run :

cap deploy:setup
This will create the needed folders on the remote servers.

If you want, you can run cap deploy:check to be sure that your servers are well configured and meet the requirements (currently, only a few of them are implemented)

At the end, you just need to execute the deploy task :

$ cap deploy
And if you use the multistage ext. don't forget to specify to which environment you want to deploy you eZ Publish website :
$ cap production deploy

Settings Deployment

You can run basic in-file replacements by setting the file_changes. It's a dead simple associative array which has to be set in a deploy/*.rb file (which defines a certain environment). Here is an example :

set :file_changes, {
    'settings/override/site.ini.append.php' => {
        'replace' => {
            'SiteURL=devel-www.arnaudlafon.com' => 'SiteURL=www.arnaudlafon.com'
        }
    },
    'settings/override/solr.ini.append.php' => {
        'replace' => {
            'SearchServerURI=http://localhost:8983/solr' => 'SearchServerURI=http://search-server:8983/solr'
        }
    }
}

Because, the system is very basic and only replace a text by another, I'd recommand to use placeholders instead of 'real' values (like in the example above) :

set :file_changes, {
    'settings/override/site.ini.append.php' => {
        'replace' => {
            'SiteURL=@GLOBAL_SITE_URL@' => 'SiteURL=www.arnaudlafon.com',
            'Database=@DATABASE_NAME@' => 'Database=ezpublish'
        }
    },
    'settings/override/solr.ini.append.php' => {
        'replace' => {
            'SearchServerURI=@SEARCH_SERVER_URI@' => 'SearchServerURI=http://search-server:8983/solr'
        }
    }
}

You can also rename files with the 'rename' action :

set :file_changes, {
    'settings/override/site.ini.append.dist' => {
        'rename' => 'settings/override/site.ini.append.php',
        'replace' => {
            'SiteURL=@GLOBAL_SITE_URL@' => 'SiteURL=www.arnaudlafon.com',
            'Database=@DATABASE_NAME@' => 'Database=ezpublish'
        }
    }
}

This is very handy because :

Note that these actions are done every time you deploy your application but you can also run it manually using the cap ezpublish:settings:deploy task

Documentation

Capistrano tasks dedicated to eZ Publish

Note : you can list all the available tasks with cap -vT

task definition comments
cap ezpublish:autoloads:generate # Generates autoloads (extensions and kernel ove...
cap ezpublish:cache:clear # Clear caches the way it is configured in ezpub...
cap ezpublish:dev:local_check # Checks if there are local changes or not (only...
cap ezpublish:var:init_shared # Creates the needed folder within your remote(s...
cap ezpublish:var:link # Link .../shared/var into ../releases/[latest_r...
cap ezpublish:var:sync_to_local # Sync your var directory with a remote one
cap ezpublish:var:sync_to_remote # Sync your remote var folder with local data

Todo List

Known bugs

Symlink usage

Having the var directory being a symlink to somewhere else seems to prevent the cache from working properly, see http://pwet.fr/blog/symlink_to_the_ez_publish_var_directory_a_good_idea for a good explanation on the issue.
Following a recent discussion with Damien, I think that only symlinking the 'storage' folders within var/ should be enough... This also means that var/[^/]/cache will be generated in all the release folders (and we will need to purge them with a dedicated task I think)

UPDATE 2012-08-16 : this should have been fixed in the latest version. var/ is not fully symlink anymore, only the var/[^/]/storage directories are symlinked ; cache & logs are now generated in the release itself.

Contributing to AlCapON

Contributing to the current page is also muchly appreciated :)

Authors and Contributors

Support or Contact

Having trouble with Pages? Check out the documentation at http://help.github.com/pages or contact support@github.com and we’ll help you sort it out.