Usando o Vagrant como ambiente de desenvolvimento no Windows


Leia em 12 minutos

Vagrant

O Vagrant é um projeto que permite virtualizar o ambiente de desenvolvimento de forma simples. No caso específico do Windows, você precisava instalar algo como o Cygwin (que convenhamos, não funciona tão bem assim) se quisesse usar alguma ferramenta do Unix.

Com o Vagrant você pode executar máquinas virtuais utilizando o VirtualBox ou VMware. Estas máquinas virtuais podem ter qualquer configuração e programas instalados e você pode, inclusive, criar a sua própria configuração com muita facilidade. Isso ajuda bastante quando um novo funcionário é contratado, por exemplo. Se todo o seu ambiente de desenvolvimento for baseado em boxes (box é o nome que o Vagrant utilizada para definir cada máquina virtual) personalizados, tudo o que ele precisa fazer é instalar o Vagrant e executar um único comando. Simples assim.

Voltemos ao Windows. Todo mundo que já tentou desenvolver com Ruby/Rails no Windows sabe o quão lento ele é. Não é um pouquinho lento. É muuuuuuuuuuito lento. Em uma das turmas do curso de Ruby on Rails um dos alunos usava Windows. Enquanto todos os que usavam Macs e Linux rodavam 100 testes em 4 segundos, esta mesma suíte de testes demorava mais do que 4 minutos para ser executada no Windows.

Além disso, o Windows é um péssimo sistema operacional para quem precisa trabalhar constantemente na linha de comando. O PowerShell, que é infinitamente melhor que a versão anterior da linha de comando, ainda não chega nem perto de um Bash.

Com o Vagrant você consegue resolver todos estes problemas. No fim das contas, você irá executar uma distribuição Linux.

O fluxo de desenvolvimento com o Vagrant muda um pouco, mas não muito. Você usará a máquina virtual como um terminal. Em vez de abrir o PowerShell, por exemplo, você irá se conectar através de SSH. Uma grande vantagem do Vagrant é que ele compartilha um diretório entre o host (a máquina real, neste caso um Windows) e o guest (a máquina virtual). Qualquer alteração realizada em uma das pontas será imediatamente refletida na outra. Você pode continuar utilizando o seu editor de texto (ou IDE) favorito no Windows, e executar o projeto no Linux. Mais fácil impossível.

Agora que você já sabe como tudo isso funciona, vamos configurar o seu sistema. Para este artigo, utilizei um servidor Windows configurado na Amazon EC2, mas o processo não muda nada para a sua instalação real.

NOTA: Estas dicas também servem para quem trabalha com Linux e Mac, mas não quer configurar as instalações na máquina real. Estou trabalhando desta forma há mais de um ano no Mac! :)

NOTA 2: Este artigo foi originalmente publicado em 16/06/2012 e atualizado para refletir as alterações introduzidas na versão 1.2.

NOTA 3: Eu falei sobre Vagrant no Guru-SP e na RubyConf Brasil 2013. Não deixe de assistir!

Instalando o VirtualBox

O primeiro passo é instalar o VirtualBox. Acesse a página de downloads e baixe a versão própria para o seu sistema operacional. Inicie a instalação, e avance todos os passos como nas imagens abaixo.

Após finalizar a instalação, você poderá instalar o Vagrant.

Instalando o Vagrant

Agora é a vez do Vagrant. Acesse o site do Vagrant e faça o download da versão para o seu sistema operacional. Inicie a instalação, e avance todos os passos como nas imagens abaixo.

Agora, precisamos adicionar um novo box ao Vagrant. Para os cursos de Rails, decidi por criar um box com tudo instalado, para que os alunos não precisem se preocupar em fazer isso manualmente. Este box já vem com uma série de configurações e programas, dentre eles:

Para adicionar o box, abra o seu terminal e execute o comando vagrant box add hellobits http://files.hellobits.com/vagrant/hellobits-64bits-virtualbox.box. Isso pode demorar algum tempo, já que a imagem com 559MB precisará ser baixada.

Veja uma lista de todas as imagens disponíveis na Hellobits:

Antes de iniciar uma nova máquina virtual, você precisa fazer uma coisa: baixar um programa chamado PuTTY, que permitirá a conexão através do SSH. Se você usa Mac ou Linux, pode pular este passo.

Acesse a página de downloads do PuTTy e baixe os programas putty.exe e puttygen.exe. Execute o programa puttygen.exe; nós iremos gerar uma chave privada de SSH que possa ser utilizada no PuTTY.

Criando a chave Privada de SSH com o PuTTYgen

Clique no botão “Load”, selecione o arquivo C:/Users/<seu usuário>/.vagrant.d/insecure_private_key e clique em “Open”.

Criando a chave Privada de SSH com o PuTTYgen

Isso irá carregar a chave privada de SSH utilizada pelo Vagrant.

Criando a chave Privada de SSH com o PuTTYgen

Clique no botão “Save private key”. Uma janela perguntando se você quer continuar sem uma senha irá aparecer. Clique no botão “Yes”.

Criando a chave Privada de SSH com o PuTTYgen

Salve este arquivo com o nome “vagrant.ppk” no mesmo diretório do arquivo “insecure_private_key”.

Criando a chave Privada de SSH com o PuTTYgen

Se não quiser criar este arquivo manualmente, deixei o arquivo que exportei disponível.

Pronto! Agora podemos criar uma nova máquina virtual.

Iniciando uma nova máquina com o Vagrant

Para iniciar uma nova máquina virtual, volte ao terminal e crie um novo diretório. Eu usei myapp, mas prefira algo mais útil como Projetos. De dentro deste diretório, execute o comando vagrant init hellobits.

Criando o arquivo de configuração Vagrantfile

Toda vez que você atualizar a versão do VirtualBox our VMware, precisará atualizar também o programa que gerencia a interação entre o host e o guest, como compartilhamento de diretórios.

No VirtualBox, a maneira mais simples de fazer isso é instalando um plugin chamado vagrant-vbguest. Para instalá-lo, execute o comando vagrant plugin install vagrant-vbguest:

Instalando o plugin vagrant-vbguest

Agora, toda vez que sua máquina for iniciada com o comando vagrant up, ele irá verificar se a versão deste programa precisa ser atualizada e, em caso positivo, fará isso automaticamente.

O plugin vagrant-vbguest não tem suporte para VMware; neste caso, instale o pacote open-vm-tools na máquina virtual e recarre suas configurações com o comando vagrant reload.

Abra o arquivo Vagrantfile, gerado com o comando anterior. Para editá-lo como o exemplo abaixo.

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hellobits"
  config.vm.box_url = "http://files.hellobits.com/vagrant/hellobits-64bits-virtualbox.box"

  config.vm.network :forwarded_port, guest: 3000, host: 3000
end

Este arquivo de configuração é utilizado para iniciar uma nova máquina. Aqui, estamos especificando o nome do box utilizado, e em qual URL ele pode ser encontrado caso ele ainda não tenha sido adicionado. Já a linha config.vm.network :forwarded_port, guest: 3000, host: 3000 especifica o número da porta do servidor Rails, que por padrão é iniciado na porta 3000. Essa configuração permite que você acesse o servidor à partir de seu navegador local.

Se quiser, pode criar um arquivo mais completo, que mapeia mais portas, como no exemplo à seguir:

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hellobits"
  config.vm.box_url = "http://files.hellobits.com/vagrant/hellobits-64bits-virtualbox.box"

  config.vm.network :forwarded_port, guest: 3000, host: 3000    # rails
  config.vm.network :forwarded_port, guest: 9292, host: 9292    # rack
  config.vm.network :forwarded_port, guest: 4567, host: 4567    # sinatra
  config.vm.network :forwarded_port, guest: 1080, host: 1080    # mailcatcher
  config.vm.network :forwarded_port, guest: 8888, host: 8888    # jasmine
  config.vm.network :forwarded_port, guest: 3306, host: 3306    # mysql
  config.vm.network :forwarded_port, guest: 1234, host: 1234    # node
  config.vm.network :forwarded_port, guest: 5432, host: 5432    # postgresql
  config.vm.network :forwarded_port, guest: 6379, host: 6379    # redis
  config.vm.network :forwarded_port, guest: 9200, host: 9200    # elasticsearch
  config.vm.network :forwarded_port, guest: 27017, host: 27017  # mongodb
  config.vm.network :forwarded_port, guest: 80, host: 8080      # apache/nginx
end

Agora, você já pode iniciar o servidor. Isso pode ser feito com o comando vagrant up. Este comando pode demorar um pouco na primeira vez que é executado.

Iniciando o servidor virtual

O próximo passo é acessar o seu servidor por SSH.

Iniciando uma conexão com SSH

Para conectar ao servidor que você acabou de adicionar, vai precisar conectar através de SSH. Para isso, execute o comando vagrant ssh. Infelizmente, este comando, que inicia uma conexão automática com o servidor, não funciona no Windows. Para isso, nós iremos utilizar um programa chamado PuTTY.

Resposta do comando `vagrant ssh`

Abra o PuTTY. O endereço de conexão é vagrant@127.0.0.1 e a porta utilizada é a 2222. Perceba que a porta que você precisa conectar pode mudar dependendo de quantas máquinas virtuais você já está executando.

Conectando ao servidor com o PuTTY

Selecione a seção “Connection > SSH > Auth”. Clique no botão “Browse” e selecione o arquivo “vagrant.ppk”. Se você seguiu todas as instruções corretamente, ele deve ter sido salvo em C:/Users/<seu usuário>/.vagrant.d/vagrant.ppk.

Conectando ao servidor com o PuTTY

Como você irá utilizar estas configurações constantemente, salve-as. Para isso, volte até a seção “Session”, digite um nome no campo “Saved Sessions” e clique no botão “Save”.

Salvando as configurações do PuTTY

Para iniciar a conexão, clique no botão “Open”, presente na seção “Session” . Se tudo der certo, uma janela perguntando se quer conectar no servidor irá aparecer. Clique no botão “Yes”.

Confirmando a conexão com o servidor

Sua conexão com o servidor foi iniciada! Agora, você já pode configurar o Rails.

Acesso ao servidor

Note que o box Vagrant da Hellobits foi configurado para uma tema branco. Você precisará modificar a cor do Putty na opção “Window > Colors > Default Background”.

Configurando as cores do Putty

Configurando o Ruby on Rails

Para instalar o Ruby on Rails, basta executar o comando gem install rails. Isso instalará o Rails e todas as suas dependências.

Instalando o Rails

Depois de instalado, você poderá criar o seu primeiro app. Para isso, acesse o diretório “/vagrant”. Este diretório é compartilhado entre o servidor virtual e sua máquina. Qualquer alteração realizada em qualquer uma das pontas será imediatamente refletida na outra. Atenção: se você remover qualquer arquivo deste diretório, ele também será imediatamente removido de sua máquina local.

Execute o comando rails new myapp -d mysql para iniciar um novo app configurado para o MySQL.

Gerando um novo app

O MySQL pode ser acessado com o usuário root, sem nenhuma senha. Seu servidor Rails já pode ser executado com o comando rails server.

Executando o comando `rails server`

O seu app Rails já está rodando! Para saber se está tudo funcionando corretamente, abra o seu navegador na máquina host e acesse o endereço http://127.0.0.1:3000. Neste exemplo, estou usando o Internet Explorer. Você deverá ver a página inicial do Rails.

Página inicial do Rails

Alguns comandos úteis

Quando você não quiser mais trabalhar (todo mundo precisa de uma pausa de vez em quando), pode pausar a execução de sua máquina virtual com o comando vagrant suspend. Para reiniciar a máquina virtual, execute o comando vagrant resume. Estes dois comandos permitirão reiniciar a sua máquina virtual no exato ponto onde ela estava antes de ser pausada.

Se você decidir que quer recomeçar um novo ambiente, pode simplesmente remover a máquina virtual existente. Para isso, execute o comando vagrant destroy e inicie uma nova com o comando vagrant up. Os arquivos compartilhados não serão removidos, mas todo o resto sim! Isso inclui dados salvos no banco e arquivos de configuração adicionados no próprio servidor.

E lembre-se! Se você está em um outro sistema operacional como Mac OS X ou Linux, acesse sua máquina virtual com o comando vagrant ssh.

É uma ótima ideia dar uma lida na documentação. Ela é bem completa, com uma leitura fácil, mas está disponível apenas em inglês (o que não deve ser um problema, certo?).

Manutenção de sua máquina virtual

Esta máquina virtual nada mais é que um Ubuntu Linux Server 12.04 LTS 64-bits. Por isso, todas as coisas que você faria normalmente em um Ubuntu Server, podem ser feitas aqui também.

Vez ou outra é bom você atualizar os pacotes. Para fazer isso, execute os comandos abaixo como sudoer (o usuário vagrant não possui senha para executar o comando sudo).

sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade
sudo apt-get autoremove
sudo apt-get clean

Sobre o Ruby

O Ruby está instalado através do pacote Debian que mantenho em um repositório da Hellobits. Sempre que uma nova versão é lançada, eu atualizo este pacote. Então, para atualizar para a versão mais recente, basta executar os comandos apt-get.

sudo apt-get update
sudo apt-get upgrade

Se você precisa trabalhar com versões mais antigas, ou até mesmo com mais de uma versão em diferentes projetos, instale o RVM ou rbenv.

Outras configurações do Vagrant

Existem algumas outras configurações do Vagrant muito interessantes. Por exemplo, para controlar a quantidade de memória que sua máquina virtual terá, não é necessário usar a interface do VirtualBox/VMware. Basta adicinar a configuração abaixo ao seu arquivo Vagrantfile que, neste caso, dedica 2GB de memória.

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hellobits"
  config.vm.box_url = "http://files.hellobits.com/vagrant/hellobits-64bits-virtualbox.box"

  config.vm.provider :virtualbox do |vb|
    vb.customize ["modifyvm", :id, "--memory", "2048"]
  end

  config.vm.provider(:vmware_fusion) do |v|
    v.vmx["memsize"] = "2048"
  end
end

Se você precisa criar links simbólicos no VirtualBox (por exemplo, se estiver instalando pacotes com NPM, o gerenciador de dependências do Node.js), precisará da configuração abaixo.

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hellobits"
  config.vm.box_url = "http://files.hellobits.com/vagrant/hellobits-64bits-virtualbox.box"

  config.vm.provider :virtualbox do |vb|
    vb.customize [
      "setextradata", :id,
      "VBoxInternal2/SharedFoldersEnableSymlinksCreate/v-root", "1"
    ]
  end
end

Também é possível definir o diretório raíz mapeado pelo Vagrant. Além disso, você também pode mapear outros diretórios que não precisam estar criados relativamente ao arquivo Vagrantfile.

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hellobits"
  config.vm.box_url = "http://files.hellobits.com/vagrant/hellobits-64bits-virtualbox.box"

  config.vm.synced_folder ".", "/Projects", id: "vagrant-root"
  config.vm.synced_folder "~/projects", "/Repos", id: "vagrant-repos"
end

Finalmente, uma opção que venho usando em vez de mapear todas as portas que quero deixar disponíveis é definir um IP fixo para a máquina virtual.

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hellobits"
  config.vm.box_url = "http://files.hellobits.com/vagrant/hellobits-64bits-virtualbox.box"

  config.vm.network :private_network, ip: "192.168.50.2"
end

Isso fará com que esta máquina virtual seja acessível através do endereço IP 192.168.33.2. Então, em vez de mapear a porta do Rails, por exemplo, posso simplesmente acessar o endereço http://192.168.33.2:3000. Como este IP não muda, você pode adicionar um hostname ao seu arquivo /etc/hosts ou equivalente (isso deve ser feito no host, ou seja, a sua máquina real). Desse modo, posso acessar a minha máquina virtual através do endereço http://dev:3000, em vez de decorar o endereço IP.

127.0.0.1 localhost
192.168.33.2 dev

Lembre-se que você deve liberar os serviços para serem acessíveis de outros endereços além de 127.0.0.1, pois o binding é normalmente feito para este endereço IP.

Para ver a lista completa de opções que o Vagrant suporta, acesse a documentação. Outras opções podem ser definidas seguindo a API do VirtualBox.

Perguntas frequentes

Qual a senha de root do servidor?

O usuário vagrant é sudoer e não possui senha. Isso significa que você pode executar tarefas que exigem permissões de administrador com o comando sudo [comando] e não será perguntado sobre a senha deste usuário.

Como faço para acessar o MySQL usando uma interface gráfica?

Primeiro, você precisará configurar o MySQL para que ele ouça as conexões originadas por outros endereços IP que não 127.0.0.1. Abra o arquivo /etc/mysql/my.cnf e comente a linha que contém a configuração bind-address. Se você está usando o box da Hellobits, isso já vem comentado por padrão.

Agora, execute o comando abaixo para permitir que o usuário root possa conectar nessa máquina.

mysql -u root -e "CREATE USER 'root'@'%'; GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;"

Finalmente, faça o mapeamento da porta 3306 no arquivo Vagrantfile.

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hellobits"
  config.vm.box_url = "http://files.hellobits.com/vagrant/hellobits-64bits-virtualbox.box"

  config.vm.network :forwarded_port, guest: 3306, host: 3306    # mysql
end

Configure o seu cliente com o host 127.0.0.1 e usuário root, sem senha. Se você você está definindo o endereço IP da máquina virtual, use-o em vez de 127.0.0.1.

Configurando o Sequel Pro com o Vagrant

Como configuro o arquivo database.yml com o PostgreSQL?

Para usar o PostgreSQL, basta utilizar os dados de conexão abaixo.

defaults: &defaults
  adapter: postgresql
  encoding: unicode
  pool: 5
  username: vagrant
  password:
  min_messages: warning

development:
  <<: *defaults
  database: sample_development

test:
  <<: *defaults
  database: sample_test

production:
  <<: *defaults
  database: sample_production

Estou recebendo um erro “Vagrant cannot forward the specified ports on this VM…”. O que está acontecendo?

Este erro significa que uma porta que você está mapeando já está em uso. Este erro acontece frequentemente quando você tenta mapear a porta do MySQL mas ele também está rodando no host. Para corrigir, você tem algumas alternativas:

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hellobits"
  config.vm.box_url = "http://files.hellobits.com/vagrant/hellobits-64bits-virtualbox.box"

  config.vm.network :forwarded_port, guest: 3306, host: 3306, auto_correct: true
end

Estou enfrentando uma lentidão muito grande. O que posso fazer?

Às vezes, operações que envolvem o filesystem podem ser muito lentas. Esse problema raramente acontece se você tem SSD, mas pode acontecer esporadicamente. Você pode tentar usar o compartilhamento de diretórios como NFS, mas saiba que esta opção não está disponível se você estiver usando o Windows como host.

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hellobits"
  config.vm.synced_folder ".", "/vagrant", :nfs => true
end

Você também pode definir algumas opções de performance recomendadas pelas documentações do VirtualBox e VMware.

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hellobits"

  config.vm.provider :virtualbox do |vb|
    vb.customize [
      "setextradata", :id,
      "VBoxInternal/Devices/ahci/0/LUN#[0]/Config/IgnoreFlush", "1"
    ]
  end

  config.vm.provider(:vmware_fusion) do |v|
    v.vmx["MemTrimRate"] = "0"
    v.vmx["sched.mem.pshare.enable"] = "FALSE"
  end
end

Minhas alterações parecem não surtir efeito.

Sempre que você fizer uma alteração, execute o comando vagrant reload. Às vezes este comando falha; neste caso, execute o comando vagrant halt e depois, vagrant up.

Próximos passos

Embora pareça um processo complicado, ele é bastante simples. É muito melhor do que configurar o seu ambiente como neste outro artigo que escrevi. E se você usa um outro sistema operacional, dê uma olhada também. Na minha opinião, é muito mais fácil de manter um ambiente coeso, com instalações muito próximas de um servidor real.

Se você pretende ter um box por cada projeto, você pode definir como sua máquina será provisionada. Você pode configurar a sua máquina usando Puppet, Chef ou até mesmo um script shell. A grande vantagem é que os mesmos scripts usados para configurar o servidor de produção podem ser usados em desenvolvimento, e vice-versa.

Se você quer aprender mais sobre Rails, não deixe de conhecer o meu curso de Ruby on Rails. Ele é apresentado nas modalidades presencial e online e, com certeza, irá dar um conhecimento muito bom sobre este framework.