PDA

View Full Version : Deploy rails app using SSH/PuTTY/Pageant, SVN, MySQL, Capistrano, Mongrel, nginx - 2


Larry
03-22-2008, 06:17 PM
Subversion
The usual way to create a brand new repository is to create the repository on the server, import an entire existing project (i.e. from your local machine to the server), and then check out that project. That works and if you're comfortable with that process then by all means do it. But a problem is that you have to screw around with removing files and directories from the repository that you don't want under version control, e.g. log/*.*, tmp/*.*, etc.

An easier way is to do an in-place import, which allows you to selectively commit only the files/folders you want. (http://subversion.tigris.org/faq.html#in-place-import)

Login as "root"
cd /root/var
mkdir svn
cd svn
svnadmin create --fs-type fsfs repos (Creates a Subversion repository: /var/svn/repos directory with several subdirectories.)

Note regarding the following commands:
1) It's 'svn mkdir', not just 'mkdir'
2) There are 3 "/"s after "file:", not 2
3) You need to provide the "message" option
4) You need to make the "sample" directory before making the subdirectories
5) The subdirectories - all 3 of which are entered on the same command line - create the standard SVN repository structure of "trunk", "branches", and "tags".

svn mkdir --message "Initial project layout" file:///var/svn/repos/sample
svn mkdir --message "Initial project layout" file:///var/svn/repos/sample/trunk file:///var/svn/repos/sample/tags file:///var/svn/repos/sample/branches

You won't see any of these directories ("sample" and its 3 subdirectories) explictitly listed because Subversion stores all of this stuff in its own internal format. Now enter the following commands:

groupadd svn (create group ‘svn’)
chgrp –R svn /var/svn/repos (associate group with 'repos' dir, recursively)
chmod –R g+w /var/svn/repos (give the group write access to the dir, recursively)
usermod –G yourusername,svn yourusername (add yourself to the group)

The repository's trunk is at /var/svn/repos/sample/trunk, however, when you access it you do so via SSH. So, for example, if you use TortoiseSVN to browse your repository you would enter the following URL: svn+ssh://username@yourwebsite.com/var/svn/repos/sample/trunk. You could access it as svn+ssh://root@yourwebsite.com/var/svn/repos/sample/trunk, but, as mentioned earlier, it's best not to do things as "root" if you don't have to. Besides, you'll want to access it by username so that when you add more developers Subversion can connect usernames to actions so you know who did what.

Now you should have an empty repository. Assuming all code is accessed from the trunk:
"svn checkout" the empty trunk (using TortoiseSVN and the "svn+ssh..." URL mentioned above) into the root directory of your local sample app. You will be warned that the directory contains files; you already know that, so it's okay.
"svn add" the entire tree of your local app.
"svn add to ignore list" the files and directories you don't want in the repository (see below)
"svn commit"

Now only the files you want will be in your repository. For Rails apps, typical exclusions are:
config/database.yml (I recommend leaving this in for now; it's easier to make it through the rest of the steps)
db/schema.rb
log/*
tmp/*
nbproject/* and any root NetBeans files (for NetBeans users; ignore your own IDE-specific files)


MySQL
Your Rails app probably needs a database. Assuming you have some migrations to run, the only thing you need to do in advance is create the database on the server. There are three ways to do this:

1) From the command line on your server. (I didn't do it this way, so you're on your own.)

2) From RimuHosting's Webmin Control Panel.
Log in with username "root" and your password. Then "Servers > MySQL Database Server > Create a new Database".

3) Use SQLyog or any other MySQL GUI admin program you have running on your local machine.
To connect you need to supply a host address (yourwebsite.com), a username ("root"), a port (3306), and a password. Setting up and providing a password is the only tricky part. Turns out there are essentially 3 types of connections and corresponding passwords.

The 3 connection types are:
1) root@localhost - for when you access the database locally, i.e. from your Rails app that is running on the same machine as the database. This jives with the settings in your database.yml file.
2) root@yourwebsite.com - for when you access the database remotely, i.e. from your local MySQL GUI program
3) % - This is a wildcard which basically translates to "any connection".

I used SQLyog to make all 3 of my passwords the same: In "Tools > User Manager > Add User" > do for each connection type:

Username - root
Host - localhost
Password - mypassword
Privileges - "Select All" check boxes

Username - root
Host - mywebsite.com
Password - mypassword
Privileges - "Select All" check boxes

Username - root
Host - %
Password - mypassword
Privileges - "Select All" check boxes

When you are done:

1) Create this file with these contents on the server so that the Webmin Control Panel can access your MySQL server:

File: /root/.my.cnf

Contents:
[client]
user=root
password=yourpassword

2) Allow outside connections to your database server so your local GUI client can access your MySQL server:
Webmin Control Panel > Servers > MySQL database server > MySQL Server Configuration > MySQL server listening address (upper right corner) > set to Any.


Take Another Breather
Whew! You now have a Subversion repository that contains the code from your local web app, and a MySQL database just waiting for tables. Time for a drink! (Make it a good micro-brew; you've worked too hard to settle for any of that Lite crap.)


Server Preparation

cd /var/www
mkdir apps
groupadd apps (create group ‘apps’)
chgrp –R apps /var/www/apps (associate group with dir, recursively)
chmod –R g+w /var/www/apps (give the group write access to the dir, recursively)
usermod –G yourusername,svn,apps yourusername (add yourself to the group)

Useful commands to see status information:
groups yourusername (See what groups you belong to )
ls –l (Lists permissions for owner, group, and others)


Capistrano
The first thing you need to realize about Capistrano is that it resides on your local computer, not on the server. Basically it just pumps commands via SSH to your server. It can do a lot of things, but for our purposes we care only about getting our latest-and-greatest code out of Subversion and into our website location, and then stopping and restarting Mongrel so that our new code takes root. That's because when developing locally (Rails Development Mode), changes to your code are immediately reflected on your "localhost" server. When deploying remotely (Rails Production Mode) you have to stop and then restart the servers for the changes to take effect.

On your local machine:
cd \projectroot
capify . (This "capifies" your Rails project. Numerous websites explain what this means.)

You'll get a sample config/deploy.rb. Substitute its contents with the following (type as-is, including quotation marks):

set :application, "sample"
set :domain, "yourwebsite.com"
set :user, "yourusername"

# So doesn't do an 'svn check out', thus giving you unneeded .svn directories and files
set :deploy_via, :export

# So can work with Pageant (i.e. public/private keys instead of password)
set :ssh_options, { :forward_agent => true }

set :mongrel_config, "/etc/mongrel_cluster/#{application}.yml"

# You will still need to provide your 'root' password for a sudo operation
# for mongrel cluster. Need this in order to input password.
# (Scheduled to be default setting in Cap 2.2 release)
default_run_options[:pty] = true

set :repository, "svn+ssh://yourusername@#{domain}/var/svn/repos/#{application}/trunk"
set :deploy_to, "/var/www/apps/#{application}"

# Your web server, e.g. nginx
role :web, "#{domain}"
# Your application server, e.g. mongrel
role :app, "#{domain}"
# Your database server, e.g. MySQL
role :db, "#{domain}", :primary => true

# You need this in order to get prompted for password.
namespace :deploy do
[:start, :stop, :restart].each do |t|
desc "#{t.to_s.capitalize} the mongrel app server"
task t do
sudo "mongrel_rails cluster::#{t.to_s} -C #{mongrel_config}"
end
end
end


While you are in your IDE changing local code, make the following two changes:
1) environment.rb:

Uncomment the following line. Don't forget to re-comment for local development:
#ENV['RAILS_ENV'] ||= 'production'

2) database.yml

production:
adapter: mysql
encoding: utf8
database: sample_production
username: root
password: yourpassword
host: localhost
socket: /var/lib/mysql/mysql.sock


Okay, now from your local project root:
cap deploy:setup (creates needed directories in /var/www/apps/sample)
cap deploy:check (sees if everything you need is in place)

You're now ready to deploy your app!

No you're not. Just kidding. (But you're pretty damn close, so hang in there!)