<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>John Leach's Blog &#187; deployment</title>
	<atom:link href="http://johnleach.co.uk/words/archives/tag/deployment/feed" rel="self" type="application/rss+xml" />
	<link>http://johnleach.co.uk/words</link>
	<description>Stuff I think, see and do</description>
	<lastBuildDate>Fri, 18 Jun 2010 22:57:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Rubinius multiple instances, one process</title>
		<link>http://johnleach.co.uk/words/archives/2008/01/15/290/rubinius-multiple-instances-one-process</link>
		<comments>http://johnleach.co.uk/words/archives/2008/01/15/290/rubinius-multiple-instances-one-process#comments</comments>
		<pubDate>Mon, 14 Jan 2008 23:42:56 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[mongrel]]></category>
		<category><![CDATA[processes]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rubinius]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[threads]]></category>

		<guid isPermaLink="false">http://johnleach.co.uk/words/archives/2008/01/15/290/</guid>
		<description><![CDATA[Rubinius has support (as of today!) for running multiple instances of it&#8217;s VM within one process, each VM on it&#8217;s own *native* thread, each VM running many ruby green threads. Each VM has it&#8217;s own heap and so each VM could load different apps that wouldn&#8217;t interfere with each other. We have plans for a [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>Rubinius has support (as of today!) for running multiple instances of it&#8217;s VM within one process, each VM on it&#8217;s own *native* thread, each VM running many ruby green threads. Each VM has it&#8217;s own heap and so each VM could load different apps that wouldn&#8217;t interfere with each other. We have plans for a mod_rubinius for apache that takes full advantage of this feature. Stay tuned ;)</p></blockquote>
<p>- <a href="http://brainspl.at/">Ezra Zygmuntowi </a>on a comment on <a href="http://www.rubyinside.com/no-true-mod_ruby-is-damaging-rubys-viability-on-the-web-693.html">Ruby Inside.</a></p>
<p>Very interesting stuff.  Why bother making Rails thread safe when you have an awesome Ruby VM such as Rubinius.  I&#8217;d like to see Mongrel (or FastCGI! Bring back FastCGI!) make use of this somehow, running multiple Rails instances itself in one process and distributing requests between them.  Interested in knowing how it&#8217;d deal with memory leaks in external libraries though (like rmagick suffers from).</p>
<p>Still, you lose finer grained access to most of the nice UNIX process management stuff though then, like limiting memory usage with ulimits, but nobody seems to be using that for Ruby deployment anyway.  It&#8217;s all fiddling around with Monit and such instead (why always with the steps backward!).</p>
]]></content:encoded>
			<wfw:commentRss>http://johnleach.co.uk/words/archives/2008/01/15/290/rubinius-multiple-instances-one-process/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>local and remote subversion repositories with Capistrano 2</title>
		<link>http://johnleach.co.uk/words/archives/2007/06/17/268/local-and-remote-subversion-repositories-with-capistrano-2</link>
		<comments>http://johnleach.co.uk/words/archives/2007/06/17/268/local-and-remote-subversion-repositories-with-capistrano-2#comments</comments>
		<pubDate>Sun, 17 Jun 2007 14:40:56 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[capistrano]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[subversion]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://johnleach.co.uk/words/archives/2007/06/17/268/</guid>
		<description><![CDATA[Peeking at the code of the upcoming Capistrano 2, I noticed you can define different scm variables for remote and local use, which is something I need (I was looking at the code in the hope it could do this :) So, say I have my code stored in a subversion repository on my local [...]]]></description>
			<content:encoded><![CDATA[<p>Peeking at the code of the upcoming <a href="http://www.capify.org/">Capistrano 2</a>, I noticed you can define different scm variables for remote and local use, which is something I need (I was looking at the code in the hope it could do this :)</p>
<p>So, say I have my code stored in a subversion repository on my local disk, say <code>file:///project/trunk</code>.  That’s fine for when Capistrano is querying the latest revision, but the remote servers need to use the repository url <code>svn+ssh://mymachine/project/trunk</code>.</p>
<p>Without modifying the code, this was impossible with Capistrano v1. With Capistrano v2, you can prefix any scm configuration variable with <code>local_</code> and it will be used for local operations:</p>
<pre><code>set :repository, "svn+ssh://mymachine/project/trunk"
set :local_repository, "file:///project/trunk"</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://johnleach.co.uk/words/archives/2007/06/17/268/local-and-remote-subversion-repositories-with-capistrano-2/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Daemontools and Ruby on Rails</title>
		<link>http://johnleach.co.uk/words/archives/2007/04/08/262/daemontools-and-ruby-on-rails</link>
		<comments>http://johnleach.co.uk/words/archives/2007/04/08/262/daemontools-and-ruby-on-rails#comments</comments>
		<pubDate>Sun, 08 Apr 2007 11:46:51 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[GNU/Linux]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[daemontools]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[fastcgi]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://johnleach.co.uk/words/archives/2007/04/08/262/</guid>
		<description><![CDATA[Dan J Bernstein&#8217;s (djb) daemontools is a set of programs to help you manage unix services. It provides a flexible, secure and convenient way of starting, stopping and sending signals to background processes. Combined with his ucspi-tcp tools, it can be used as an awesome replacement to inetd (it&#8217;s most often used in this way [...]]]></description>
			<content:encoded><![CDATA[<p>Dan J Bernstein&#8217;s (djb) <a href="http://cr.yp.to/daemontools.html" title="daemontools website">daemontools</a> is a set of programs to help you manage unix services.  It provides a flexible, secure and convenient way of starting, stopping and sending signals to background processes.  Combined with his <a href="http://cr.yp.to/ucspi-tcp.html">ucspi-tcp</a> tools, it can be used as an awesome replacement to inetd (it&#8217;s most often used in this way to run <a href="http://cr.yp.to/qmail.html">qmail</a>, a secure and high-performance mta).  It can be fiddly to set up and has a bit of a steep learning curve but I already use daemontools for various other stuff, so it was just natural for me to use it for Ruby on Rails deployment.</p>
<p><span id="more-262"></span></p>
<p>Djb has some interesting ideas about how we should be doing things on unix, namely: very differently from how we&#8217;re doing things now.  As his own software follows these rules, it tends to seem a bit odd to a new user, especially the filesystem layout.  He also doesn&#8217;t allow modified versions of his software to be distributed, so it&#8217;s a bit tricky for GNU/Linux distros to &#8220;fix&#8221; it.  Most distros get around this by distributing a source-only package, which automatically patches the code and builds you your own package &#8211; you just can&#8217;t then distribute this package to others.</p>
<p>This makes djb&#8217;s software technically non-free in the <a href="http://www.gnu.org/philosophy/free-sw.html">FSF sense</a>.  Some argue that it&#8217;s these license limitations that have kept his software so secure all these years.  I&#8217;m side stepping the issue for now &#8211; I&#8217;m either a pragmatist or I just don&#8217;t care about your freedom.  Try to decide which it is, and whether there is actually a difference.</p>
<p>Anyway, follow the docs for your distro and get daemontools up and running then I can focus on the Ruby on Rails aspect.  This post is getting a little too long and windy already.</p>
<h2>Rails</h2>
<p>So, the usual way to deploy a FastCGI RoR app is to run the spawner script to start it, then run the script every 5 minutes or so to restart the process if it crashes.  This maybe be convenient but it&#8217;s just laughable.  It delays startup on boot, leaves you high and dry for 5 minutes if ruby crashes and wastes resources checking.  And the reaper script, for restarting and stopping the process, just looks in the process list to find the pid.  More chuckling.  What decade are we in?</p>
<p>We&#8217;re going to run the RoR FastCGI process under daemontools.  It takes a little initial setup, and with multiple daemons some duplication of configs, but it will start immediately (or asap) on boot, will be restartable/reloadable without guessing pids and will restart automatically if ruby crashes.  We can even do &#8220;advanced&#8221; security stuff such as dropping secondary groups, setting resource limits and even logging that can&#8217;t be manipulated by an attacker compromising ruby.</p>
<h2>Daemontools setup</h2>
<p>Our rails app is called shop and it&#8217;s located on the filesystem at <code>/home/web/shop/current</code>.  We are going to run it as the user <code>web</code> on port 12000.  We need the <code>spawn-fcgi</code> tool from <code>lighttpd</code> too.  We&#8217;re going to run the log process as the user <code>rorlog</code>.  You need root access on the deployment box but that shouldn&#8217;t be a problem for a serious deployment.  I do have a way of configuring daemontools to allow your users to safely setup and control their own processes, but I&#8217;ll save that for another post.</p>
<ol>
<li>Make a new service directory for this service:
<pre><code>mkdir /var/lib/ror-shop</code></pre>
</li>
<li>Create the service run script (and make it executable):
<pre><code>cat &gt; /var/lib/ror-shop/run
#!/bin/sh
export RAILS_ENV=production
exec /usr/bin/spawn-fcgi -u web -g web -n -p 12000 -f /home/web/shop/current/public/dispatch.fcgi
</code></pre>
</li>
<li>Create the service log directory:
<pre><code>mkdir -p /var/lib/ror-shop/log/main</code></pre>
</li>
<li>Create the log service run script (and make it executable):
<pre><code>cat &gt; /var/lib/ror-shop/log/run
#!/bin/sh
exec setuidgid rorlog multilog t ./main
</code></pre>
</li>
<li>Symlink the new service into the daemontools services directory (usually <code>/service</code>):
<pre><code>ln -s /var/lib/ror-shop /service</code></pre>
</li>
</ol>
<p>Within 5 seconds, daemontools will see the new service and start both the ror and the log run scripts.</p>
<p>If you need to run a few processes on different ports, just make a service for each process and modify the run script to change the port.</p>
<p>By default, the logs rotate at 99999 bytes and keep 10 files archive.  See the <a href="http://cr.yp.to/daemontools/multilog.html">multilog</a> docs for arguments to change this</p>
<h2>Controlling your processes</h2>
<p>To control the process you use the <code>svc</code> command.  For example to restart the service:</p>
<pre><code>svc -t /service/ror-shop</code></pre>
<p><code>-d</code> to stop it, <code>-u</code> to start it, <code>-h</code> to reload the app, <code>-k</code> to kill it if ruby goes haywire (daemontools will restart it immediately).</p>
<p>I&#8217;m using <code>spawn-fcgi</code> to set the uid/gid because I need to preserve secondary groups in my setup and it does this.  If you don&#8217;t need this, I&#8217;d recommend using the <a href="http://cr.yp.to/daemontools/setuidgid.html">setuidguid</a> tool that comes with daemontools:</p>
<pre><code>exec setuidguid web /usr/bin/spawn-fcgi -n -p 12000 -f /home/web/shop/current/public/dispatch.fcgi</code></pre>
<p>To set some resource limits you can use the <a href="http://cr.yp.to/daemontools/softlimit.html">softlimit</a> tool.  To limit rails to 30M of ram and 300 file descriptors, use something like:</p>
<pre><code>exec softlimit -m 31457280 -o 300 setuidguid web /usr/bin/spawn-fcgi -n -p 12000 -f /home/web/shop/current/public/dispatch.fcgi</code></pre>
<p>As you can see, daemontools can be a bit tricky for a new user and a bit fiddly for a the initial setup but it is reliable, secure and flexible enough to cover most Ruby on Rails deployments for sure.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnleach.co.uk/words/archives/2007/04/08/262/daemontools-and-ruby-on-rails/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Maintenance pages status codes and Lighttpd</title>
		<link>http://johnleach.co.uk/words/archives/2007/01/10/251/maintenance-pages-status-codes-and-lighttpd</link>
		<comments>http://johnleach.co.uk/words/archives/2007/01/10/251/maintenance-pages-status-codes-and-lighttpd#comments</comments>
		<pubDate>Wed, 10 Jan 2007 14:59:42 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[GNU/Linux]]></category>
		<category><![CDATA[Networks and Firewalls]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[error]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[lighttpd]]></category>
		<category><![CDATA[lua]]></category>
		<category><![CDATA[mod_magnet]]></category>

		<guid isPermaLink="false">http://johnleach.co.uk/words/archives/2007/01/10/251/</guid>
		<description><![CDATA[I&#8217;ve noticed a few very broken maintenance page Lighttpd config examples around, including the one on the mod_magnet documentation page. They all manage to display the maintenance page ok, but they return a HTTP 200 status code to the client, rather than the more appropriate HTTP 503 code. As with all 500 status codes, the [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve noticed a few very broken maintenance page Lighttpd config examples around, including the one on the mod_magnet documentation page.  They all manage to display the maintenance page ok, but they return a HTTP 200 status code to the client, rather than the more appropriate HTTP 503 code.</p>
<p>As with all 500 status codes, the 503 code is an error code but it signifies a <strong>temporary</strong> error.  The client should try again later (in fact you can specify how much later using the <code>Retry-After</code> header).</p>
<p>A 200 code tells the client everything is normal and OK.  So the user gets your nice maintenance page telling them of a temporary outage, whereas their browser gets told that <strong>everything is fine</strong>.  Now this might not be a problem for a user, but if the client is a <strong>search engine</strong> or a <strong>caching proxy</strong> then it will assume the maintenance page is the new valid content for the request.</p>
<p>If the Google crawler hits your site when you have the maintenance page up, it will update its search index with your &#8220;we&#8217;re down for now&#8221; message, rather than your cash prizes blog content.  Your page rank will drop, your fat Adsense cheque will diminish and you&#8217;ll have to go back to your regular nine to five job in the city with people you don&#8217;t like in clothes you hate wearing.</p>
<p>So, as you can see, it&#8217;s important to return the correct status code.  Here&#8217;s how to do it with Lighty and mod_magnet:</p>
<p><span id="more-251"></span></p>
<h3>Mod_magnet</h3>
<p>Mod_magnet allows you to control request handling in Lighttpd using the Lua programming language (it replaces mod_cml and adds some bells and whistles).  Here&#8217;s how to do a maintenance page with it:</p>
<p>Ensure the module is loaded:</p>
<pre><code>server.modules += ("mod_magnet")
</code></pre>
<p>Tell it where to find your Lua script:</p>
<pre><code>magnet.attract-physical-path-to = (server.docroot + "/magnet.lua")</code></pre>
<p>Write a lua script to check for the maintenance page file and display it instead of the usual content if it exists.</p>
<pre><code>if (lighty.stat(lighty.env["physical.doc-root"] .. "/maintenance-live.html")) then
                lighty.content = { { filename = lighty.env["physical.doc-root"] .. "/maintenance-live.html" } }
                lighty.header["Content-Type"] = "text/html"
        return 503
end
</code></pre>
<p>Create your maintenance page as <code>maintenance.html</code> in your document root.  When you want it displayed, symlink it to <code>maintenance-live.html</code> and it will automatically be displayed.</p>
<p>I find it useful to be able to switch back and forth easily without restarts in and around the actual maintenance period but don&#8217;t need it day to day.  So if you worry about the extra file stat operation (and the Lua) overhead during normal periods then just comment the Lua code out when you&#8217;re done with the maintenance feature for a while.  mod_magnet will detect that you modified the Lua script and recompile it automatically.</p>
<p>You&#8217;ll notice that the <code>return 503</code> actually returns a pre-generated HTML page as well as setting the status code.  This extra bit of html gets tagged onto the end of your nice maintenance page, making it a bit ugly.  You&#8217;ll just have to put up with this for now. I see this as a bug in Lighty which needs addressing.  There should be some way to set a status code with Lua without returning the pre-generated html too.</p>
<h3>Debug access</h3>
<p>It might be convenient to disable the maintenance page for certain client IP addresses: if you&#8217;re upgrading the site, you&#8217;ll want to test it&#8217;s working yourself before disabling the maintenance page, right?  I couldn&#8217;t figure out how to get the source address from within the Lua script, so I did it as a conditional in the Lighty config:</p>
<pre><code>  $HTTP["remoteip"] != "10.0.0.1" {
    magnet.attract-physical-path-to = ( server.document-root + "/magnet.lua" )
  }
</code></pre>
<p>Using mod_magnet might be overkill for just this task, but if you&#8217;re already using it for other request processing stuff, then it&#8217;s ideal for this.  Or maybe its convenience will be enough to sway you.  Just remember to get the status code right!</p>
<p>See nixCraft for <a href="http://www.cyberciti.biz/tips/howto-disable-site-for-maintenance-with-503-error.html">another example using PHP</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnleach.co.uk/words/archives/2007/01/10/251/maintenance-pages-status-codes-and-lighttpd/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
