Nick Sieger: RailsConf: Mike Clark -- Introduction to Capistrano http://blog.nicksieger.com/articles/2006/06/23/railsconf-mike-clark-capistrano en-us 40 do what you love RailsConf: Mike Clark -- Introduction to Capistrano <h2>Introduction to Capistrano</h2> <p>Mike Clark has been Java-free for 15 months and 16 days. He&#8217;s here to talk about deployment with Capistrano.</p> <p>First off, props to Jamis! There are several hundred people in the room and it&#8217;s a tribute to him.</p> <p>Capistrano is about making it easy to deploy web applications. &#8220;Cap&#8221;, the short name has quickly become jargon in the Rails community. &#8220;Stop wasting time, just cap it!&#8221;</p> <p>Capistrano is built to scale. From a single machine all the way up to clusters, it is intended to make application deployment as simple as the push of a button. That&#8217;s priceless for reducing friction as your project nears its first production live date, as well as subsequent maintenance releases.</p> <h3>Configuring Capistrano - create a recipe</h3> <h4>Set the application name</h4> <div class="typocode"><pre><code class="typocode_ruby "><span class="ident">set</span> <span class="symbol">:application</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">depot</span><span class="punct">&quot;</span></code></pre></div> <h4>Set the repository</h4> <div class="typocode"><pre><code class="typocode_ruby "><span class="ident">set</span> <span class="symbol">:repository</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">http://svn.yourhost.com/<span class="expr">#{application}</span>/trunk</span><span class="punct">&quot;</span></code></pre></div> <h4>Roles</h4> <div class="typocode"><pre><code class="typocode_ruby "><span class="ident">role</span> <span class="symbol">:app</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">app01.example.com</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">app02.example.com</span><span class="punct">&quot;</span> <span class="ident">role</span> <span class="symbol">:web</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">web01.example.com</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">web02.example.com</span><span class="punct">&quot;</span> <span class="ident">role</span> <span class="symbol">:db</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">db.example.com</span><span class="punct">&quot;,</span> <span class="symbol">:primary</span> <span class="punct">=&gt;</span> <span class="constant">true</span></code></pre></div> <h4>Deployment Root</h4> <div class="typocode"><pre><code class="typocode_ruby "><span class="ident">set</span> <span class="symbol">:deploy_to</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">/Library/Rails/<span class="expr">#{application}</span></span><span class="punct">&quot;</span></code></pre></div> <h3>Setup</h3> <p>Run <code>cap setup</code> once to setup the deployment directory structure on all the roles you&#8217;ve configured:</p> <pre><code>depot `- releases `- shared `- log `- system </code></pre> <h3>First time deploy</h3> <p>Run <code>cap update_code symlink</code>. This checks out the code, adds a &#8220;current&#8221; symlink to the code on the remote machine that points to the timestamped releases directory where the code was checked out. You can then manually start your web server(s) if you wish.</p> <h3>New Release</h3> <p>Run <code>cap deploy</code>. The newly committed code to your repository gets pulled, a new release created, and it also restarts fcgi processes.</p> <h3>Rollback release</h3> <p>Run <code>cap rollback</code>. The &#8220;current&#8221; symlink gets updated to the previous release, and the fcgi processes get restarted.</p> <h3>Scheduled downtime</h3> <p>Run <code>cap disable_web</code>. A maintenance screen is put up during the maintenance period. This is great when you&#8217;re in firefighting mode and you don&#8217;t want to think, just get the page up there. To enable again, use <code>cap enable_web</code>.</p> <h3>Customization</h3> <p>Here are examples of several useful, real-world tasks. The fourth task shows aggregation of tasks together.</p> <div class="typocode"><pre><code class="typocode_ruby "><span class="ident">desc</span> <span class="punct">&quot;</span><span class="string">locate ruby</span><span class="punct">&quot;</span> <span class="ident">task</span> <span class="symbol">:which_ruby</span><span class="punct">,</span> <span class="symbol">:roles</span> <span class="punct">=&gt;</span> <span class="punct">[</span><span class="symbol">:app</span><span class="punct">]</span> <span class="keyword">do</span> <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">You're running:</span><span class="punct">&quot;</span> <span class="ident">run</span> <span class="punct">&quot;</span><span class="string">which ruby</span><span class="punct">&quot;</span> <span class="keyword">end</span> <span class="ident">task</span> <span class="symbol">:current_revision</span> <span class="keyword">do</span> <span class="ident">run</span> <span class="punct">&quot;</span><span class="string">echo Current rev is <span class="expr">#{revision}</span></span><span class="punct">&quot;</span> <span class="ident">run</span> <span class="punct">&quot;</span><span class="string">echo Current rev is at <span class="expr">#{releast_path}</span></span><span class="punct">&quot;</span> <span class="keyword">end</span> <span class="ident">task</span> <span class="symbol">:uptime</span><span class="punct">,</span> <span class="symbol">:roles</span> <span class="punct">=&gt;</span> <span class="punct">[</span><span class="symbol">:app</span><span class="punct">,</span> <span class="symbol">:web</span><span class="punct">,</span> <span class="symbol">:db</span><span class="punct">]</span> <span class="keyword">do</span> <span class="ident">run</span> <span class="punct">&quot;</span><span class="string">uptime</span><span class="punct">&quot;</span> <span class="keyword">end</span> <span class="ident">task</span> <span class="symbol">:status</span> <span class="keyword">do</span> <span class="ident">which_ruby</span> <span class="ident">current_revision</span> <span class="ident">uptime</span> <span class="keyword">end</span></code></pre></div> <h3>Channels and streams</h3> <p>Mike showed a log file tailing task here. I failed to capture the full task code, so you&#8217;re on your own here.</p> <h3>Hooks</h3> <div class="typocode"><pre><code class="typocode_ruby "><span class="ident">task</span> <span class="symbol">:before_deploy</span><span class="punct">,</span> <span class="symbol">:roles</span> <span class="punct">=&gt;</span> <span class="punct">[</span><span class="symbol">:app</span><span class="punct">]</span> <span class="keyword">do</span> <span class="ident">cleanup</span> <span class="keyword">end</span> <span class="ident">task</span> <span class="symbol">:after_update_code</span><span class="punct">,</span> <span class="symbol">:roles</span> <span class="punct">=&gt;</span> <span class="punct">[</span><span class="symbol">:app</span><span class="punct">]</span> <span class="keyword">do</span> <span class="ident">production_config</span> <span class="punct">=</span> <span class="punct">&quot;</span><span class="string">path/to/database.yml</span><span class="punct">&quot;</span> <span class="ident">run</span> <span class="punct">&quot;</span><span class="string">cp <span class="expr">#{production_config}</span> <span class="expr">#{current_path}</span>/config/database.yml</span><span class="punct">&quot;</span> <span class="keyword">end</span></code></pre></div> <h3>Multiple configs</h3> <div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">if</span> <span class="ident">where</span> <span class="punct">==</span> <span class="punct">&quot;</span><span class="string">production</span><span class="punct">&quot;</span> <span class="ident">set</span> <span class="symbol">:user</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">ops_gal</span><span class="punct">&quot;</span> <span class="keyword">else</span> <span class="ident">set</span> <span class="symbol">:user</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">dev_guy</span><span class="punct">&quot;</span> <span class="keyword">end</span></code></pre></div> <h3>Task libraries</h3> <p>You can creat a file full of extra, reusable tasks and simply <code>require</code> them in. The files can be published and installed as gems or placed anywhere on your load path.</p> <h3>Capistrano isn&#8217;t just for Rails</h3> <p>It&#8217;s great at shuttling files around and executing remote commands on the server. Mike describes some automation James Duncan Davidson did to replicate new servers into a cluster with the push of a button.</p> <h3>Assumptions</h3> <p>Capistrano, out of the box comes with some assumptions:</p> <ul> <li>Remote servers talk POSIX</li> <li>Same deploy structure and password on each machine</li> <li>Web application uses FastCGI with Apache or Lighty</li> </ul> <p>It looks like you can bend some of these assumptions if you are willing to write your own custom deployment tasks.</p> <h3>Take Home</h3> <p>Capistrano provides easy, consistent, worry-free deployment of new releases. The friction to deploying your app just got simpler, so you can go enjoy your life!</p> <h3>Notes and Questions</h3> <ul> <li>Can you use SSH public keys to authenticate? <em>Yes, this is the most typical scenario.</em></li> <li>You can use <code>sudo</code> to execute remote commands &#8211; this is built-in.</li> <li>Can you/would you want to check out subsets of files on each server, rather than pulling all the code everywhere? <em>So far most of our stuff has been on the same server, so this hasn&#8217;t been an issue. It seems like you would need to override deployment tasks for some roles.</em></li> <li>Sometimes I want to deploy a lot, but what if the app is big, lots of media files? It can take a longer time to pull all the code. <em>One solution I&#8217;ve seen is to check out once and rsync everywhere else. I haven&#8217;t had to do that myself.</em></li> <li>Who can I talk to for promoting my own extensions into Capistrano. <em>You probably don&#8217;t. Instead, publish your extensions, blog them, and see if it takes.</em></li> <li><code>deploy_with_migrations</code> &#8211; use with caution as it&#8217;s not as easy to rollback, and not all migrations can be rolled back cleanly.</li> </ul> Fri, 23 Jun 2006 16:45:00 +0000 urn:uuid:fd4b197e-ec51-47aa-bc0c-7e90a4339f19 Nick Sieger http://blog.nicksieger.com/articles/2006/06/23/railsconf-mike-clark-capistrano ruby rails railsconf http://blog.nicksieger.com/articles/trackback/23