Using Mongrel Cluster

by Austin Godber

Mongrel_cluster is a GemPlugin that wrappers the mongrel HTTP server and simplifies the deployment of webapps using a cluster of mongrel servers. Mongrel_cluster will conveniently configure and control several mongrel servers, or groups of mongrel servers, which are then load balanced using a reverse proxy solution. Typical load balancing reverse proxies include:

Requirements

Throughout these instructions we will assume the following:

  • All mongrel instances are running on the same machine
  • Mongrel 0.3.13 or greater
  • Mongrel_cluster 0.2.0 or greater
  • Linux platform (Centos 4.3 in this case, so you will see RedHat? like commands).
  • You have sudo or root access

Preliminary steps

In general, when deploying a mongrel cluster, none of the mongrel servers will be listening on a privileged port. This is nice, we don't have to run mongrel as root, therefore we should create a user for mongrel to run as:

  $ sudo /usr/sbin/adduser -r mongrel

For the purpose of this example we will just use a freshly minted rails app. You can adjust these instructions to work with your app, wherever you may have placed it but lets pretend we are working in /var/www/apps. So lets go set up our app and test that mongrel will serve it:

  $ cd /var/www/apps
  $ rails testapp
  $ cd testapp
  $ mongrel_rails start

You should now be able to see your application at http://host:3000/. If you can, you are good to go. Hit CTRL+C to stop the mongrel server. At a minimum the log directory of your app has to be writable by the *mongrel* user:

  $ sudo chown -R mongrel:mongrel /var/www/apps/testapp

Mongrel Cluster Setup

With mongrel working and our webapp directory prepared we can proceed with the mongrel_cluster configuration step:

  $ sudo mongrel_rails cluster::configure -e production \
    -p 8000 -N 3 -c /var/www/apps/testapp -a 127.0.0.1 \
    --user mongrel --group mongrel 

This will write a configuration file in *config/mongrel_cluster.yml*. We have setup to run our cluster in production mode as the user *mongrel* and will start 3 mongrel servers listening on ports 8000, 8001, and 8002. Now, lets do a quick test of what we have setup so far:

   $ sudo mongrel_rails cluster::start

Checking our host on ports 8000, 8001, and 8002 we should now be able to see our test application. We can stop all of those mongrels with sudo mongrel_rails cluster::stop.

On Boot Initialization Setup

At this point, mongrel and mongrel_cluster are setup and working with our sample webapp. Ultimately, we want this cluster to start on boot. Fortunately, mongrel_cluster comes with an init script that we can just drop into place. All we need to do is put the configuration files in */etc/mongrel_cluster* and take care of a few system tasks:

  $ sudo mkdir /etc/mongrel_cluster
  $ sudo ln -s /var/www/apps/testapp/config/mongrel_cluster.yml \
    /etc/mongrel_cluster/testapp.yml
  $ sudo cp \
    /path/to/mongrel_cluster_gem/resources/mongrel_cluster \
    /etc/init.d/
  $ sudo chmod +x /etc/init.d/mongrel_cluster 

Now we have a typical System V init script that will launch our mongrel cluster. Actually, this script will launch any cluster that has a configuration file in /etc/mongrel_cluster/. So when we run /etc/init.d/mongrel_cluster start it will start all clusters. Likewise for stop and restart. If we are using a RedHat? like system we can configure mongrel_cluster for startup:

  $ sudo /sbin/chkconfig --level 345 mongrel_cluster on

For users of Debian, you can use this command to install the script:

  $ sudo /usr/sbin/update-rc.d -f mongrel_cluster defaults

NOTE At this point there are a few issues with this init script that only apply under certain circumstances. Those issues include:

  • Shebang line - The init script uses #!/usr/bin/env ruby to find the appropriate interpreter. Some distribution installs of ruby only give you a /usr/bin/ruby1.8. You may change the shebang line or simply create a symbolic link from /usr/bin/ruby1.8 to /usr/bin/ruby[3].
  • mongrel_cluster_ctl location - If you have installed your gems in /usr/local/ you may find that the init script can not find mongrel_cluster_ctl. To resolve this, you can symbolically link /usr/local/bin/mongrel_cluster_ctl into /usr/bin/

Conclusion

We have configured mongrel and mongrel_cluster with our webapp and setup mongrel_cluster to run our cluster at startup. What's missing? Well, unless your application users expect to have to connect to ports 8000-8002 you had best check out the reverse proxy options listed above.

The process of setting up mongrel_cluster will be the same for all of the reverse proxy deployment options. So this document will likely serve as a reference for several of the other deployment guides.


[1] Thanks to Bradley Taylorfor writing mongrel_cluster and recent improvements in its startup capabilities. The following people have provided valuable feedback on this document: Alison Rowland.

[2] adduser -r is a RedHat?-centric way of creating a system account. For Debian-ish distributions replace that with adduser --system mongrel.

[3] If you have this problem, you will probably discover other ruby related executables are also missing. You may want to link irb1.8 and ri1.8 as well, though only /usr/bin/ruby is necessary for this init script.