Rails Application deployed on a brand new Joyent Accelerator with Capistrano 2.0
You should start with a new Virtual Server and a new Administrative user for the Virtual Server.
If you haven't done this yet. Start here: http://wiki.joyent.com/accelerators:kb:getting-started
After you setup the website, create the database for your website. Under Virtualmin, you will click on Edit Databases. From there you click “create a new database”:
The username you specified when you created your virtual Server should precede the name of the database. Provide the rest of the name, ignore the options, and click create.
Now all the Virtualmin stuff is done, time to give your new user the proper paths and permissions in an ssh session (this is for Capistrano).
Create .ssh/environment PATH
SSH into your server.
Create the .ssh directory:
mkdir .ssh
Create a new file “environment” using nano:
nano .ssh/environment
Add this to “environment” if you have an “old” accelerator(blastwave template):
PATH=/usr/bin:/usr/sbin:/usr/ucb:/usr/sfw/bin:/usr/ccs/bin:/opt/csw/bin:/opt/csw/sbin:/opt/csw/gnu:/opt/csw/gcc3/bin:/opt/csw/mysql5/bin:/opt/csw/postgresql/bin:/opt/csw/apache2/bin:/opt/csw/apache2/sbin
Add this to “environment” if you have an newer accelerator(pkgsrc template):
PATH=/opt/local/bin:/opt/local/sbin:/usr/xpg4/bin:/usr/bin:/usr/sbin:/usr/sfw/bin:/usr/openwin/bin:/usr/ccs/bin
Save the file.
Edit the sudoers file
This step must be carried out as the admin user of your accelerator (or another user allowed to call sudo visudo) otherwise you won't be allowed to run the command. To add a user to sudoers file, you must use visudo. visudo emulates VI and is used to prevent errors when editing the sudoers file:
sudo visudo
How to use visudo
1. Use the arrow keys to navigate the cursor to the spot where you want to start typing
2. Enter “insert mode” by pressing “i”
3. When you are done entering text, hit esc to go back to “command mode”
4. Write the file back to disk by typing :w followed by hitting enter.
5. Exit visudo with :q followed by enter.
Text entered for my user, right below “root ALL=(ALL) ALL”:
newuserforvirtualserver ALL=(ALL) ALL
Add a Mongrel Config
If you are on a S or M sized Accelerator, create a mongrel_cluster.yml file in your config folder. Add the following to it.
--- port: 8000 pid_file: /tmp/`hostname`-mongrel.pid servers: 4 environment: production
If you want to hide your mongrels from the outside world once everything is running smoothly, bind them to localhost by adding this to your mongrel_cluster.yml:
address: 127.0.0.1
If you are on a L or larger sized Accelerator do the following.
cd /home/YOUR/PATH/TO/RAILS/APP svn export http://svn.joyent.com/public/accelerators/configs/mongrel/mongrel_cluster.yml config/mongrel_cluster.yml
Add capistrano 2.0 recipes to your rails application
To start, you need to capify your application. For more information: http://www.capify.org/getting-started/rails
Capify your app:
capify .
Now, you are going to get your copy and paste on. Copy these next three files and place them into your_app_name/config/accelerator.
NOTE: Newer Accelerators (March 22 2008 and later) will have apache installed in /opt/local/etc/httpd, not /opt/csw/apache2 (see http://wiki.joyent.com/accelerators:kb:changes-to-accelerators). You'll need to correct these recipes as noted in the comments within each file below.
NOTE 2: If you'd like SMF to monitor each mongrel separately, an alternative setup with different versions of the files below is available at Rails Deployment with SMF Monitoring for Individual Mongrels.
FILE #1: accelerator_tasks.rb
Capistrano::Configuration.instance(:must_exist).load do namespace :accelerator do desc "Adds a SMF for the application" task :create_smf, :roles => :app do puts "set variables" service_name = application working_directory = current_path template = File.read("config/accelerator/smf_template.erb") buffer = ERB.new(template).result(binding) put buffer, "#{shared_path}/#{application}-smf.xml" sudo "svccfg import #{shared_path}/#{application}-smf.xml" end desc "Creates an Apache 2.2 compatible virtual host configuration file" task :create_vhost, :roles => :web do public_ip = "" run "ifconfig -a | ggrep -A1 e1000g | grep inet | awk '{print $2}'" do |ch, st, data| public_ip = data.gsub(/[\r\n]/, "") end cluster_info = YAML.load(File.read('config/mongrel_cluster.yml')) start_port = cluster_info['port'].to_i end_port = start_port + cluster_info['servers'].to_i - 1 public_path = "#{current_path}/public" template = File.read("config/accelerator/apache_vhost.erb") buffer = ERB.new(template).result(binding) put buffer, "#{shared_path}/#{application}-apache-vhost.conf" sudo "cp #{shared_path}/#{application}-apache-vhost.conf /opt/csw/apache2/etc/virtualhosts/#{application}.conf" # If you're on a new pkgsrc templated accelerator replace the line above with the following line: # sudo "cp #{shared_path}/#{application}-apache-vhost.conf /opt/local/etc/httpd/virtualhosts/#{application}.conf" restart_apache end desc "Restart apache" task :restart_apache, :roles => :web do sudo "svcadm refresh svc:/network/http:cswapache2" # If you're on a new pkgsrc templated accelerator replace the line above with the following line: # sudo "svcadm restart apache" end desc "Stops the application" task :smf_stop, :roles => :app do sudo "svcadm disable /network/mongrel/#{application}-production" end desc "Starts the application" task :smf_start, :roles => :app do sudo "svcadm enable -r /network/mongrel/#{application}-production" end desc "Restarts the application" task :smf_restart do smf_stop smf_start end desc "Deletes the configuration" task :smf_delete, :roles => :app do sudo "svccfg delete /network/mongrel/#{application}-production" end desc "Shows all Services" task :svcs, :roles => :app do run "svcs -a" do |ch, st, data| puts data end end desc "After setup, creates Solaris SMF config file and adds Apache vhost" task :setup_smf_and_vhost do create_smf create_vhost end end after 'deploy:setup', 'accelerator:setup_smf_and_vhost' end
FILE #2 apache_vhost.erb
<VirtualHost <%= public_ip %>:80> ServerName <%= server_name %> ServerAlias <%= server_alias %> DocumentRoot <%= public_path %> <Directory "<%= public_path %>/"> Options FollowSymLinks AllowOverride None Order allow,deny Allow from all </Directory> <Proxy balancer://<%= application %>-mongrels><% start_port.upto(end_port) do |port| %> BalancerMember http://127.0.0.1:<%= port %><% end %> </Proxy> ProxyPass /images ! ProxyPass /javascripts ! ProxyPass /stylesheets ! ProxyPass / balancer://<%= application %>-mongrels/ ProxyPassReverse / balancer://<%= application %>-mongrels/ ProxyPreserveHost On </VirtualHost>
FILE #3 smf_template.erb
applicationname #don't name it applicationname.com or www.applicationname.com as the periods seems to mess up the SMF
<?xml version='1.0'?> <!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'> <service_bundle type='manifest' name='mongrel/<%= service_name %>-production'> <service name='network/mongrel/<%= service_name %>-production' type='service' version='0'> <create_default_instance enabled='true'/> <single_instance/> <dependency name='fs' grouping='require_all' restart_on='none' type='service'> <service_fmri value='svc:/system/filesystem/local'/> </dependency> <dependency name='net' grouping='require_all' restart_on='none' type='service'> <service_fmri value='svc:/network/loopback'/> <!-- uncomment the following line if you are on an L+ Accelerator since /home is mounted through nfs --> <!--<service_fmri value='svc:/network/nfs/client'/>--> </dependency> <dependent name='mongrel_multi-user' restart_on='none' grouping='optional_all'> <service_fmri value='svc:/milestone/multi-user'/> </dependent> <exec_method name='start' type='method' exec='/opt/csw/bin/mongrel_rails cluster::start' timeout_seconds='60'> <!-- If you're on a new pkgsrc templated accelerator replace the line above with the following line: --> <!--<exec_method name='start' type='method' exec='/opt/local/bin/mongrel_rails cluster::start' timeout_seconds='60'>--> <method_context working_directory='<%= working_directory %>'> <method_credential user='applicationuser' group='applicationdomain' /> <method_environment> <envvar name='PATH' value='/usr/bin:/bin:/opt/csw/bin' /> <!-- If you're on a new pkgsrc templated accelerator replace the line above with the following line: --> <!--<envvar name='PATH' value='/usr/bin:/bin:/opt/local/bin' />--> </method_environment> </method_context> </exec_method> <exec_method name='stop' type='method' exec=':kill' timeout_seconds='60'> <method_context/> </exec_method> </service> </service_bundle>
Edit deploy.rb
Now you need to replace the deploy.rb file that capify created. Open up deploy.rb, delete its contents, and paste this in:
set :scm_command, "/opt/local/bin/svn"
set :local_scm_command, :default
require 'erb' require 'config/accelerator/accelerator_tasks' set :application, "app_name" #matches names used in smf_template.erb set :repository, "http://repo/location" # If you aren't deploying to /u/apps/#{application} on the target # servers (which is the default), you can specify the actual location # via the :deploy_to variable: set :deploy_to, "/var/www/apps/#{application}" # I like this location set :user, 'newapplicationadminuser' set :runner, 'newapplicationadminuser' # If you aren't using Subversion to manage your source code, specify # your SCM below: set :scm, :subversion # keep a cached code checkout on the server, and do updates each time (more efficient) set :deploy_via, :remote_cache # Set the path to svn and rake if needed(Does not seem to be necessary on the newpkgsrc templated accelerators, but if needed change path to /opt/local/bin/ ) set :svn, "/opt/csw/bin/svn" set :rake, "/opt/csw/bin/rake" set :domain, 'your public ip' role :app, domain role :web, domain role :db, domain, :primary => true set :server_name, "domain.com" set :server_alias, "*.domain.com" # Example dependancies depend :remote, :command, :gem depend :remote, :gem, :money, '>=1.7.1' depend :remote, :gem, :mongrel, '>=1.0.1' depend :remote, :gem, :image_science, '>=1.1.3' depend :remote, :gem, :rake, '>=0.7' depend :remote, :gem, :BlueCloth, '>=1.0.0' depend :remote, :gem, :RubyInline, '>=3.6.3' deploy.task :restart do accelerator.smf_restart accelerator.restart_apache end deploy.task :start do accelerator.smf_start accelerator.restart_apache end deploy.task :stop do accelerator.smf_stop accelerator.restart_apache end after :deploy, 'deploy:cleanup'
Save all your files, make sure they have been added to your repository and committed.
Now in a command prompt on your local computer type:
cap deploy:setup
After that completes type:
cap deploy:cold
You should now have a working application.
TROUBLESHOOTING
Common problems and solutions. For unsolved questions, please post them on the forum.
| Q. | Despite setting the PATH in .ssh/environment, when capsitrano runs, it does not have svn and the other commands in its path. |
| A. | I had the same issue. Make sure you're editing ~/.ssh/environment … Note the tilde. |
| Q. | After even cap deploy; the mongrel cluster is running correctly but you cannot access it from port 80, only 8000/8001/8002/8003 |
| A. | The issue is in your mapping of the apache VirtualHost to mongrels. Since you are able to access it via 8000, then that means you have your mongrel_cluster.yml set to use the External IP address (not a good thing) change it to localhost and you will be golden. -Linda |
| Q. | When I execute ” > cap deploy:setup ” I receive Permission denied errors when it is executing mkdir |
| A. | Remove the ”/” from in front of :deploy_to in deploy.rb since they may try to put it in the root of your accelerator depending on your settings. If this doesn't work, check if the “user” value in the deploy.rb file belongs to the “root” group. You can check it using “sudo nano /etc/groups” on your accelerator. Change the line “root::0:” to “root::0:yourusername” |
| Q. | cap deploy:cold is failing with “Permission denied (gssapi-keyex,gssapi-with-mic,publickey,keyboard-interactive).” What do I do? |
| A. | You are most likely running on Mac OSX. As someone else has already figured out, “It turns out that my svn+ssh connection was failing because it was trying to connect as the wrong user (my local username and server username are not identical)”. The solution is to do a slight tweak for your ”:repository” variable. Instead of “svn+ssh://server/svn_directory”, use “svn+ssh://svn_username@server/svn_directory” instead. Setting the ”:svn_user” and ”:scm_user” variables did not work for me. |
| Q. | cap deploy:cold is still failing during “updating the cached checkout on all servers”. What do I do? |
| A. | You are probably still getting a “Permission denied (gssapi-keyex,gssapi-with-mic,publickey,keyboard-interactive)” while it is trying to execute “if [ -d /var/www/apps/zonename/shared/cached-copy ]; then svn update -q -r10 /var/www/apps/zonename/shared/cached-copy; else svn checkout -q -r10 svn+ssh://svn_username@zonename.joyent.us/home/zonename/svn/svn_repo_name/trunk /var/www/apps/zonename/shared/cached-copy; fi”. For some reason just manually creating the ”/var/www/apps/zonename/shared/cached-copy” beforehand solved my problem. |