Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to link chef with capistrano for deployment

I have configured chef environment and i am able to deploy my application using capistrano . Now i want to my chef to handle capistrano to deploy my apps . How can it be done ?

like image 823
mbdvg Avatar asked Mar 12 '13 13:03

mbdvg


People also ask

How does Capistrano work?

Capistrano is a framework written in Ruby that provides automated deploy scripts. It connects to your web server via SSH and executes a bunch of tasks that will make your app ready to shine.

How do I run Capfile?

Navigate to your application's root directory in Terminal and run the following command: capify . This command creates a special file called Capfile in your project, and adds a template deployment recipe at config/deploy.

What is Capistrano rails?

Capistrano is a framework written in Ruby language that provides automated deployment. Similar to Rake tasks in Ruby language, it runs on the remote servers via SSH. It can be configured on the local or remote server.


2 Answers

I do the opposite, ie. deploy my Chef recipes via Capistrano. I recommend it.

#config/deploy.rb
...
before 'bundle:install', "provision:default", "deploy:config_db_yml_symlink"
...

This will execute the chef config for a server after before bundle install, which is important because a lot of gems rely on packages being installed to the OS.

#config/deploy/provision.rb
Capistrano::Configuration.instance(:must_exist).load do
  namespace :provision do
    task :default do
      provision.setup
      provision.web
      provision.db
      provision.db_slave
    end

    task :setup, once: true do
      provision.get_environment_variables
      provision.update_cookbooks
    end

    task :db, :roles => :db do
      next if find_servers_for_task(current_task).empty?
      if rails_env == 'staging'
        run %{cd #{release_path}/provision; sudo chef-solo -c solo.rb -j db.json -l debug}
      else
        run %{cd #{release_path}/provision; sudo chef-solo -c solo.rb -j db_master.json -l debug}
      end
    end

    task :db_slave, :roles => :db_slave do
      next if find_servers_for_task(current_task).empty?
      run %{cd #{release_path}/provision; sudo chef-solo -c solo.rb -j db_slave.json -l debug}
    end

    task :web, :roles => :web do
      next if find_servers_for_task(current_task).empty?
      run %{cd #{release_path}/provision; sudo chef-solo -c solo.rb -j web.json -l debug}
    end

    task :get_environment_variables do
      run "if [ -d ~/.config ]; then " +
        "cd ~/.config && git fetch && git reset origin/master --hard; " +
        "else git clone [email protected]:mycompany/config.git .config; fi"
      run "sudo cp ~/.config/secureshare/#{rails_env}/environment /etc/environment"
    end

    task :update_cookbooks do
      run "if [ -d /u/chef ]; then " +
        "cd /u/chef && git fetch && git reset origin/master --hard; " +
        "else git clone [email protected]:mycompany/chef.git /u/chef; fi"
    end
  end

  namespace :deploy do
    task :setup, :except => { :no_release => true } do
      dirs = [deploy_to, releases_path, shared_path]
      dirs += shared_children.map { |d| File.join(shared_path, d.split('/').last) }
      dirs += [File.join(shared_path, 'sockets')]
      run "#{try_sudo} mkdir -p #{dirs.join(' ')}"
      run "#{try_sudo} chmod g+w #{dirs.join(' ')}" if fetch(:group_writable, true)
      run "#{try_sudo} chown -R ubuntu:ubuntu #{dirs.join(' ')}" if fetch(:group_writable, true)
    end

    task :config_db_yml_symlink do
      run "ln -s #{shared_path}/database.yml #{release_path}/config/database.yml"
    end
  end
end

I have a folder in my project named provision, to handle the definition of chef roles, though the recipes are in a different repository.

#provision/solo.rb
root = File.absolute_path(File.dirname(__FILE__))
cookbook_path '/u/chef'
role_path root + "/roles"
log_level :debug
log_location STDOUT

Nodes are defined in the project

#provision/db_slave.json
{
  "run_list": ["role[db_slave]"]
}

And roles

#provision/roles/db_slave.rb
name "db_slave"
description 'A postgresql slave.'
run_list(["recipe[base]", "recipe[postgresql::slave]", "recipe[rails]","recipe[papertrail]", "recipe[fail2ban]"])
override_attributes(
  'kernel' => {
  'shmmax' => ENV['KERNEL_SHMMAX'],
  'shmall' => ENV['KERNEL_SHMALL'],
  'msgmax' => ENV['KERNEL_MSGMAX'],
  'msgmnb' => ENV['KERNEL_MSGMNB']  
},
'postgresql' => {
  'user'     => ENV['PG_USER'],
  'password' => ENV['PG_PASSWORD'],
  'database' => ENV['PG_DATABASE'],
  'master_host' => ENV['PG_HOST']
},
'app_dir' => ENV['APP_DIR'],
'papertrail' => {
  'port' => ENV['PAPERTRAIL_PORT'],
  'log_files' => [
    "#{ENV['APP_DIR']}/shared/log/*.log",
    "/var/log/*.log",
    "/var/log/syslog",
    "/var/log/upstart/*.log",
    "/var/log/postgresql/*.log"
  ]
},
'new_relic' => {
  'key' => ENV['NEW_RELIC_LICENSE_KEY']
})

All without keeping any sensitive information within the app. I also use capistrano-ec2group in order to map servers to roles using EC2 security groups.

group :myapp_web, :web
group :myapp_web, :app
group :myapp_db, :db, :primary=>true
group :myapp_db_slave, :db_slave

So basically you keep your chef recipes in one repo, your environment variables in another repo, and your app in another repo - and use Capistrano to both provision servers and deploy your app.

You could also keep your chef recipes in your application repo, but that inhibits reuse between project. The key is to put everything that changes into environment variables and store them separate to the app and the recipes.

When this is configured correctly, to add new servers you simply need to spin one up in EC2, apply the desired security group and then

cap deploy
like image 148
Chris Aitchison Avatar answered Oct 03 '22 20:10

Chris Aitchison


You could watch that Foodfightshow Episode about Application Deployment.

You can e.g. put the configuration files (with e.g. the database credentials) to the server with Chef, while pushing the source code with Capistrano.

like image 35
StephenKing Avatar answered Oct 03 '22 21:10

StephenKing