Vagrant

Gerenciamento automatizado de VM
Voltar
Conteúdo disponível

Introdução

Solução de gerenciamento automatizado e construção de laboratórios de máquinas virtuais (VMs), via arquivo único ('Vagrantfile'), descartando todas etapas de interações com SO e suas necessidades, conectado a um Provider (Hypervisor como VirtualBox). Pode ser conectado localmente ou até mesmo em Clouds (AWS, Azure, GCP, Digital Ocean, etc). Utiliza linguagem HCL (Hashicorp Configuration Language), baseada em Ruby. Para a criação de Boxes, recomenda-se o software Packer, ao invés dos Boxes na Vagrant, pois os mesmos tendem a possuir vulnerabilidades. Códigos conforme documentação oficial: Site oficial.

Conceitos

  • Box: Componente com SO definido no início do projeto, juntamente com suas configurações, que terá sua imagem baixada pelo Vagrant na VM. O VagrantUp é o repositório oficial dos Boxes (Vagrant Cloud), também há o Vagrantbox.es, que armazena vários Boxes: Vagrant Cloud, Vagrantbox.es;
  • Host e Guest: Host é o SO que está executando o Vagrant (SO da máquina local). Guest é o SO da VM;
  • Provider: Hypervisor responsável pela virtualização (VirtualBox-default, VMWare, KVM, Docker, Hyper-V);
  • Provisioner: Software orquestrador que irá automatizar as tarefas executadas na VM (Chef, Puppet, Ansible, Salt, arquivos, Shell Script manualmente, etc). Consiste em scripts e arquivos com códigos de automação do processo de criação da VM;
  • Plugins: Extensões do Vagrant, que podem ser baixadas;
  • Synced Folders: Diretórios usados para compartilhar conteúdo entre Host e Guest;
  • Vagrantfile: Arquivo de configuração do Vagrant, onde são definidas configurações da VM, versão do SO, memória, ip, etc;

Comandos básicos


Instalação (Debian): sudo apt install vagrant #Comando 'vagrant version' para verificar instalação, ou 'vagrant -h' para ajuda. Também opção de Download na página oficial.
vagrant init: Gerar novo Vagrantfile baseado em uma Box ('-m' após init especifica criação mínima. '-f' para sobrescrever criação)
vagrant up: Iniciar VM e executadar Provisioner (Subir ambiente. Pode-se relacionar com Provider, como 'vagrant up --provider=vmware_fusion')
vagrant reload: Reiniciar VM
vagrant provision: Executar Provisioner
vagrant halt: Desligar VM (destroy excluir VM)
vagrant suspend: Pausar VM (resume retomar VM)
vagrant ssh: Acessar ssh da VM (Sintaxe: 'vagrant ssh [name|id] [--extra_ssh_args]')
vagrant powershell: Abrir PowerShell de Box que possua suporte
vagrant box list: Listar Boxes
vagrant box add USER/BOX: Somente adicionar Box
vagrant box remove hashicorp/bionic64: Remover Box específico #No caso, removeria o hashicorp/bionic64
vagrant status: Ver status de Box
vagrant global-status: Ver status dos ambientes de Boxes
vagrant port [name|id]: Listar portas disponíveis/abertas das Boxes

Vagrantfile

Estrutura do arquivo Vagrantfile e exemplo passo a passo de sua construção (Comando 'vagrant validate' valida o Vagrantfile):


1.Estrutura básica:
Vagrant.configure("2") do |config|
    Conteúdo aqui
end

2.Boxes: (Executar vagrant up para criar, depois vagrant ssh para acessar)
Vagrant.configure("2") do |config|
    Conteúdo aqui, exemplos abaixo:
    config.vm.box = "ubuntu/xenial64" #Definir Box (SO e versão opcional)
end

3.Provisioner: (Executar vagrant provision para atualizar)
Existem várias possibilidades de Provisioners, como Shell, Ansible, Chef, Docker, Podman, Puppet, Salt, entre outros.
Vagrant.configure("2") do |config|
    config.vm.box = "ubuntu/xenial64"
    config.vm.provision "shell",
    inline: "apt update"
    config.vm.provision "shell", inline:<<-SHELL
        apt install -y apache2
    SHELL
end

4.Especifiar porta de acesso e plugins: (Executar vagrant reload para reiniciar. Após, acessar porta 8080 da VM o apache2)
Podem ser redes privadas ou públicas, incluir hosts personalizados, protocolos personalizados, IP estático, entre outras configurações pormenores.
Vagrant.configure("2") do |config|
    config.vm.box = "ubuntu/xenial64"
    config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
    config.vagrant.plugins = ["vagrant-plugin", "vagrant-other-plugin"]
    config.vm.provision "shell",
    inline: "apt update"
    config.vm.provision "shell", inline:<<-SHELL
        apt install -y apache2
    SHELL
end

Synced Folders

O diretório em que encontra-se o Vagrantfile (Host), e o diretório '/vagrant' (Guest) são sincronizados por padrão. Para testar, crie, na VM, algo dentro do '/vagrant', saia da VM e vá ao diretório do Vagrantfile do Host para verificar se sua criação também encontra-se lá. Pode-se usar tipos personalizados, como NFS, RSync, SMB e via VirtualBox diretamente. Para modificar os padrões, segue linha de código no Vagrantfile:


Vagrant.configure("2") do |config|
    config.vm.synced_folder "src/", "/srv/website" #Diretório Host, diretório Guest
end

Upload:
Enviar arquivos do Host para o Guest
vagrant upload source [destination] [name|id]

Vagrant Cloud

Pode-se interagir com o Vagrant Cloud, hospedando novos Boxes diretamente do mesmo. Para isso, precisa-se cadastro no Vagrant Cloud, conforme links acima. Pode-se interagir, inclusive, usando comandos 'cloud_init' no Vagrantfile. Os comandos abaixo entre colchetes são parâmetros opcionais. Os comandos abaixo possuem outros parâmetros de refinamento, que podem ser acessados na documentação oficial.


Autenticação:
vagrant cloud auth login #Informe dados conforme cadastro Vagrant Cloud. Use 'logout' ao invés de login para fazer logout
vagrant cloud auth login --token ABCD1234 #Mesmo comando, usando token de autenticação (Gerado nas configurações do site Vagrant Cloud)

Gestão de Boxes:
vagrant cloud box create ORGANIZATION/BOX-NAME #Criar Box
vagrant cloud box delete ORGANIZATION/BOX-NAME #Deletar Box
vagrant cloud box show ORGANIZATION/BOX-NAME #Ver Box
vagrant cloud box update ORGANIZATION/BOX-NAME #Editar Box
vagrant cloud search TERMO #Pesquisar no Vagrant Cloud (Exemplo: vagrant cloud search hashicorp --limit 5)

Gestão de Providers:
vagrant cloud provider create ORGANIZATION/BOX-NAME PROVIDER-NAME VERSION [URL] #Criar Provider
vagrant cloud provider delete ORGANIZATION/BOX-NAME PROVIDER-NAME VERSION #Deletar Provider
vagrant cloud provider update ORGANIZATION/BOX-NAME PROVIDER-NAME VERSION [URL] #Editar Provider
vagrant cloud provider upload ORGANIZATION/BOX-NAME PROVIDER-NAME VERSION BOX-FILE #Upload arquivo de Box para Vagrant Cloud
vagrant cloud publish ORGANIZATION/BOX-NAME VERSION PROVIDER-NAME [PROVIDER-FILE] #Publicar no Vagrant Cloud

Gestão de Versões:
vagrant cloud version create ORGANIZATION/BOX-NAME VERSION
vagrant cloud version delete ORGANIZATION/BOX-NAME VERSION
vagrant cloud version release ORGANIZATION/BOX-NAME VERSION
vagrant cloud version revoke ORGANIZATION/BOX-NAME VERSION #Desfazer alteração
vagrant cloud version update ORGANIZATION/BOX-NAME VERSION

Exemplo:
Publicar Box no Vagrant Cloud
vagrant cloud publish briancain/supertest 1.0.0 virtualbox boxes/my/virtualbox.box -d "Descrição aqui" --version-description "Versão 1" --release --short-description "Download me!"

Vagrant Share

Compartilhar ambiente Vagrant, via padrão/http/ssh.


Instalação:
vagrant plugin install vagrant-share

Via HTTP:
vagrant share #Incluir '--https' para casos de HTTPS

Via SSH:
vagrant share --ssh
vagrant share --full #Ver todas portas possíveis para conexão

Conectar:
vagrant connect --ssh NAME #Criará IP estático para conexões

Packages

Após criar o Vagrantfile, pode-se empacotá-lo para futuro compartilhamento, conforme códigos abaixo:


Empacotar Vagrantfile:
vagrant package [name|id]
vagrant package --base idBox #Gerará arquivo 'package.box', que poderá ser aberto com 'vagrant box add nomePacote.box'
vagrant package --vagrantfile Vagrantfile.pkg #Pacote de Vagrantfile

Plugins

Complementos personalizados para Boxes Vagrant


Instalar:
vagrant plugin install <name>
vagrant plugin install /path/to/my-plugin.gem

Desinstalar/Reparar:
vagrant plugin expunge my-plugin #Incluir --reinstall para reinstalar. Incluir --force para remover forçadamente. 
vagrant plugin uninstall <name> [<name2> <name3> ...]

Editar:
vagrant plugin update [<name>]

Listar
vagrant plugin list

Hardware

Pode-se configurar discos, memória, CPUs das Boxes, particionando-os e configurando-os de forma personalizada, via Vagrantfile, conforme trechos de comandos abaixo. Entre os tipos de discos, tem-se 'disk', 'dvd' e 'floppy'. Para remover o disco, precisa-se remover a linha no Vagrantfile e executar 'vagrant reload'. Pode-se relacionar os discos com Providers, como VirtualBox, Hyper-V e VMWare.


Definir discos:
config.vm.disk: disk, name: "backup", size: "10GB"
config.vm.disk: disk, size: "100GB", primary: true
config.vm.disk: dvd, name: "installer", file: "./installer.iso"
config.vm.disk: floppy, name: "cool_files"

Memória (MB), CPUs:
config.vm.provider "virtualbox" do |vb|
    vb.memory = "1024"
    vb.cpus   = "2"
end

Múltiplos Boxes

Criar ambiente com múltiplas máquinas, conforme exemplo abaixo:


Vagrant.configure("2") do |config|
    config.vm.provision "shell", inline: "echo Hello"

    config.vm.define "web" do |web|
        web.vm.box = "apache"
    end

    config.vm.define "db" do |db|
        db.vm.box = "mysql"
    end
end

Acessar:
vagrant ssh apache

Snapshots

Snapshots preservam a VM em determinado estado/condições, assim como seus dados nela.


vagrant snapshot save [vm-name] NAME #Criar Snapshot (Similar: vagrant snapshot push)
vagrant snapshot restore [vm-name] NAME #Restaurar Snapshot (Similar: vagrant snapshot pop)
vagrant snapshot delete [vm-name] NAME #Deletar Snapshot
vagrant snapshot list #Listar Snapshots

Push

Publicar aplicação em determinado servidor. Primeiro, define-se o servidor e suas respectivas configurações, para então executar comando Push, conforme códigos abaixo:


1. Configurar Server:
config.push.define "staging", strategy: "ftp" do |push|
    push.host = "ftp.example.com"
    push.username = "nome"
    push.password = "senha"
end

1.2. Configurar Server Heroku:
config.push.define "heroku" do |push|
    push.app = "my_application"
end

1.3.1. Local (Path Remoto):
config.push.define "local-exec" do |push|
    push.inline = <<-SCRIPT
        scp -r . server:/var/www/website
    SCRIPT
end

1.3.2. Local (Path Local):
config.push.define "local-exec" do |push|
    push.inline = <<-SCRIPT
        cp -r . /var/www/website
    SCRIPT
end

1.4. Via Shell Script:
config.push.define "local-exec" do |push|
    push.script = "my-script.sh"
end

2. Executar Push:
vagrant push staging #Se não especificar o nome acima ('staging') no Vagrantfile, não precisará especificá-lo no comando (Somente vagrant push)

Triggers:

Comandos gatilhos que são ativados/executados após determinadas condições, especificadas no cabeçalho do trecho específico no Vagrantfile, conforme trechos de comandos abaixo. Pode-se especificar o type da Tigger, onde tem-se:

  • 'type: :action': Executa antes/depois de Vagrant Action;
  • 'type: :command': Executar antes/depois de Vagrant Command;
  • 'type: :hook': Executar antes/depois de Vagrant Hook.

Executar comando após 'up':
config.trigger.after :up do |trigger|
    Comandos aqui
end

Outros modelos:
config.trigger.before [:up, :destroy, :halt, :package] do |trigger|
    Comandos aqui
end

config.trigger.after :up, :destroy, :halt, :package do |trigger|
    Comandos aqui
end

Sempre executar:
config.trigger.before :all do |myTrigger|
    myTrigger.name = "Run Trigger"
    myTrigger.info = "Running a before trigger!"
    myTrigger.ignore = [:destroy, :halt]
end

Em escopo Guest:
config.vm.define "ubuntu" do |ubuntu|
    ubuntu.vm.box = "ubuntu"
    ubuntu.trigger.before :destroy do |trigger|
        trigger.warn = "Dumping database to /vagrant/outfile"
        trigger.run_remote = {inline: "pg_dump dbname > /vagrant/outfile"}
    end
end

Inlcuindo type:
config.trigger.after :destroy, type: :command do |t|
    t.warn = "Destroy command completed"
end

Ordem de execução:
Vagrantfile
    global trigger 1
    global trigger 2
    machine defined
        machine trigger 3
    global trigger 4
end

Exemplo prático


1. Criar Vagrantfile:
vagrant init -m ubuntu/bionic64

2. Complementar Vagrantfile com o seguinte código:
$script = <<-EOF
sudo apt-get update
sudo apt-get install -y nginx
EOF

Vagrant.configure("2") do |config|
    config.vm.define "server1" do |server1|
        server1.vm.box = "ubuntu/bionic64"
        server1.memory = "1000"
        server1.cpus = "1"
        server1.vm.network "private_network", ip: "192.168.56.2" #Comando do Provider VirtualBox (Outros Providers trazem comandos diferentes)
        config.vm.provision "shell", inline: $script
    end
    config.vm.define "server2" do |server2|
        server2.vm.box = "centos/7"
        server2.vm.network "private_network", ip: "192.168.56.3"
    end
end

3. Criar Boxes:
vagrant up
vagrant status

4. Acessar máquinas:
vagrant ssh server1
vagrant ssh server1 -c "cat /etc/*release" #Realizar comando na Box via ssh
vagrant ssh server1 -c "ip -c a show enp0s8" #Mostrar IP configurado da máquina Ubuntu
vagrant ssh server2 -c "ip -c a show eth1" #Mostrar IP configurado da máquina CentOS
curl 192.168.56.2 #Acessará nginx da máquina Ubuntu. No Browser da máquina Host, acessar url '192.168.56.2'

Elaborado por Mateus Schwede
ubsocial.github.io