LiteSpeed, LSAPI & Capistrano

Posted by Mathew Abonyi Sat, 28 Oct 2006 12:03:00 GMT

Capistrano is a highly flexible deployment system (among other things) written in Ruby. It is used primarily by Rails applications, but can be suitable for any kind of web/database/application combination (Ruby or otherwise).

For more information about Capistrano, please read the Capistrano Manual for Rails.

Requirements

  • a web application to deploy
  • a working LSAPI setup
  • a working Capistrano installation on your client machine(s)
  • Capistrano set-up for your application on your server machine(s)

If any of this is bedazzling, please see the Capistrano Manual above.

Note: This wiki is based on Capistrano 1.2.0.

Quick Summary

Deploying an application to a LiteSpeed server requires you to check out your application to a new release directory, change the link for the RAILS_ROOT/current directory, and then restart the LiteSpeed server.

Before restarting Apache-style gives you shivers, know that LiteSpeed’s restart is instant, with no downtime and negligible effect on the server.

Step 1: Restricted SUDO

For those of you who do not have sudo set up to allow lswsctrl, you must change your /etc/sudoers file using visudo.

To restrict a user to only restarting the server, add the following with visudo:

Cmnd_Alias  LSWS = /opt/lsws/bin/lswsctrl restart
depuser     ALL = (root) LSWS

The LSWS command alias should be set to the path of your lswsctrl command.

Note: If you do not have root access yourself, you need to ask your system administrator to add you with the above sudoer entry. It only allows you to restart the server to get your application refreshed.

Step 2: Custom Deployment

The standard deployment script for Capistrano 1.2.0 assumes you are using SVN, deploying to one server, and restarting using the reaper script. To overwrite the default task, add the following to the end of your project’s config/deploy.rb:

set :lsws_cmd, "/opt/lsws/bin/lswsctrl"

task :restart, :roles => :app do
  sudo "#{lsws_cmd} restart"
end

Change the lsws_cmd to wherever your lswsctrl resides.

Note: You may wish, for cleanliness, place the ‘set’ command with your deploy_to, rails_env and user ‘set’s. A full deploy.rb can be seen at the end of this wiki for single and multiple application server deployments.

Step 3: Unprivileged User (Optional)

If you want your application to run in suEXEC mode, you need to create an unprivileged user for it and add whichever user will be deploying on the server to its group. It’s a little more tricky than most things and requires you to have at least this in your /etc/sudoers file:

depuser ALL = (root) LSWS, /bin/chown, /bin/chmod

The irony of using suEXEC is that you practically need root privileges to do it. Of course, your deployment user should not have such a frail password if it has this much power through sudo.

On most Linux systems, creating an application user would look like this:

sudo adduser --system --group --no-create-home --disabled-login --gecos "My Web App" mywebapp
sudo usermod -G mywebapp deploymentuser

Once you have your deployment user in the application user’s group, we set up Capistrano to deploy and fix permissions in config/deploy.rb. We do this after the code is checked out, like so:

set :jail_user, "mywebapp"
set :jail_group, "mywebapp"

task :after_update_code, :roles => :app do
  sudo <<-CMD
  sh -c "chown -R #{jail_user}:#{jail_group} #{release_path} &&
         chmod -R g+w #{release_path}"
  CMD
end

Now when you deploy, your entire application directory will be owned by the suEXEC user. If there are only specific directories (such as ‘public’ and ‘tmp’) you want to allow access to your application user, change the chown commands accordingly.

Step 4: Test It Out

Assuming you have your application, deploy_to and other parts of your Capistrano script configured properly, try it out:

shell /home/myproject$ cap deploy

The two most important things you should see are the password prompt for sudo and the lswsctrl command being run. It will probably not give any output, but you’ll notice your application is the latest deployment.

Step 5: Mulitple Application Servers

This is where Capistrano really shines. To make your application scale, just change this:

set :app, "www.example.com"

To this:

set :app, "www.example.com", "www2.example.com", "www3.example.com"

All of the deployment steps will be replicated across the application servers. It is important that they all have the same setup (i.e. same users, directory structure and the presence of LiteSpeed).

Example Deployment Script


set :user, "depuser"
set :svn_username, "depuser"

set :application, "www.example.com"
set :repository, "svn+ssh://#{user}@www.example.com/svn/trunk"

set :web, "www.example.com"
set :app, "www.example.com", "www2.example.com", "www3.example.com"
set :db, "db.example.com", :primary => true

set :rails_env, "production"
set :deploy_to, "/var/www/#{application}"

set :lsws_cmd, "/opt/lsws/bin/lswsctrl"

set :jail_user, "mywebapp"
set :jail_group, "mywebapp"

task :after_update_code, :roles => :app do
  sudo <<-CMD
  sh -c "chown -R #{jail_user}:#{jail_group} #{release_path} &&
         chmod -R g+w #{release_path}"
  CMD
end

task :restart, :roles => :app do
  sudo "#{lsws_cmd} restart"
end

Good Luck!

Posted in ,  | no comments | 9 trackbacks

LiteSpeed & LSAPI

Posted by Mathew Abonyi Sat, 28 Oct 2006 12:00:00 GMT

As part of a series on the LiteSpeed server, which I’ve come to really love for its small memory footprint, speed and ease of use, I’m going to make a few articles on setting up LiteSpeed to work smoothly—or at least as it does for me.

Requirements

  • a working installation of LiteSpeed 2.2.x
  • prior knowledge of the LiteSpeed wiki

Quick Summary

There are two ways to deploy using LiteSpeed’s custom-built API for Ruby. The first is to use their latest Rails context, which is configured in Server > Rails. The second is to set up a custom LSAPI external application in either your Server or Virtual Host context. I prefer something a little more hands on in order to control ecah application, so I use the second method.

Step 1: Install Ruby LSAPI

sudo gem install ruby-lsapi

The latest version at the time of writing is 1.11.

Step 2: Copy LSAPI to RAILS_ROOT/public/dispatch.lsapi

Most people have their rubygems located in /usr/lib/ruby/gems or /usr/local/lib/ruby/gems. Copy over the dispatch.lsapi like this:

$ cp /usr/lib/ruby/gems/1.8/gems/ruby-lsapi-1.11/rails/dispatch.lsapi public/dispatch.lsapi

Be sure to commit your changes before continuing to step 3.

Step 3: Define Server or VHost External Application


Type: LSAPI App
Name: mywebapp
Address: uds://tmp/lshttpd/mywebapp.sock
Max Connections: 5
Environment:
  RAILS_ENV=production
  LSAPI_CHILDREN=5
Initial Request Timeout: 120
Retry Timeout: 60
Persistent Connection: Yes
Connection Keep-Alive Timeout: 1000
Response Buffering: No
Auto Start: Yes
Command: $VH_ROOT/public/dispatch.lsapi
Back Log: 100
Instances: 1
Run On Start Up: Yes
Max Idle Time: -1
Memory Soft Limit: 80M
Memory Hard Limit: 100M
Process Soft Limit: 200
Process Hard Limit: 250

Explanation

Max Connections and LSAPI_CHILDREN: In order to account for unresponsive LSAPI threads, you should expect in the worst case scenario to have twice the number of threads as your Max Connections. These extras will be killed off.

Initial Request Timeout: Generally, you want this value set pretty high so LiteSpeed doesn’t think the external application is unresponsive and spawns a new one.

Max Idle: Setting this to -1 ensures the application isn’t removed from the pool and the following request incurs a start-up delay.

Instances: We pretty much ignore this value because we’re using LSAPI_CHILDREN instead. We want Ruby LSAPI to be the application manager, not LiteSpeed itself.

Back Log: How many requests to queue up before giving a server error. This will almost never happen if your server is up to the job.

How Many Max Connections?

On even the smallest web server with 256MB memory, you can get away with Max Connections set to 3 and still have plenty of memory for other things. Roughly, if you have 512MB, you want 5 threads; for 1GB, push up to 10; for 2GB, push up to 20. These connections help your concurrency; they do not increase the speed. If you do not have [MaxConns x 86400] hits a day, then you don’t need it to be set so high. Be frugal. These numbers will, of course, need adjustment and will also depend on what else is running on the system.

Step 4: Some URL Rewrites

One of the things which puts LSAPI higher in my opinion than Mongrel as a deployment option is the ability to use the custom rewrites to feed out static content as well as serve that all-important maintenance splash screen effectively. Here is a working [Virtual Host] > Rewrite setup:

Enable Rewrite: Yes
Log Level: 0

Rewrite Rules:

RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{REQUEST_FILENAME} !/stylesheets*
RewriteCond %{REQUEST_FILENAME} !/images*
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^(.*)$ /system/maintenance.html [L]

RewriteRule ^/$ /index.html [QSA]
RewriteRule ^/([^.]+)$ /$1.html [QSA]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ /dispatch.lsapi [QSA,L]

Explanation

You’ll notice in the first block of rules that there are some extras for the maintenance.html file check which you may not have seen before: stylesheets and images. This allows you to create your own maintenance splash with images and stylesheets—perhaps even the same ones used in the rest of your application.

The second block attempts to serve cached pages through LiteSpeed if Rails has made any.

The third block throws everything back at Rails if it isn’t found.

Step 5: Create Your VHost Context


Type: LiteSpeed API
URI: /dispatch.lsapi
LSAPI App: [Server Level]: mywebapp

Explanation

If you are wondering why we make the URI ’/dispatch.lsapi’ instead of ’/’, this is to use the rewrite rules from Step 4. Everything will route back to dispatch.lsapi if it doesn’t already exist, but if there are files which can be served, we want LiteSpeed to handle it. This is a pretty easy way to deal with it.

Step 6: `sudo lswsctrl restart`

Posted in ,  | 1 comment

Older posts: 1 2