Entenda o vagrant

1. Sobre o Vagrant

O Vagrant é uma ferramenta que permite que criemos rapidamente ambientes virtuais para fazermos testes, desenvolvimento ou provisionmento de ambientes utilizando as soluções de virtualização mais comuns como o Virtualbox e o VMWare, sendo também compatível com os principais provedores cloud como AWS, Rackspace e Digitalocean. Além disto, tem suporte a várias tecnologias de provisionamento como Puppet, Chef, Salt, Ansible e CFEngine, com isto, você já cria e configura o ambiente em um único processo, é realmente mágico.

Outros aspecto bacana é que você tem a portabilidade de criar e recriar esses ambientes em qualquer lugar de forma simples e descomplicada bastando apenas ter a ‘receita mágica’ do vagrant.

2. Entendendo a necessidade

Desde 2010 eu conhecia o vagrant, mas confesso que não havia dado muita bola para o projeto, como eu usava o ganeti na época, para mim era muito prático criar e recriar vms baseadas em templates, no servidor da empresa, não havia a menor necessidade de fazer isso no meu ambiente local (mbp).

Contudo, nos últimos 2 anos tenho trabalhado intensamente com virtualização e implantação de ambientes Puppet, e a construção de módulos em ambiente controlado é muito importante.

Eu vinha sofrendo no OSX tanto com o VirtualBox quanto com o VMWARE Fusion para clonar e reconfigurar VMs sempre que eu tinha que construir um novo módulo ou criar um ambiente para algum treinamento ou palestra.

Era sempre chato no caso do VMWARE clonar (copiando o disco) uma VM, dar boot, corrigir problemas de interface de rede, hostname, dar boot de novo, configurar outras coisas, etc, dar outro boot, era um clico cansativo. No virtualbox idem, apesar de ter o clone a um clique de distância, o que já ajuda, ainda era necessário fazer vários ajustes bem manuais para ter o ambiente do jeito que eu queria, e nem preciso dizer que isso consumia muito, mas muito tempo mesmo, tempo que hoje é precisoso demais para perder com isso, tempo que posso utilizar com minha família por exemplo.

Para resolver esses problemas e mais alguns outros, depois de alguma insistência de alguns amigos, resolvi brincar com o vagrant. Posso dizer que a brincadeira foi longe e os resultados me impressionaram.

3. Instalando Vagrant

A instalação é descomplicada, basta entrar na área de downloads do site e escolher o pacote para o seu sistema operacional. Você vai encontrar pacotes para o CentOS, Ubuntu, Debian, MacOX e Windows. É possível instalar via gem se preferir - sim o vagrant foi escrito em Ruby.

Depois de fazer o dowload acesse a documentação que é bem clara e siga a risca.

Ter o virtualbox instalado é pré-requisito, de preferência a última versão.

3.1 OSX

No meu caso eu peguei o pacote do OSX e instalei com bastante facilidade com alguns cliques.

4. Iniciando o uso do vagrant

Um vez instalado ele está disponível para uso, basta abrir o console e digitar

vagrant

Acompanhe a saída

Usage: vagrant [options] <command> [<args>]

    -v, --version                    Print the version and exit.
    -h, --help                       Print this help.

Common commands:
     box          manages boxes: installation, removal, etc.
     connect      connect to a remotely shared Vagrant environment
     destroy      stops and deletes all traces of the vagrant machine
     halt         stops the vagrant machine
     help         shows the help for a subcommand
     init         initializes a new Vagrant environment by creating a Vagrantfile
     login        log in to Vagrant Cloud
     package      packages a running vagrant environment into a box
     plugin       manages plugins: install, uninstall, update, etc.
     provision    provisions the vagrant machine
     reload       restarts vagrant machine, loads new Vagrantfile configuration
     resume       resume a suspended vagrant machine
     share        share your Vagrant environment with anyone in the world
     ssh          connects to machine via SSH
     ssh-config   outputs OpenSSH valid configuration to connect to the machine
     status       outputs status of the vagrant machine
     suspend      suspends the machine
     up           starts and provisions the vagrant environment

For help on any individual command run `vagrant COMMAND -h`

Additional subcommands are available, but are either more advanced
or not commonly used. To see all subcommands, run the command
`vagrant list-commands`.

4.1 Diretório de trabalho

Eleja um diretório pra trabalhar, no meu caso eu criei um diretório chamado vagrant no diretório home do meu usuário e dentro dele um diretório chamado projects.

mkdir -p ~/vagrant/projects

4.2 Boxes

Ao invés de trabalharmos com templates, o vagrant usa o conceito chamado box, que são imagens de sistemas operacionais pré-configurados que vão servir como base para a construção de nossas vms.

Hoje existe o vagrant cloud que é um repositório de boxes interessante

https://vagrantcloud.com

Além deste, existe um base pública de boxes no site abaixo

http://www.vagrantbox.es

E está é a base de boxes públicas da Puppetlabs

http://puppet-vagrant-boxes.puppetlabs.com
4.2.1 Instalando um box via vagrant cloud

Primeiro procure a box que deseja na cloud

https://vagrantcloud.com/discover/featured

Depois insira a box em seu ambiente vagrant

vagrant box add puppetlabs/centos-6.5-32-puppet

E depois verifique se a box foi adicionada corretamente

vagrant box list

Acompanhe a saída

centos-6.5-32    (virtualbox, 0)

Maravilha, box adicionada e pronta para uso.

4.2.2 Instalando uma box manualmente

Você pode adicionar boxes manualmente, eu particularmente gosto das boxes da puppetlabs por já virem com o puppet pré-configurado

cd /tmp
wget http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-puppet.box

Agora vamos adicionar a box

vagrant box add /tmp/centos-65-x64-virtualbox-puppet.box --name centos6x64pl

E vamos verificar a box

vagrant box list

Acompanhe a saída

centos-6.5-32    (virtualbox, 0)
centos6x64pl     (virtualbox, 0)

Maravilha, adicionamos mais uma box com sucesso.

4.3 Criando a VM

Para criar uma nova VM, vamos basicamente criar um diretório para o projeto e iniciar o projeto.

cd ~/vagrant/projects
mkdir meuprojeto
cd meuprojeto

Depois de criar o diretório precisamos rodar o comando init para criar o arquivo de configuração

vagrant init

Acompanhe a saída

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.

Veja que o vagrant nos disse que criou um arquivo de configuração em nosso diretório, vamos olhar esse arquivo

cat Vagrantfile

Acompanhe a saída

# -*- mode: ruby -*-
# vi: set ft=ruby :

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  # All Vagrant configuration is done here. The most common configuration
  # options are documented and commented below. For a complete reference,
  # please see the online documentation at vagrantup.com.

  # Every Vagrant virtual environment requires a box to build off of.
  config.vm.box = "base"

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  # config.vm.network "private_network", ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"

  # If true, then any SSH connections made will enable agent forwarding.
  # Default value: false
  # config.ssh.forward_agent = true

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  # config.vm.synced_folder "../data", "/vagrant_data"

  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  # config.vm.provider "virtualbox" do |vb|
  #   # Don't boot with headless mode
  #   vb.gui = true
  #
  #   # Use VBoxManage to customize the VM. For example to change memory:
  #   vb.customize ["modifyvm", :id, "--memory", "1024"]
  # end
  #
  # View the documentation for the provider you're using for more
  # information on available options.

  # Enable provisioning with CFEngine. CFEngine Community packages are
  # automatically installed. For example, configure the host as a
  # policy server and optionally a policy file to run:
  #
  # config.vm.provision "cfengine" do |cf|
  #   cf.am_policy_hub = true
  #   # cf.run_file = "motd.cf"
  # end
  #
  # You can also configure and bootstrap a client to an existing
  # policy server:
  #
  # config.vm.provision "cfengine" do |cf|
  #   cf.policy_server_address = "10.0.2.15"
  # end

  # Enable provisioning with Puppet stand alone.  Puppet manifests
  # are contained in a directory path relative to this Vagrantfile.
  # You will need to create the manifests directory and a manifest in
  # the file default.pp in the manifests_path directory.
  #
  # config.vm.provision "puppet" do |puppet|
  #   puppet.manifests_path = "manifests"
  #   puppet.manifest_file  = "site.pp"
  # end

  # Enable provisioning with chef solo, specifying a cookbooks path, roles
  # path, and data_bags path (all relative to this Vagrantfile), and adding
  # some recipes and/or roles.
  #
  # config.vm.provision "chef_solo" do |chef|
  #   chef.cookbooks_path = "../my-recipes/cookbooks"
  #   chef.roles_path = "../my-recipes/roles"
  #   chef.data_bags_path = "../my-recipes/data_bags"
  #   chef.add_recipe "mysql"
  #   chef.add_role "web"
  #
  #   # You may also specify custom JSON attributes:
  #   chef.json = { :mysql_password => "foo" }
  # end

  # Enable provisioning with chef server, specifying the chef server URL,
  # and the path to the validation key (relative to this Vagrantfile).
  #
  # The Opscode Platform uses HTTPS. Substitute your organization for
  # ORGNAME in the URL and validation key.
  #
  # If you have your own Chef Server, use the appropriate URL, which may be
  # HTTP instead of HTTPS depending on your configuration. Also change the
  # validation key to validation.pem.
  #
  # config.vm.provision "chef_client" do |chef|
  #   chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
  #   chef.validation_key_path = "ORGNAME-validator.pem"
  # end
  #
  # If you're using the Opscode platform, your validator client is
  # ORGNAME-validator, replacing ORGNAME with your organization name.
  #
  # If you have your own Chef Server, the default validation client name is
  # chef-validator, unless you changed the configuration.
  #
  #   chef.validation_client_name = "ORGNAME-validator"
end

É bem grande mas é bem simples, vamos retirar os comentários e preparar ele para usar a VM que acabamos de baixar.

# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

		config.vm.hostname = "suavm.seudominio"
		config.vm.box = "centos6x64pl"
		
		config.vm.provider "virtualbox" do |virtualbox|
			virtualbox.customize [ "modifyvm", :id, "--cpus", "1" ]
			virtualbox.customize [ "modifyvm", :id, "--memory", "600" ]
		end
end

Veja como ficou bem mais simples de entender, eu disse no arquivo que vou usar a box centos6x64pl, defini memória e quantidade de processadores, mais nada, no caso dessa box ela já vem com uma interface de rede configurada em modo nat.

4.4 Iniciando a VM

Para iniciar a VM

vagrant up

Agora aguarde ela carregar, a primeira vez ai demorar alguns minutos pois ele vai copiar o BOX para esse projeto, depois passa a ser bem rápido.

vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'centos6x64'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: meuprojeto_default_1399893568659_66343
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 => 2222 (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
    default: Warning: Connection timeout. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Setting hostname...
==> default: Mounting shared folders...
    default: /vagrant => /Users/gutocarvalho/vagrant/projects/

No caso do meu macbookpro core2duo com disco mecanico, a vm levou 1.48 minutos para ser criada, agora vamos entrar nela.

vagrant ssh

E você já está rodando sua vm.

[vagrant@meuprojeto ~]$ ifconfig
eth0      Link encap:Ethernet  Endereço de HW 08:00:27:73:BF:1C
          inet end.: 10.0.2.15  Bcast:10.0.2.255  Masc:255.255.255.0
          endereço inet6: fe80::a00:27ff:fe73:bf1c/64 Escopo:Link
          UP BROADCASTRUNNING MULTICAST  MTU:1500  Métrica:1
          RX packets:448 errors:0 dropped:0 overruns:0 frame:0
          TX packets:348 errors:0 dropped:0 overruns:0 carrier:0
          colisões:0 txqueuelen:1000
          RX bytes:47075 (45.9 KiB)  TX bytes:42215 (41.2 KiB)

lo        Link encap:Loopback Local
          inet end.: 127.0.0.1  Masc:255.0.0.0
          endereço inet6: ::1/128 Escopo:Máquina
          UP LOOPBACKRUNNING  MTU:16436  Métrica:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          colisões:0 txqueuelen:0
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

[vagrant@meuprojeto ~]$ cat /etc/issue
CentOS release 6.5 (Final)
Kernel \r on an \m

[vagrant@meuprojeto ~]$ df -h
Filesystem                    Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root  8,4G  1,1G  6,9G  14% /
tmpfs                         289M     0  289M   0% /dev/shm
/dev/sda1                     485M   34M  426M   8% /boot
/vagrant                      931G  853G   78G  92% /vagrant

[vagrant@meuprojeto ~]$ free -m
             total       used       free     shared    buffers     cached
Mem:           576        109        466          0          9         45
-/+ buffers/cache:         55        521
Swap:          991          0        991

[vagrant@meuprojeto ~]$

Se quiser criar outro ambiente, basta criar outro diretório, iniciar o seu projeto e configurar o Vagrantfile.

4.4 Manipulando a VM

Para iniciar a configuração de uma VM

vagrant init

Para iniciar uma VM

 vagrant up

Para desligar a VM

vagrant halt

Para recarregar uma VM (reboot)

 vagrant reload

Para suspender uma VM

 vagrant suspend

Para fazer resume de uma vm suspensa

 vagrant resume

Para verificar o status de uma VM

 vagrant status

Para acessar sua vm

 vagrant ssh

Para destruir a VM, apagando ela do seu disco

vagrant destroy

Para outros comandos e ajuda

vagrant help

5. Dicas de configuração

Abaixo uma configuração que cria uma máquina virtual baseada no box centos6x84, configura um encaminhamento de portas da porta 80 no guest (vm) para porta 8080 em meu host (osx), isto significa que eu poderei acessar a aplicação da VM como se estivesse rodando localmente na porta 8080.

Outro detalhe legal é que montaremos o diretório /Users/gutocarvalho/Sites do host (osx) dentro da VM no destino /srv/sites, ou seja, meus arquivos podem ficar no meu host, sendo editados pela minha IDE de preferência estarão sendo servidos pelo Apache do meu guest e meus sites serão acessíveis pela porta 8080, sensacionalmente fácil e prático.

Independente do Synced Folder específico que está presente no arquivo, o vagrant por DEFAULT monta na VM a raiz do seu projeto, então se eu colocar um arquivo em /Users/gutocarvalho/vagrant/projects/meuprojeto/arquivo.txt (host) ele estará disponível no guest em /vagrant/arquivo.txt.

Além disto, crio uma segunda interface de rede, em modo rede privada com o endereço IP 192.168.200.20 para comunicação futura com outra máquina.

# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

		config.vm.hostname = "apache.hacklab"
		config.vm.box = "centos6x64"
		config.vm.network "forwarded_port", guest: 80, host: 8080
		config.vm.network "private_network", ip: "192.168.200.20"
		config.vm.synced_folder "/Users/gutocarvalho/vagrant/projects/meuprojeto", "/srv/sites"

		config.vm.provider "virtualbox" do |virtualbox|
			virtualbox.customize [ "modifyvm", :id, "--cpus", "1" ]
			virtualbox.customize [ "modifyvm", :id, "--memory", "600" ]
		end
end

Existem centenas de outros parâmetros que podemos utilizar, acesse a documentação e leia bastante => http://docs.vagrantup.com.

6. Conclusão

Começar a trabalhar com vagrant me possibilitou aumentar radicalmente a minha agilidade na criação, testes e desenvolvimento de qualquer coisa em ambiente virtualizado, é realmente uma ferramenta fantástica e simples, recomendo.

Nos próximos posts eu vou falar sobre configuração de Multi Machines e provisionamento SHELL e PUPPET ;)

Conforme eu for aprendendo vou compartilhando com vocês.

7. Referências