Puppet: System Administration Automated

Puppet Training Schedule
Next Class July 27-29
New York, New York
Discount before July 1st

Rails stack recipe

Here is my stab at setting up a Rails stack based on Rails, Mongrel (cluster) Apache2.2 and Proxybalancer.

This example is using The Debian Apache2 recipe and the remotefile definition. I've just renamed the class to "webserver" and added some extras (such as copying all the relevant vhost files to the server and installing cronolog).

I'm trying to switch to templates instead of copying the files, as it usually contains lots of redundant info, but I haven't got time to refactor it yet. Actually I think I'll make a complete railsapp definition and use that instead. I will update this page when I've done it. Until then, I'm just using this in my node definition:

node 'my.rails.node' {
    $appname = "railstest"
    $sitename = "railstest.example.com"
    include railsstack
    file { "/etc/apache2/sites-available/${sitename}":
        content     => template("apache/apache_mongrel"),
    }
}

file mongrel.pp:

class mongrel {
    include rubygems
    package {
        [ "mongrel", "mongrel_cluster" ]:
            ensure      => installed,
            provider    => "gem",
            require     => Package["rubygems"];
    }
    file { "/etc/mongrel_cluster":
        ensure          => directory,
    }
    remotefile { "/etc/init.d/mongrel_cluster":
        source          => "config/apps/mongrel/mongrel_cluster.rc",
        mode            => "755",
    }
    service { "mongrel_cluster":
        ensure          => running,
        enable          => true,
        pattern         => "mongrel_rails",
        hasrestart      => true,
        subscribe       => File["/etc/mongrel_cluster"],
        require         => Remotefile["/etc/init.d/mongrel_cluster"],
    }
}

file railsstack.pp:

class railsstack {
    include webserver
    include mongrel
    include mysql-server-50
    include wwwroot
    package { 
        [ "libmysqlclient15-dev", "ruby1.8-dev", "gcc", "make" ]:
            ensure      => installed;
        [ "mysql", "rails" ]:
            ensure      => installed,
            provider    => "gem",
            require     => Package["rubygems"];
    }
    webserver::apache_module { [ "proxy_http", "rewrite", "ssl", "proxy_balancer", "deflate" ]: }
    remotefile { "/etc/profile":
        source          => "config/apps/rubygems/etc_profile",
        mode            => "644",
    }
}

file wwwroot.pp:

class wwwroot {
    @file { "/srv/www":
        ensure      => directory,
	    owner		=> "www-data",
	    group		=> "www-data",
	    mode		=> "775",
    }
    realize File["/srv/www"]
}

file mysql.pp:

class mysql-server-50 {
	package { "mysql-server-5.0": }
    service { "mysql":
        ensure      => running,
        hasstatus   => no,
        pattern     => "mysqld",
    }
}

template apache_mongrel:

# Thanks to Bradley Taylor author of mongrel_cluster and owner of RailsMachine.com for this config
<VirtualHost *:80>
  ServerName <%= sitename %>
  DocumentRoot /srv/www/<%= appname %>/current/public
  <Directory "/srv/www/<%= appname %>/current/public">
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
  </Directory>
  # Configure the cluster member proxy
  <IfModule mod_proxy.c>
    ProxyRequests Off
    <Proxy *>
        AddDefaultCharset off
        Order deny,allow
        Allow from all
    </Proxy>
    ProxyVia On
  </IfModule>
  <Proxy balancer://<%= appname %>>
    BalancerMember http://127.0.0.1:5000
    BalancerMember http://127.0.0.1:5001
    BalancerMember http://127.0.0.1:5002
  </Proxy>
  RewriteEngine On
  # If there is a maintenence.html file in your
  # public dir all requests will get rerouted to
  # this file.  This is for use with capistrano
  RewriteCond %{DOCUMENT_ROOT}/maintenance.html -f
  RewriteCond %{SCRIPT_FILENAME} !maintenance.html
  RewriteRule ^.*$ /maintenance.html [L]
  # Rewrite index to check for static index.html
  RewriteRule ^/$ /index.html [QSA] 
  # Rewrite to check for Rails cached pages with .html extentions
  RewriteRule ^([^.]+)$ $1.html [QSA]
  # All dynamic requests get sent to the cluster
  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
  RewriteRule ^/(.*)$ balancer://<%= appname %>%{REQUEST_URI} [P,QSA,L]
  # Deflate for clients that support it.
  AddOutputFilterByType DEFLATE text/html text/plain text/xml
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4\.0[678] no-gzip
  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
  # Error and access logs.
  ErrorLog "|/usr/bin/cronolog /srv/www/<%= appname %>/logs/%Y/%m/error-%d.log"
  CustomLog "|/usr/bin/cronolog /srv/www/<%= appname %>/logs/%Y/%m/access-%d.log" combined
</VirtualHost>

If you have any comments or suggestions, please feel free to contact me on the mailinglist.

/jrisch