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, ninguém parecia se importar em automatizar tarefas “mecânicas” como o deployment, coisa que mudou de figura ao passo que metodologias ágeis — juntamente com técnicas como Integração Contínua — passaram a se tornar populares. Desde então, algum esforço vem sendo investido para criar ferramentas para automatização de muitas dessas tarefas.
Atualização: Trechos de código adaptados para as versões mais recentes do Fabric (22/06/2010).
Fabric: ferramenta Python para deployment
Apesar de já ter utilizado algumas dessas ferramentas no desenvolvimento de projetos em Java, plataforma na qual eu possuo uma experiência maior, eu ainda não conhecia nenhuma ferramenta em Python que me permitisse automatizar o deployment de uma aplicação.
Como eu estava começando a ficar de saco cheio de ter que atualizar os arquivos de uma aplicação Django 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 Fabric, uma ferramenta mais ou menos parecida com um Capistrano “capado”.
A instalação do Fabric é bem simples para quem costuma usar o easy_install:
$ sudo easy_install Fabric
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.
Atenção: Quem utiliza máquinas Windows, provavelmente precisará do Cygwin, já que o Fabric assume o uso de ambientes Unix.
Fabric a 3.000 pés
Neste momento você já deve conseguir executar o comando fab no terminal. Se tudo correu bem até aqui, estamos prontos continuar.
Vamos começar criando o arquivo fabfile.py no diretório-raíz da aplicação. Coloque o seguinte conteúdo neste arquivo:
from fabric.api import * env.project = 'project_name', env.package = '$(project).zip', # Remote servers env.user = 'usuario_ssh', env.hosts = ['servidor1.com', 'servidor2.com'], def deploy(): "Deploys the application to the production servers." build() def build(): "Builds the application." prepare() def prepare(): "Prepares the build directory." clean() def clean(): "Removes the build directory." pass
Cada método definido no arquivo é equivalente a uma task do Capistrano. No início temos as variáveis env.* necessárias para o script. Destaque para a variável env.hosts, que indica os servidores nos quais os comandos remotos devem ser executados.
Ok, tente executar o comando fab -l no terminal, no mesmo diretório onde se encontra o arquivo fabfile.py. Se tudo correr bem, você receberá a seguinte saída:
$ 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.
Veja que as tasks que criamos estão disponíveis para serem executadas via linha de comando. Para executar as tasks clean e deploy, por exemplo, utilizaríamos o seguinte comando:
$ fab clean deploy
Simples, não é? Antes de vermos um exemplo de script completo, vamos conhecer os três principais métodos utilizados em scripts Fabric: local, run e put:
local: Serve para executar comandos na máquina local. Ex:local('mkdir build');run: Igual aolocal, mas executa os comandos nas máquinas remotas (indicadas na variávelenv.hosts);put: Envia um arquivo para as máquinas remotas. Ex:put('arquivo.zip', '/home/user/app.zip').
Finalmente, o script completo!
Antes de mostrar o script que eu venho utilizando para fazer o deployment de uma aplicação Django, veja como seus arquivos e diretórios estão organizados: (isso deve ajudar a entender melhor o script)
E, finalmente, o script:
#!/usr/bin/env python # -*- coding: utf-8 -*- """Build script. """ from fabric.api import * env.project = 'destaqueweb' # Build output directory env.build_path = 'build' env.package = '%s.zip' % env.project env.local_path = '%s/%s' % (env.build_path, env.package) # Media env.media_src = 'media' env.media_root = 'public_html' env.media_path = '%s/%s/%s' % (env.media_root, env.project, env.media_src) env.media_build = '%s/%s' % (env.build_path, env.media_path) # Application code env.app_root = 'wsgi_apps' env.app_path = '%s/%s' % (env.app_root, env.project) env.app_build = '%s/%s' % (env.build_path, env.app_path) # Remote servers env.hosts = ['destaquenet.com'] env.destination = '/home/destaquenet' def clean(): """Removes the build directory. """ local('rm -fR %s' % env.build_path) def prepare(): """Prepares the build directory. """ clean() local('mkdir -p %s' % env.media_build) local('mkdir -p %s' % env.app_build) def build(): """Builds the application. """ local('cp -R %s/* %s/%s' % (env.project, env.build_path, env.app_path)) local('cp -R %s/* %s/%s' % (env.media_src, env.build_path, env.media_path)) local('find %s -name *.pyc -delete' % env.build_path) local('find %s -path *upload* -delete' % env.build_path) local('find %s -path *fixtures* -delete' % env.build_path) local('cd %s;zip -r %s %s %s' % (env.build_path, env.package, env.media_root, env.app_root)) def reload_app(): """Reloads the app. """ run('touch %s/%s/%s/index.wsgi' % (env.destination, env.media_root, env.project)) run('python %s/%s/manage.py ping_google /sitemap.xml' % (env.destination, env.app_path)) def deploy(): """Deploys the application to the production server. """ build() put(env.local_path, env.destination) run('cd %s; unzip -uo %s; rm %s' % (env.destination, env.package, env.package)) reload_app()
Este código deve ser facilmente entendido por quem tem trabalha com uma certa facilidade no terminal.
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 touch no script WSGI para que o Apache recarregue a aplicação.
Tudo pronto. Agora basta executar fab deploy no terminal para subir a aplicação para o(s) servidor(es) desejado(s).
Fabric e ambiente de homologação
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.
Por exemplo, vamos supor que sua empresa possua um servidor de produção e um servidor de homologação. Podemos, então, adequar o script para que ele possa trabalhar com ambos os ambientes:
# ... env.user = 'production', env.hosts = ['app.com'] def staging(): # deploy to staging servers env.user = 'staging' env.hosts = ['staging.app.com'] # other tasks...
Fazendo as mudanças mostradas acima, para executar o deployment no ambiente de homologação basta rodar o comando fab staging deploy; o deployment em ambiente de produção continua disponível através do comando fab deploy.
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 fab staging deploy, o Fabric executa a task staging, substituindo o valor das variáveis env.user e env.hosts, fazendo com que os comandos contidos na task deploy sejam executados nos servidores de homologação em vez de nos servidores de produção.

Posts em Português
Posts in English
Na verdade dá para automatizar muitas das tarefas que possam ser feitas através da execução comandos de terminal (locais e remotos).
Muito bom!
Pelo visto, dá pra fazer deploy de qualquer aplicação, mesmo que não seja Python, não é?
Pingback: Destaquenet blog » Blog Archive » Integração Contínua de aplicações Python com Hudson
Pingback: Fabric + VirtualEnv: uma combinação explosiva (no bom sentido) « Destaquenet blog
Muito bom o artigo, vou estudar um pouco mais tanto o Fabric como o Capistrano pois estou exatamente com o problema que você relatou no início do artigo.
Vai ser de grande ajuda, obrigado!
Valeu Ruhan!
Várias coisas mudaram no Fabric desde a publicação deste texto. Assim que possível, eu darei um jeito de atualizar o post.
[]s!
Desse eu gostei. Ele é mais “Pythônico”. Fora que segue um pouco o ANT na automação de processos.