If you would create a deployment system for PHP/MySQL web application with several external dependancies, across multiple *nix platforms usually you can use rsync or may be scp, git, and pear for dependencies and some custom scripts.
In the fact, there are a nice solution and interesting one based on three tools : capistrano, jenkins and composer
Capistrano to deploy project to remote servers and be able to rollback when screw up.
Capistrano is a nice ruby application that can perform pre and post-deploy functions like restarting webserver, busting cache, renaming files, running database migrations, with capistrano we can easily copy code from source ( control repository ) to production server.
Capistrano by itself isn’t enough to make my deployment complete, that why my capistrano script will runs composer on the app to gather dependencies.
First , you can get capistrano using gem like that:
sudo gem install capistrano
sudo gem install capistrano-ext
You may get composer using git like this, run :
git clone https://github.com/composer/composer.git
In general, you’ll use Capistrano as follows:
You will create a recipe file (“capfile” or “Capfile”) usgin capify command line as follow :
capify .
This will create config directory and a deploy.rb file that we will edit
vim confing/deploy.rb
deploy.rb is ruby file with a very simple syntax, here is my recipe file that i use to deploy my blog:
set :application, "blog"
#You probably want to change this to be the location of the repo you just forked
set :repository, "git://github.com/WordPress/WordPress.git"
set :php_bin, "/usr/bin/php"
#The following is not the document root, but just the app root
set :deploy_to, "/home/mezgani/www/#{application}/"
set :current, "/home/mezgani/www/#{application}/current"
role :web, "server1", "server2" # Your HTTP server, Apache/etc
role :app, "server1", "server2" # This may be the same as your `Web` server
role :db, "database-server", :primary => true # This is where Rails migrations will run
role :db, "database-server"
set :local_path, "/home/mezgani/config/wordpress/config"
# SSH Settings
set :user, "mezgani"
#set :password, "password"
ssh_options[:keys] = %w(/home/user/.ssh/id_rsa) # SSH key
ssh_options[:port] = 22
#########################
#things you'll probably not change, unless you know what you're doing
###########################
# If you aren't using Subversion to manage your source code, specify
# your SCM below:
# set :scm, :subversion
set :scm, :git
#the following is needed because if it's not there, for some reason we don't get
#asked to accept the key from github..annoying when deploying to a new server
default_run_options[:pty] = true
#since this is PHP, we don't really need to restart apache or anything
set :use_sudo, true
#ssh agent forwarding..
ssh_options[:forward_agent] = true
#A lot of this stuff has been overridden for PHP/Non Rails magic
namespace :deploy do
task :default do
update
finalize_update
composer
end
task :finalize_update, :except => { :no_release => true } do
run "chmod -R g+w #{latest_release}" if fetch(:group_writable, true)
run "cp -fr #{current}/wp-content #{shared_path}/"
run "cp #{current}/.htaccess #{shared_path}/"
run "cp #{current}/wp-config.php #{shared_path}/configs/"
run "cp #{shared_path}/configs/wp-config.php #{latest_release}/"
run "cp -fr #{shared_path}/wp-content #{latest_release}/"
run "chmod -R 777 #{latest_release}/wp-content"
run "cp #{shared_path}/.htaccess #{latest_release}/"
end
end
task :composer do
top.upload("#{local_path}/composer.json", "#{shared_path}/install", {:via => :scp, :recursive => true})
run "cd #{shared_path}/install && curl -s http://getcomposer.org/installer | #{php_bin}"
run "cd #{shared_path}/install && ./composer.phar install"
end
task :setup do
run "sudo apt-get install curl"
run "mkdir #{shared_path}/"
run "mkdir #{shared_path}/install/"
run "mkdir #{shared_path}/configs/"
set(:wp_environment_ready, Capistrano::CLI.ui.ask("Is wp-config.php ready for this environment? (yes/no): "))
if wp_environment_ready == 'yes'
#top.upload("htdocs/wp-config.php", "#{shared_path}/configs/wp-config.php", :via => :scp)
run "cp #{deploy_to}/wp-config.php #{shared_path}/configs/wp-config.php "
end
run "mkdir #{shared_path}/wp-content"
run "mkdir #{shared_path}/wp-content/uploads"
end
Before deploy we have to define a composer.json file that defines all
the dependencies my application has, whether they’re composer enabled or not.
Edit composer.json, specify your dependencies and run composer on capistrano to get the dependencies:
vim composer.json
Finally, use the cap script to execute your recipe. Use the cap script as follows:
cap deploy