Rubber Deployment Notes on EC2 for Rails App.

I need deployment my rails app on EC2 recently,  actually I use Heroku for a while, Heroku is excellent for development, but the price is not very well compare to EC2, also it's was little slow when access from China.

So I decide to deployment it to EC2, unlike Heroku, Setup  EC2 require a lots of setting, which is headache for every one. But I found Rubber, and excellent tool for setup environment on EC2, it based on Capistrano.

From these link1, link2,  I can start to do with rubber.

In my first try, I setup all db, app, web, all all server to a single EC2 instance, but there is a lot minor issue, record them here:

1. in rubber.yml, make sure set correct private net mask, default was 10.0.0.0/8, but in some AWS Region, it was become like 172.0.0.0/8, make sure it added to the list, otherwise, your app instance maybe can not access your db instance.

2. When build redis, I found it become build failed, like depends on jemalloc.a not been found, the fix is redis build Makefile sucks, and it need add following like into deloy-redis.rb (between two > )

>           tar -zxf redis-#{rubber_env.redis_server_version}.tar.gz
          # Build the binaries.
          cd redis-#{rubber_env.redis_server_version}
          cd deps; make hiredis jemalloc linenoise lua; cd ..  # to fix the build error.
>           make

3. postgresql, because my postgresql require uuid-ossp, I have add following task warper in config/deploy.rb

namespace :rubber do

  namespace :project do

    before "deploy:migrate", "rubber:project:add_pg_superuser_and_enable_hstore"
    after "deploy:migrate", "rubber:project:remove_pg_superuser"

    task :add_pg_superuser_and_enable_hstore,
         :roles => [:postgresql_master, :postgresql_slave] do
      alter_user_cmd = "ALTER USER #{rubber_env.db_user} SUPERUSER;"
      create_ext_cmd = 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp";'
      rubber.sudo_script "add_superuser_create_hstore", <<-ENDSCRIPT
      ENDSCRIPT
      rsudo "sudo -i -u postgres psql -c "#{create_ext_cmd}""


    end

    task :remove_pg_superuser, :roles => [:postgresql_master,
                                          :postgresql_slave] do
      alter_user_cmd = "ALTER USER #{rubber_env.db_user} NOSUPERUSER"
      rubber.sudo_script "add_superuser_create_hstore", <<-ENDSCRIPT
        sudo -i -u postgres psql -c "#{alter_user_cmd}"
      ENDSCRIPT
    end

  end

Also need this package change in rubber-postgresql.yml : 36

packages: [postgresql-client, libpq-dev, postgresql-contrib]

4. About figaro

If you're save your secret in ENV var like me, you maybe want to use figaro,
but when you use github to deploy code, the application.yml is not check in to repo, so you need add a task in your config/deploy.rb

# This task make sure application.yml will copy after git.
namespace :figaro do
  desc "SCP transfer figaro configuration to the shared folder"
  task :setup do
    transfer :up, "config/application.yml", "#{shared_path}/application.yml", via: :scp
  end
 
  desc "Symlink application.yml to the release path"
  task :symlink do
    run "ln -sf #{shared_path}/application.yml #{latest_release}/config/application.yml"
  end
 
  desc "Check if figaro configuration file exists on the server"
  task :check do
    begin
      run "test -f #{shared_path}/application.yml"
    rescue Capistrano::CommandError
      unless fetch(:force, false)
        logger.important 'application.yml file does not exist on the server "shared/application.yml"'
        exit
      end
    end
  end
end
after "deploy:setup", "figaro:setup"
after "deploy:finalize_update", "figaro:symlink"

5. Github ssh.

Because you maybe using a private github account to do deployment, you need to use ssh auth, but you don't want to the private put in every EC2 instance.

So you can consider use ssh agent forwarding to do this job, you need 3 steps to make it happen:
a)   add following to your ~/.ssh/config

Host *.compute.amazonaws.com
  ForwardAgent yes

b) use this command to generate a new key for the deployment.

ssh-keygen -f ~/.ec2/github_key

c) add setting in your config/deploy.rb

ssh_options[:forward_agent] = true
ssh_options[:port] = 22
ssh_options[:keys] = [File.join(ENV["HOME"], ".ec2", "github_key")]

Don't forgot change the scm part:

# Use a simple directory tree copy here to make demo easier.
# You probably want to use your own repository for a real app
set :scm, :git
set :repository, "git@github.com:xxxx/yyyy.git"
set :deploy_via, :remote_cache

After all, you can use github to deploy your new code.