Go to English Blog

Usando o Vagrant como ambiente de desenvolvimento no Windows

Leia em 13 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, dentre muitas outras opções. 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[1]. Todo mundo que já tentou desenvolver com Ruby/Rails no Windows sabe o quão lento ele é. Não é um pouquinho lento. É muuuuuuuuuuito lento. Um dos participantes do curso de Rails que eu dava 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 em seu computador.

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.

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. Quando eu dava 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 fnando/dev-bionic64. Isso pode demorar algum tempo, já que uma imagem com ~524MB precisará ser baixada.

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

Baixe a chave privada de SSH do Vagrant. De volta ao PuTTYgen, clique no botão “Load” e selecione o arquivo que você baixou. Depois, 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 fnando/dev-bionic64.

Criando o arquivo de configuração Vagrantfile

Toda vez que você atualizar a versão do VirtualBox, 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.

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 = 'fnando/dev-bionic64'
  config.vm.network :forwarded_port, guest: 3000, host: 3000
  config.ssh.insert_key = false
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 = 'fnando/dev-bionic64'
  config.ssh.insert_key = false

  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.

Vagrant Cloud

À partir do Vagrant 1.5.0 foi introduzido suporte ao Vagrant Cloud, um serviço de compartilhamento de imagens criado pela própria Hashicorp. A vantagem de utilizar o Vagrant Cloud é que você não precisa adicionar as imagens antes de iniciar um novo Vagrantfile. Basta executar o comando vagrant init especificando qual a imagem que você quer usar; na hora que você for executar o comando vagrant up a imagem será baixada caso ela ainda não exista.

$ vagrant init fnando/dev-bionic64

Lembre-se de adicionar a linha abaixo ao arquivo Vagrantfile; caso contrário, o Vagrant irá substituir a chave pública adicionada por uma gerada especificamente para aquela máquina virtual.

VAGRANTFILE_API_VERSION = '2'

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = 'fnando/dev-bionic64'
  config.ssh.insert_key = false
end

Depois, inicie o servidor com o comando à seguir; caso a imagiem ainda não exista, ela será baixada neste momento.

$ vagrant up --provider virtualbox

No Vagrant Cloud é possível versionar as imagens. Se você quiser atualizar suas imagens locais, execute o comando vagrant box outdated para listar as quais boxes podem ser atualizados e, então, vagrant box update <nome do box>, como em vagrant box update fnando/dev-bionic64.

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 por padrão no Windows (veja a seção “Perguntas Frequentes” para instruções de como habilitar esta funcionalidade). 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 14.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. 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 = 'fnando/dev-bionic64'

  config.vm.provider :virtualbox do |vb|
    vb.customize ['modifyvm', :id, '--memory', '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 = 'fnando/dev-bionic64'

  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 = 'fnando/dev-bionic64'

  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 = 'fnando/dev-bionic64'
  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. No caso do Rails, você deve iniciá-lo como no comando abaixo:

rails server -b 0.0.0.0

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 tem a senha vagrant. No entanto, o usuário vagrant é sudoer com configuração que não exige senha para executar as permissões de administrador. Se você precisar autenticar na máquina virtual manualmente, basta utilizar o username vagrant e a senha vagrant.

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 = 'fnando/dev-bionic64'
  config.vm.network :forwarded_port, guest: 3306, host: 3306    # mysql
  config.ssh.insert_key = false
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 = 'fnando/dev-bionic64'
  config.ssh.insert_key = false
  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 = 'fnando/dev-bionic64'
  config.ssh.insert_key = false
  config.vm.synced_folder '.', '/vagrant', :nfs => true
end

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

VAGRANTFILE_API_VERSION = '2'

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = 'fnando/dev-bionic64'
  config.ssh.insert_key = false

  config.vm.provider :virtualbox do |vb|
    vb.customize [
      'setextradata', :id,
      'VBoxInternal/Devices/ahci/0/LUN#[0]/Config/IgnoreFlush', '1'
    ]
  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.

Estou recebendo a mensagem “warning: Insecure world writable dir”.

O diretório compartilhado do Virtualbox, por algum motivo, define as permissões de arquivos e diretórios como sendo 0777. Ao executar qualquer script Ruby você verá uma mensagem como esta:

$ rails c
/home/vagrant/local/ruby/gems/gems/bundler-1.10.5/lib/bundler/shared_helpers.rb:78: warning: Insecure world writable dir /vagrant/myapp/. in PATH, mode 040777

Para desabilitar esta mensagem, é preciso exportar uma variável de ambiente chamada RUBYOPT. Edite o arquivo ~/.bash/user.rb adicionando a linha abaixo:

export RUBYOPT="-W0"

Reinicie o terminal ou recarregue este arquivo com o comando source ~/.bash/user.rb.

Como fazer para que o comando vagrant ssh funcione?

Por padrão, o comando vagrant ssh não funciona no Windows; você precisa usar o PuTTY para acessar sua máquina virtual. No entanto, é possível fazer com que isso funcione. Instale o Git ativando a opção “Use Git and optional Unix tools from the Windows Command Prompt”.

Instalador do Git - Instalando ferramentas Unix

Não deixe de selecionar também a opção “Checkout as-is, commit as-is”.

Instalador do Git - Selecionando modo de checkout e commit

O console do Windows é muito ruim. Alguma alternativa decente?

O Windows possui algumas alternativas de linha de comando, mas recomendo o ConEmu, que possui suporte para syntax highlighting, temas, abas, dentre outras opções.

ConEmu - Tema Tomorrow

ConEmu - Tema Solarized

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 Ansible, 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.

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