A Brand New Day, por Thomas Hawk.

No post sobre DevOps, eu disse que o Vagrant é uma ferramenta útil que facilita a criação e configuração de ambientes virtualizados e faz com que a frase “funciona na minha máquina” seja uma desculpa do passado. Certamente o Vagrant é uma ferramenta que auxilia as equipes DevOps a assegurarem coerência nos ambientes. Mas você não precisa praticar DevOps para desfrutar dos benefícios.

Você sabe, como desenvolvedor, que é difícil manter seu ambiente de desenvolvimento atualizado quando se alterna entre diferentes projetos. Até mesmo ferramentas como rbenv e phpenv (que ajudam na coexistência de diferentes versões da mesma linguagem de programação em uma mesma máquina), ainda temos problemas quando precisamos usar versões diferentes de bancos de dados, servidores de aplicações e outros softwares que compõem a pilha de dependência dos diferentes projetos.

Então você começa a compilar diferentes versões de bancos de dados, criando scripts para iniciar/parar serviços de acordo com um projeto mas, com o passar do tempo, você termina com um ambiente tão bagunçado que a manutenção torna-se um pesadelo.

Outro problema é que você começa a sentir o user space cada vez menos responsivo com o passar do tempo. O startup da sua máquina fica mais lento, especialmente quando você tem um monte de software instalado como serviço. Se estiver usando um notebook na bateria, ela pode ser descarregada mais rapidamente.

Então você desenvolve usando Mac ou Windows. Aquele novo e impressionante projeto open source? Às vezes ele não tem (um bom) suporte. Quando se tem (usando ferramentas como MacPorts, Homebrew ou Cygwin) às vezes você ficar com uma versão mais antiga de um pacote.

Eu mesmo tive problemas como esses. Eu tenho um Mac. Nos últimos anos eu trabalhei em diversos projetos baseados em PHP e tive um monte de problemas para compilar o PHP com extensões que precisam de bibliotecas como PDFlib, ICU e libxml. Há um ano, eu decidi ajudar no desenvolvimento do framework Symfony2, especificamente no componente Locale.

O componente Locale do Symfony2 depende do ICU, uma vez que usa as classes da ext/intl do PHP. Mas Fabien Potencier e os desenvolvedores do core do Symfony haviam decidido que o framework não deveria depender de funcionalidades não-core do PHP para funcionar. Então, precisávamos desenvolver uma maneira de imitar os comportamentos ​das classes ext/intl em código user land. Então Igor Wiedler e eu decidimos na hora em criar os testes comparando os resultados de nossa implementação contra a implementação ext/intl.

Então eu precisava instalar algumas versões diferentes do PHP e do ICU para encontrar qual a versão mínima que iríamos nos basear para codificar nossa implementação (nós nos baseamos na versão 4.2). Eu não queria compilar todos os softwares na minha máquina (um Macbook com o velho, mas bom MacOS X Leopard). Eu estava pensando em voltar a usar alguma distro baseada em Debian como desktop.

Nada bate uma distribuição Linux (e seus vários gerenciadores de pacotes) quando se trata de usar projetos open source para desenvolvimento de software. Mas eu ainda preferia usar o Mac como ambiente desktop. Na época, eu já estava usando o VirtualBox para desenvolvimento e, então, eu descobri o Vagrant, que tornou minha vida muito mais fácil. Desde então, eu crio um ambiente virtualizado para cada projeto. Este post mostra a maneira que eu pessoalmente uso o Vagrant.

Talk is cheap. Vamos para a diversão!

Instalação e comandos básicos

Como o Vagrant cria máquinas virtuais VirtualBox, você obviamente irá precisar dele instalado (versão 4.0.x ou 4.1.x). Faça o download da versão mais recente do Vagrant, que tem instaladores para Windows e MacOS X e pacotes para Debian, RedHat e Arch Linux. Ou você pode instalá-lo usando Rubygems:

$ sudo gem install vagrant

Com o Vagrant instalado, você terá que adicionar um box. Um box é um pacote tar, que contém uma imagem de máquina virtual base. Comece adicionando um dos boxes oficiais do Vagrant:

$ vagrant box add lucid32 http://files.vagrantup.com/lucid32.box
$ vagrant box add lucid64 http://files.vagrantup.com/lucid64.box

Ao executar um dos comandos acima, o box escolhido será baixado do site do projeto Vagrant. O primeiro argumento do comando vagrant box add é o nome do box em seu ambiente Vagrant. Você vai usá-lo para especificar qual box que você deseja usar ao criar um ambiente virtualizado. Você pode listar os boxes disponíveis no seu ambiente Vagrant com o comando vagrant box list:

$ vagrant box list
lucid32
lucid64

Após terminar o download, crie o seu primeiro ambiente virtualizado usando Vagrant:

$ vagrant init lucid32
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

Vamos discutir o arquivo Vagrantfile no próximo tópico. Como a mensagem acima diz, basta executar o comando vagrant up:

$ vagrant up

Em seguida, faça o login na VM:

$ vagrant ssh
vagrant@lucid32:~$

O Vagrant automaticamente configura uma pasta VirtualBox compartilhada no caminho /vagrant para o diretório do Vagrantfile:

vagrant@lucid32:~$ ls /vagrant/
Vagrantfile

Depois que parar de usar o ambiente virtualizado, você pode suspendê-lo (pausá-lo) ou pará-lo (desligá-lo). Primeiro, faça o log off.

vagrant@lucid32:~$ exit
$ vagrant status
Current VM states:

default                  running

The VM is running. To stop this VM, you can run `vagrant halt` to
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.

Então execute o comando vagrant suspend ou vagrant halt:

$ vagrant suspend
[default] Saving VM state and suspending execution...
$ vagrant status
Current VM states:

default                  saved

To resume this VM, simply run `vagrant up`.
$ vagrant halt
[default] Discarding saved state of VM...
$ vagrant status
Current VM states:

default                  poweroff

The VM is powered off. To restart the VM, simply run `vagrant up`

O arquivo Vagrantfile

O Vagrantfile é onde todas as definições de uma VM estão. Você pode configurar qualquer definição da VM VirtualBox. Para configurar sua VM para usar 512 MB de RAM, defina o seguinte:

config.vm.customize [
  "modifyvm", :id,
  "--memory", "512",
  "--name",   "Meu primeiro box Vagrant"
]

Se você quiser usar outro box base, mude o valor de config.vm.box para o nome do box desejado:

config.vm.box = "lucid64"

Agora imagine que você está desenvolvendo uma aplicação web e que você quer deixar que seus amigos em uma mesma rede possa acessá-la. Você pode definir um IP estático para isso:

config.vm.network :hostonly, "192.168.33.11"

Como vimos antes, Vagrant automaticamente configura a VM para usar uma pasta VirtualBox compartilhada no caminho /vagrant. Enquanto as pastas compartilhadas do VirtualBox podem ser úteis, o seu desempenho degrada rapidamente enquanto o número de arquivos na pasta compartilhada aumenta. Eu recomendo usar NFS e ignorar as pastas compartilhadas completamente (você precisa definir a VM para usar um IP estático, como mostra o exemplo anterior):

# Caminho relativo
config.vm.share_folder("v-root", "/vagrant", ".", :nfs => true)

# Caminho absoluto
config.vm.share_folder("v-root", "/vagrant", "/Users/eriksencosta/Dev/my-project", :nfs => true)

Depois de alterar o seu Vagrantfile, você precisa reiniciar a VM para que as alterações entrem em vigor:

$ vagrant halt
$ vagrant up

Se estiver usando a pasta compartilhada NFS, será solicitado a você direitos de administrador, já que o Vagrant modifica o arquivo /etc/exports para configurar corretamente o servidor NFS na máquina host.

É o suporte a provisionadores que torna o Vagrant uma ferramenta muito útil. Até aqui, você viu como criar uma nova VM e alguma configuração básica, mas faltava alguma coisa. Para desenvolver uma aplicação, nós normalmente precisamos de outros softwares instalados como linguagens de programação, bancos de dados e afins. Mas o processo de instalação deve ser repetível e, mais importante, automatizado.

Vagrant suporta provisionamento usando Chef (Solo e Server), Puppet (Standalone e Server) e Shell. Seu suporte a Chef e Puppet é uma funcionalidade valiosa para aprender e testar Cookbooks Chef e Módulos Puppet. Para simplificar, vamos configurar um ambiente LAMP usando o provisionador Shell.

## Criando um ambiente LAMP usando o provisionador Shell

Vamos criar um ambiente LAMP. Nós iremos instalar o Apache, MySQL e PHP, disponíveis nos repositórios Ubuntu, algumas ferramentas de desenvolvimento genéricas (Git, Subversion), ferramentas PHP (Phing, compositor), ferramentas de QA PHP (PHPUnit, PDepend) e uma ferramenta específica para Drupal (Drush). Faça o download ou clone o repositório Git vagrant-shell-scripts. Em seguida, adicione o trecho ao seu Vagrantfile:

Vagrant::Config.run do |config|
  config.vm.provision :shell, :path => "/path/to/vagrant-shell-scripts/db-mysql.sh"
  config.vm.provision :shell, :path => "/path/to/vagrant-shell-scripts/dev-tools.sh"
  config.vm.provision :shell, :path => "/path/to/vagrant-shell-scripts/php5.sh"
  config.vm.provision :shell, :path => "/path/to/vagrant-shell-scripts/php5-qa.sh"
  config.vm.provision :shell, :path => "/path/to/vagrant-shell-scripts/php5-tools.sh"
  config.vm.provision :shell, :path => "/path/to/vagrant-shell-scripts/drush.sh"
end

Após salvar o arquivo, execute o comando vagrant up:

$ vagrant up

Vagrant irá mostrar-lhe o progresso do provisionamento. Ao concluir, você terá um ambiente totalmente configurado. Faça o login e tente executar o comando phpunit!

Nota: depois de desligar uma máquina que tem definições de provisionamento, rodar o comando vagrant up irá fazer com que o provisionamento seja executado novamente. Caso você não queira que isso ocorra, use a opção --no-provision:

$ vagrant up --no-provision

O Vagrantfile é o que torna o processo de criação de ambientes VM repetível. É a parte de infraestrutura como código do Vagrant. Adicione-o no repositório do seu projeto para compartilhá-lo com sua equipe, então cada desenvolvedor só irá precisar executar o comando vagrant up para usar o mesmo ambiente de trabalho.

E não se esqueça de ler a excelente documentação disponível no site do Vagrant!