Deployment with Capistrano

To understand the deployment process of a rails application, I planned on deploying the paperclip_sample_app  from the previous post to an Amazon EC2 instance using capistrano. In this post I will list the various steps involved in the deployment process. Deploying any application is pretty time consuming so be prepared to give your self enough time.

The first step is to create an instance and setup it up. For a personal ruby project the amazon micro instance is an ideal candidate (http://aws.amazon.com/free/). Log in to you aws management console (https://console.aws.amazon.com/).

Select the EC2 tab and hit the Launch Instance button.

Select the Community AMIs tab and search for “ubuntu 10.04”. I have had package dependency issues with the “ubuntu 10.10”.  Select the ami-054e9a6c instance.

Double check that it is the micro instance and hit continue.

Hit Continue

Hit Continue

Hit Continue and select the create new key pair button and download the keys.

Create a security group from the EC2 tab with the following permissions.

Port 22 – ssh

Port 80 – HTTP

Port 3306 – mysql

Select the security group and hit continue.

Launch the instance.

Connecting to the instance – It is very important to follow the steps in the link given below in order to avoid permission issues during application deployment.

https://help.ubuntu.com/community/EC2StartersGuide

$ cd ~/.ec2

ssh -i key1.pem ubuntu@ec2-50-19-48-132.compute-1.amazonaws.com

To deploy the rails application, the EC2 instance has to be setup with Ruby, Apache server, Phusion Passenger. These are the following steps:

$ sudo apt-get update

$ sudo apt-get dist-upgrade

$ sudo apt-get install openssh-server

$ sudo apt-get install mysql-server

$ sudo apt-get update

$ sudo apt-get dist-upgrade

$ sudo apt-get install build-essential

Install rvm and dependencies

sudo apt-get install zlib1g-dev libssl-dev libreadline5-dev libxml2-dev libsqlite3-dev

$ bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)

$ echo “[[ -s $HOME/.rvm/scripts/rvm ]] && source $HOME/.rvm/scripts/rvm” >> ~/.bash_profile

$ source ~/.bash_profile

$ sudo apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion

$rvm install 1.9.2

This will take around 15 to 20 minutes.

$rvm use 1.9.2

Installing passenger and its dependencies

$ sudo apt-get install apache2-prefork-dev libapr1-dev libaprutil1-dev

$ gem install passenger

$ passenger-install-apache2-module

$ sudo apt-get install libcurl4-openssl-dev

$ sudo apt-get install apache2-mpm-prefork

$ passenger-install-apache2-module

Edit /etc/apache2/apache2.conf

$ sudo vi /etc/apache2/apache2.conf

Navigate to the bottom of the file and hit i.

Hit enter and paste the following lines.

LoadModule passenger_module /home/ubuntu/.rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.11/ext/apache2/mod_passenger.so
PassengerRoot /home/ubuntu/.rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.11
PassengerRuby /home/ubuntu/.rvm/wrappers/ruby-1.9.2-p290/ruby

Hit ESC and type :wq!

This saves the changes.

This is a useful tutorial on vi editor. http://www.washington.edu/computing/unix/vi.html

Restart apache server

$ sudo /etc/init.d/apache2 restart

To verify, enter the public DNS of your instance in a browser.

Sync github to the server

http://help.github.com/linux-set-up-git/

$ chmod 700 .ssh/

Deploying rails app using capistrano

$ cd /var/www

$ sudo mkdir apps

$ cd apps

$ sudo mkdir paperclip_sample_app

Set correct permissions for ubuntu by making ubuntu the owner of the following directories.

$ chown ubuntu /var/www/apps

$ chown ubuntu /var/www/apps/paperclip_sample_app

copy the public key(~/.ssh/id_rsa.pub) on your machine to the ~/.ssh/authorized_keys folder

cat ~/.ssh/id_rsa.pub | ssh -i key1.pem ubuntu@ec2-50-19-48-132.compute-1.amazonaws.com ‘cat >> .ssh/authorized_keys’

This is very important, otherwise capistrano asks for password during  deployment.

$ capify .

Here is the config/deploy.rb file

commit to github

$ cap deploy:setup

$ cap deploy:check

If we get this error

$ cd /var/www/apps/paperclip_sample_app/current

$ rvm use 1.9.2

$ rvm gemset use global

$ gem install rake

create the db(should have the same name as that in the config/db file)

Before configuring apache server we need to associate the amazon instance with an IP address and buy a domain name.

Configuring apache to render the newly deployed app.

https://help.ubuntu.com/community/ApacheMySQLPHP

$ sudo vi /etc/apache2/sites-available/paperclip_sample_app

Add the following content to /etc/apache2/sites-available/paperclip_sample_app

<VirtualHost *:80>
ServerName http://www.vi-shal.com
DocumentRoot /var/www/apps/paperclip_sample_app/current/public
<Directory /var/www/apps/paperclip_sample_app/current/public>
AllowOverride all
Options -MultiViews
</Directory>
</VirtualHost>

$ sudo a2dissite default

$ sudo a2ensite paperclip_sample_app

$ sudo /etc/init.d/apache2 reload

Open a browser and enter the domain name or IP address of you instance. You should now be able to see the newly deployed site.

Advertisements

Uploading images to Amazon S3

To upload images to the cloud we use paperclip gem. This post will demonstrate how to use scaffolding to create a new Rails app from scratch that uses the Paperclip plugin to upload and display an image file. Initially the images are uploaded to the public folders of the app and later the app is configured to upload images to amazon’s S3 storage service.

This app displays the list of users with their profile pictures, username and email_id.

Paperclip uses imagemagik, so in order to get paperclip to work we need to install imagemagik. This can be done using

brew install imagemagick
gem install rmagick

$ rails new paperclip_sample_app

Setup the database.yml file and create a new MySQL database to use with the sample app. Contents of config/databases.yml

production:
adapter: mysql2
encoding: utf8
database: paperclip_sample_app_development
reconnect: false
pool: 5
username: root
password: password
socket: /var/run/mysqld/mysqld.sock

development:
adapter: mysql2
encoding: utf8
database: paperclip_sample_app_development
reconnect: false
socket: /var/run/mysqld/mysqld.sock
pool: 5
username: root

$ cd paperclip-sample-app
$ rake db:create

Add the paperclip gem to the Gemfile

source ‘http://rubygems.org&#8217;

gem ‘rails’, ‘3.0.10’
gem ‘mysql’
gem ‘paperclip’

gem ‘ruby-debug’, :groups => [:development, :test]

Lets generate the user model.

$ rails g scaffold user name:string email:string

Now we need to generate the database columns necessary for Paperclip on the user model object

$ rails g paperclip user avatar
$ rake db:migrate

The paperclip generator creates the following columns in the users table, “avatar_file_name,” “avatar_content_type,” “avatar_file_size” and “avatar_updated_at”

Next we need to add a line to the user model to let it know that it has a file attachment called avatar.

app/models/user.rb

class User < ActiveRecord::Base
has_attached_file :avatar
end

 These are the views used in the app.

app/views/users/new.html.erb

<h1>New user</h1>

<% form_for(@user, :html => { :multipart => true }) do |f| %>
<%= f.error_messages %>

<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :avatar %><br />
<%= f.file_field :avatar %>
</p>
<p>
<%= f.submit ‘Create’ %>
</p>
<% end %>

<%= link_to ‘Back’, users_path %>

app/views/users/show.html.erb

<p>
<b>Name:</b>
<%=h @user.name %>
</p>

<p>
<b>Email:</b>
<%=h @user.email %>
</p>

<p>
<b>Avatar:</b>
<%= image_tag @user.avatar.url %>
</p>

<%= link_to ‘Edit’, edit_user_path(@user) %> |
<%= link_to ‘Back’, users_path %>

app/views/users/show.html.erb

<p>
<b>Name:</b>
<%=h @user.name %>
</p>

<p>
<b>Email:</b>
<%=h @user.email %>
</p>

<p>
<b>Avatar:</b>
<%= image_tag @user.avatar.url %>
</p>

<%= link_to ‘Edit’, edit_user_path(@user) %> |
<%= link_to ‘Back’, users_path %>

Paperclip gives us different options to configure the images sizes. If no options are given, paperclip uploads the actual image size. In order to upload avatars we need to make the following changes to the user model.

app/models/user.rb

class User < ActiveRecord::Base
has_attached_file :avatar,
:styles => {
:thumb => “75×75>”,
:small => “150×150>”
}
end

This app stores the images in the public/system folders.
To upload images to the cloud we need to create an S3 account. The S3 account can be created at http://aws.amazon.com/. You can use your amazon account credentials to log in.  Note your ‘access key id’ and ‘secret access key’. These can be found at https://aws-portal.amazon.com/gp/aws/securityCredentials#access_credentials.
Include the aws-s3 gem,  in the gem file.
Gemfile

gem ‘aws-s3’, :require => ‘aws/s3’
Open up the Rails console and establish a connection to our account. We then create a new ‘bucket’ where our files will be stored.
# Terminal
> bundle
> rails c
console > include AWS::S3
console > Base.establish_connection!(:access_key_id => ‘yoursecretid’, :secret_access_key => ‘yoursecretkey’)
console > Bucket.create(‘paperclip_sample_app’)
console > Service.buckets
=> [#<AWS::S3::Bucket:0x00000 @attributes={“name”=>”paperclip_sample_app“, “creation_date”=>2012-02-12 00:00:00 UTC}, @object_cache=[]>]
console > Base.disconnect
console > exit
Next we need to config the user model so that paperclip uploads to S3 rather than the public/system folders. Before that we should create a file called in the config folder to store the S3 credentials.
# config/amazon_s3.yml

access_key_id: ‘yoursecretid’
secret_access_key: ‘yoursecretkey’
bucket: ‘paperclip_sample_app
The following changes must be made to the user model.
class User < ActiveRecord::Base
has_attached_file :avatar,
:styles => {
:thumb => “75×75>”,
:small => “150×150>”
},
:storage => :s3,
:s3_credentials => “#{Rails.root}/config/amazon_s3.yml”,
:path => “/:style/:filename”
validates_attachment_size :avatar, :less_than => 1.megabyte
end

Now the images will be uploaded into the cloud. Using the aws console we can look at the images that we uploaded.