<?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>DestaqueBlog &#187; deployment</title>
	<atom:link href="http://weblog.destaquenet.com/tag/deployment/feed/" rel="self" type="application/rss+xml" />
	<link>http://weblog.destaquenet.com</link>
	<description>Blog da equipe Destaquenet.</description>
	<lastBuildDate>Tue, 23 Nov 2010 17:06:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Deployment de aplicações Python com Fabric</title>
		<link>http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/</link>
		<comments>http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/#comments</comments>
		<pubDate>Sun, 05 Oct 2008 10:00:05 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[capistrano]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[dicas]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[fabric]]></category>
		<category><![CDATA[ferramenta]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=101</guid>
		<description><![CDATA[Uma coisa é fato: subir uma nova versão de uma aplicação é um procedimento que, se feito manualmente, costuma demandar tempo precioso, independente do tamanho da aplicação e dos frameworks utilizados no projeto. Não há o que discutir. Na verdade, &#8230; <a href="http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Uma coisa é fato: subir uma nova versão de uma aplicação é um procedimento que, se feito manualmente, costuma demandar tempo precioso, independente do tamanho da aplicação e dos <em>frameworks</em> utilizados no projeto. Não há o que discutir.</p>
<p>Na verdade, ninguém parecia se importar em automatizar tarefas &#8220;mecânicas&#8221; como o <em>deployment</em>, coisa que mudou de figura ao passo que <a href="http://en.wikipedia.org/wiki/Agile_software_development">metodologias ágeis</a> &#8212; juntamente com técnicas como <a href="http://martinfowler.com/articles/continuousIntegration.html">Integração Contínua</a> &#8212; passaram a se tornar populares. Desde então, algum esforço vem sendo investido para criar ferramentas para automatização de muitas dessas tarefas.</p>
<p><strong>Atualização:</strong> Trechos de código adaptados para as versões mais recentes do Fabric (22/06/2010).</p>
<p><span id="more-101"></span></p>
<h3>Fabric: ferramenta Python para deployment</h3>
<p>Apesar de já ter utilizado algumas dessas <a href="http://maven.apache.org/">ferramentas</a> no desenvolvimento de projetos em <a href="http://java.sun.com/">Java</a>, plataforma na qual eu possuo uma experiência maior, eu ainda não conhecia nenhuma ferramenta em <a href="http://python.org/">Python</a> que me permitisse automatizar o <em>deployment</em> de uma aplicação.</p>
<p>Como eu estava começando a ficar de saco cheio de ter que atualizar os arquivos de uma aplicação <a href="http://djangoproject.org/">Django</a> via SCP, eu resolvi que já era hora de ir atrás de alguma ferramenta que me ajudasse a automatizar esse processo. Finalmente, depois de muita procura, eu encontrei <a href="http://www.nongnu.org/fab/index.html">Fabric</a>, uma ferramenta mais ou menos parecida com um <a href="http://www.capify.org/">Capistrano</a> &#8220;capado&#8221;.</p>
<p>A instalação do Fabric é bem simples para quem costuma usar o <a href="http://peak.telecommunity.com/DevCenter/EasyInstall">easy_install</a>:</p>
<pre>$ sudo easy_install Fabric</pre>
<p>Basta executar esse comando para que os fontes da última versão do Fabric (0.0.9 no momento da publicação deste texto) sejam baixados e instalados.</p>
<p><strong>Atenção</strong>: Quem utiliza máquinas Windows, provavelmente precisará do <a href="http://www.cygwin.com/">Cygwin</a>, já que o Fabric assume o uso de ambientes Unix.</p>
<h3>Fabric a 3.000 pés</h3>
<p>Neste momento você já deve conseguir executar o comando <code>fab</code> no terminal. Se tudo correu bem até aqui, estamos prontos continuar.</p>
<p>Vamos começar criando o arquivo <code>fabfile.py</code> no diretório-raíz da aplicação. Coloque o seguinte conteúdo neste arquivo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> fabric.<span style="color: black;">api</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
env.<span style="color: black;">project</span> = <span style="color: #483d8b;">'project_name'</span>,
env.<span style="color: black;">package</span> = <span style="color: #483d8b;">'$(project).zip'</span>,
&nbsp;
<span style="color: #808080; font-style: italic;"># Remote servers</span>
env.<span style="color: #dc143c;">user</span>  = <span style="color: #483d8b;">'usuario_ssh'</span>,
env.<span style="color: black;">hosts</span> = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'servidor1.com'</span>, <span style="color: #483d8b;">'servidor2.com'</span><span style="color: black;">&#93;</span>,
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> deploy<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Deploys the application to the production servers.&quot;</span>
    build<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> build<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Builds the application.&quot;</span>
    prepare<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> prepare<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Prepares the build directory.&quot;</span>
    clean<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> clean<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Removes the build directory.&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Cada método definido no arquivo é equivalente a uma <em>task</em> do Capistrano. No início temos as variáveis <code>env.*</code> necessárias para o <em>script</em>. Destaque para a variável <code>env.hosts</code>, que indica os servidores nos quais os comandos remotos devem ser executados.</p>
<p>Ok, tente executar o comando <code>fab -l</code> no terminal, no mesmo diretório onde se encontra o arquivo <code>fabfile.py</code>. Se tudo correr bem, você receberá a seguinte saída:</p>
<pre>
$  fab -l
Available commands:
   build      Build the application.
   clean      Remove the build directory.
   deploy     Deploy the application to the production servers.
   help       Display Fabric usage help, or help for a given command.
   license    Display the Fabric distribution license text.
   list       Display a list of commands with descriptions.
   prepare    Prepare the build directory.
   set        Set a Fabric variable.
   shell      Start an interactive shell connection to the specified hosts.
   warranty   Display warranty information for the Fabric software.
</pre>
<p>Veja que as <em>tasks</em> que criamos estão disponíveis para serem executadas via linha de comando. Para executar as <em>tasks</em> <code>clean</code> e <code>deploy</code>, por exemplo, utilizaríamos o seguinte comando:</p>
<pre>$  fab clean deploy</pre>
<p>Simples, não é? Antes de vermos um exemplo de script completo, vamos conhecer os três principais métodos utilizados em <em>scripts</em> Fabric: <code>local</code>, <code>run</code> e <code>put</code>:</p>
<ul>
<li><code>local</code>: Serve para executar comandos na máquina local. Ex: <code>local('mkdir build')</code>;</li>
<li><code>run</code>: Igual ao <code>local</code>, mas executa os comandos nas máquinas remotas (indicadas na variável <code>env.hosts</code>);</li>
<li><code>put</code>: Envia um arquivo para as máquinas remotas. Ex: <code>put('arquivo.zip', '/home/user/app.zip')</code>.</li>
</ul>
<h3>Finalmente, o script completo!</h3>
<p>Antes de mostrar o <em>script</em> que eu venho utilizando para fazer o deployment <a href="http://www.destaquenet.com/">de uma aplicação</a> Django, veja como seus arquivos e diretórios estão organizados: (isso deve ajudar a entender melhor o <em>script</em>)</p>
<div id="attachment_131" class="wp-caption aligncenter" style="width: 214px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/destaqueweb_structure.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/destaqueweb_structure-204x300.png" alt="Estrutura do projeto" title="Estrutura do projeto" width="204" height="300" class="size-medium wp-image-131" /></a><p class="wp-caption-text">Estrutura do projeto</p></div>
<p>E, finalmente, o <em>script</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Build script.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> fabric.<span style="color: black;">api</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
&nbsp;
env.<span style="color: black;">project</span> = <span style="color: #483d8b;">'destaqueweb'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Build output directory</span>
env.<span style="color: black;">build_path</span> = <span style="color: #483d8b;">'build'</span>
env.<span style="color: black;">package</span>    = <span style="color: #483d8b;">'%s.zip'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">project</span>
env.<span style="color: black;">local_path</span> = <span style="color: #483d8b;">'%s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">build_path</span>, env.<span style="color: black;">package</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Media</span>
env.<span style="color: black;">media_src</span>   = <span style="color: #483d8b;">'media'</span>
env.<span style="color: black;">media_root</span>  = <span style="color: #483d8b;">'public_html'</span>
env.<span style="color: black;">media_path</span>  = <span style="color: #483d8b;">'%s/%s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">media_root</span>, env.<span style="color: black;">project</span>, env.<span style="color: black;">media_src</span><span style="color: black;">&#41;</span>
env.<span style="color: black;">media_build</span> = <span style="color: #483d8b;">'%s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">build_path</span>, env.<span style="color: black;">media_path</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Application code</span>
env.<span style="color: black;">app_root</span>  = <span style="color: #483d8b;">'wsgi_apps'</span>
env.<span style="color: black;">app_path</span>  = <span style="color: #483d8b;">'%s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">app_root</span>, env.<span style="color: black;">project</span><span style="color: black;">&#41;</span>
env.<span style="color: black;">app_build</span> = <span style="color: #483d8b;">'%s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">build_path</span>, env.<span style="color: black;">app_path</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Remote servers</span>
env.<span style="color: black;">hosts</span>       = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'destaquenet.com'</span><span style="color: black;">&#93;</span>
env.<span style="color: black;">destination</span> = <span style="color: #483d8b;">'/home/destaquenet'</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> clean<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Removes the build directory.
    &quot;&quot;&quot;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'rm -fR %s'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">build_path</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> prepare<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Prepares the build directory.
    &quot;&quot;&quot;</span>
    clean<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'mkdir -p %s'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">media_build</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'mkdir -p %s'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">app_build</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> build<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Builds the application.
    &quot;&quot;&quot;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'cp -R %s/* %s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">project</span>, env.<span style="color: black;">build_path</span>, env.<span style="color: black;">app_path</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'cp -R %s/* %s/%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">media_src</span>, env.<span style="color: black;">build_path</span>, env.<span style="color: black;">media_path</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'find %s -name *.pyc -delete'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">build_path</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'find %s -path *upload* -delete'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">build_path</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'find %s -path *fixtures* -delete'</span> <span style="color: #66cc66;">%</span> env.<span style="color: black;">build_path</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'cd %s;zip -r %s %s %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">build_path</span>, env.<span style="color: black;">package</span>, env.<span style="color: black;">media_root</span>, env.<span style="color: black;">app_root</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> reload_app<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Reloads the app.
    &quot;&quot;&quot;</span>
    run<span style="color: black;">&#40;</span><span style="color: #483d8b;">'touch %s/%s/%s/index.wsgi'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">destination</span>, env.<span style="color: black;">media_root</span>, env.<span style="color: black;">project</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    run<span style="color: black;">&#40;</span><span style="color: #483d8b;">'python %s/%s/manage.py ping_google /sitemap.xml'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">destination</span>, env.<span style="color: black;">app_path</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> deploy<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Deploys the application to the production server.
    &quot;&quot;&quot;</span>
    build<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    put<span style="color: black;">&#40;</span>env.<span style="color: black;">local_path</span>, env.<span style="color: black;">destination</span><span style="color: black;">&#41;</span>
    run<span style="color: black;">&#40;</span><span style="color: #483d8b;">'cd %s; unzip -uo %s; rm %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>env.<span style="color: black;">destination</span>, env.<span style="color: black;">package</span>, env.<span style="color: black;">package</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    reload_app<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Este código deve ser facilmente entendido por quem tem trabalha com uma certa facilidade no terminal.</p>
<p>Basicamente o que o código faz é organizar os arquivos da aplicação para que estes fiquem dispostos da mesma forma utilizada pelo servidor de produção, enviar os arquivos dentro de um pacote ZIP para os servidores e descompactá-los no local correto, além de executar um <code>touch</code> no <em>script</em> <acronym title="Web Server Gateway Interface">WSGI</acronym> para que o <a href="http://apache.org/">Apache</a> recarregue a aplicação.</p>
<p>Tudo pronto. Agora basta executar <code>fab deploy</code> no terminal para subir a aplicação para o(s) servidor(es) desejado(s).</p>
<h3>Fabric e ambiente de homologação</h3>
<p>Uma coisa que vem se tornando comum é o uso de diferentes ambientes onde uma aplicação costuma ser implantada (ex: ambiente de homologação). Se sua empresa costuma trabalhar dessa forma, o Fabric ainda pode te ajudar.</p>
<p>Por exemplo, vamos supor que sua empresa possua um servidor de produção e um servidor de homologação. Podemos, então, adequar o <em>script</em> para que ele possa trabalhar com ambos os ambientes:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># ...</span>
env.<span style="color: #dc143c;">user</span>  = <span style="color: #483d8b;">'production'</span>,
env.<span style="color: black;">hosts</span> = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'app.com'</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> staging<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># deploy to staging servers</span>
    env.<span style="color: #dc143c;">user</span>  = <span style="color: #483d8b;">'staging'</span>
    env.<span style="color: black;">hosts</span> = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'staging.app.com'</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># other tasks...</span></pre></div></div>

<p>Fazendo as mudanças mostradas acima, para executar o <em>deployment</em> no ambiente de homologação basta rodar o comando <code>fab staging deploy</code>; o deployment em ambiente de produção continua disponível através do comando <code>fab deploy</code>.</p>
<p>Isso é possível pois podemos substituir o valor de uma variável (ou configurar novas variáveis) a qualquer momento. Então, quando executamos o comando <code>fab staging deploy</code>, o Fabric executa a <em>task</em> <code>staging</code>, substituindo o valor das variáveis <code>env.user</code> e <code>env.hosts</code>, fazendo com que os comandos contidos na <em>task</em> <code>deploy</code> sejam executados nos servidores de homologação em vez de nos servidores de produção.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

