Vagrant
Introdução
O Vagrant é uma ferramenta open source usada para trabalharmos com máquinas virtuais, simulando ambientes totalmente virtuais. Sua ferramenta de linha de comando é muito simples e fácil de usar ao mesmo tempo que é uma ferramenta muito poderosa para prover sistemas virtualizados numa velocidade impressionante, podendo disponibilizar uma máquina virtual pronta para uso em menos de 20 segundos (depende bastante da Internet para baixar as imagens).
Cada máquina virtual possue um arquivo chamado Vagrantfile
e nele é inserido algumas informações do sistema, como a quantidade de memória RAM, a quantidade de CPUs, o sistemas de provisionamento dentre outras informações.
Hypervisor
Um Hipervisor é um software ou hardware (servidores dedicados) usado para criar e rodar máquinas virtuais. Esse sistemas isola o sistema operacional do hipervisor (conhecido como Sistemas Operacional hospedeiro) e os recursos das máquinas virtuais e permite a criação e o gerenciamento dessas máquinas virtuais (conhecidas como convidadas).
Tipos de hipervisores
Há dois tipos de hipervisores que podem ser usados para a virtualização: são o tipo 1 e o tipo 2.
Tipo 1
É comumente conhecido como
hipervisor nativo
ou até mesmobare-metal
, ele é executado diretamente no hardware do host para gerenciar sistemas operacionais guest. Ele ocupa o lugar de um sistema operacional host, e os recursos da máquina virtual são programados diretamente no hardware pelo hipervisor.O Sistemas Operacional nesse caso é o próprio Hypervisor.
Este tipo de Hypervisor é mais comum em datacenters pois o hardware precisa ser bastante robusto, o que é mais encontrado em servidores (quanto mais robusto mais caro será o hardware).
Tipo 2
É denominado
hosted
e é executado em um Sistema Operacional convencional, tendo uma camada de software ou aplicação para gerenciar tanto o hypervisor quanto as máquina virtuais.Normalmente o gerenciamento do Hypervisor em sí é bastante tranquilo, sendo feita a instalaçao, configurações necessária e desse ponto em diante, todo o gerenciamento mesmo é feito em cima das máquinas virtuais somente, já que a base (hypervisor) já está solidificada no Sistema Operacional.
Esse tipo de hipervisor é mais usado por usuários individuais que desejam executar vários sistemas operacionais em um computador pessoal para fins de testes/aprendizado, mesmo que ainda seja possível encontrar esse tipo em pequenas empresas.
Alguns dos Hypervisores mais usados
Os hipervisores mais comuns do mercado para Linux são:
Xen
O Xen é um hipervisor Tipo 1 de software livre, o que significa que não depende de um sistema operacional subjacente para funcionar.
KVM
O Kernel Virtual Machine é um módulo do kernel Linux para virtualização. O KVM é um hipervisor híbrido que significa que ele é um hipervisor do Tipo 1 e do Tipo 2, embora precise de um sistema operacional Linux genérico para funcionar, é capaz de funcionar como um hipervisor perfeitamente bem, integrando-se a uma instalação do Linux em execução. As máquinas virtuais implantadas com KVM usam o daemon
libvirt
e utilitários de software associados para serem criados e gerenciados.VirtualBox
Um aplicativo de desktop popular que facilita a criação e o gerenciamento de máquinas virtuais. O Oracle VM VirtualBox é multiplataforma e funcionará em Linux, macOS e Microsoft Windows. Como o VirtualBox requer um sistema operacional subjacente para ser executado, ele é um hipervisor Tipo 2.
Instalação do Hypervisor
Como foi mostrado anteriormente é necessário escolher um Hypervisor para prover as máquinas virtuais, no meu caso vou escolher o KVM por oferecer um melhor desempenho com as máquinas virtuais e por ser mais fácil de gerenciar (sim, é mais fácil e mais performático).
Vou deixar aqui um [link para instalar o KVM com um gerenciador de interface gráfica](https://www.tecmint.com/install-kvm-on-ubuntu/).
Instalação do Vagrant
Agora vamos fazer a instalação do Vagrant para usarmos com o nosso Hypervisor, você pode fazer a instalação do vagrant usando este link.
Por padrão o Vagrant já está disponível no repositório do Ubuntu, mas você pode usar o repositório oficial se preferir.
# Caso queira usar do repositório, instale usando o comando abaixo:
$ sudo apt install vagrant -y
# Agora instale o plugin para usar com o libvirt:
$ sudo vagrant plugin install vagrant-libvirt
Vale ressaltar que isso é mínimo do mínimo para fazer funcionar, para ter um ambiente completo, recomendo que veja aqui para instalar outras dependências para que possa ter um ambiente mais completo.
Baixando nossa primeira Box
O termo Box é utilizado apenas no ambiente do Vagrant, uma Box é basicamente uma imagem que o hypervisor vai usar para criar a máquina virtual, tendo isso em mente, vamos baixar uma box. Antes de fazer isso, é necessário que você acesse o site Vagrant Cloud e escolha qual box você deseja.
Por padrão a opção Provider está selecionada para any (qualquer uma "imagem"), nesse caso pode notar que as imagens que aparecem são compatíveis com diversos formatos, como estamos usando KVM (libvirt), seleciona o Provider para ser apenas libvirt assim somente imagens compátiveis com ele irão ser apresentadas.
Para nosso exemplo vou desmontrar com o uso da imagem do Ubuntu 2004. Existe duas formas de obter uma imagem, são elas:
Apenas baixar a Box
Nesse caso vamos apenas adicionar a box ao nosso sistemas para que possamos utilizá-la posteriormente, isso implica em fazer o download da box apenas. Caso você já tenha a imagem no sistema mas exista uma versão mais nova dessa imagem, ela será atualizada.
# Baixando a Box do Ubuntu 20.04 disponível pelo usuário "Generic":
$ vagrant box add generic/ubuntu2004
==> box: Loading metadata for box 'generic/ubuntu2004'
box: URL: https://vagrantcloud.com/generic/ubuntu2004
This box can work with multiple providers! The providers that it
can work with are listed below. Please review the list and choose
the provider you will be working with.
1) hyperv
2) libvirt
3) parallels
4) virtualbox
5) vmware_desktop
Enter your choice: 2
==> box: Loading metadata for box 'generic/ubuntu2004'
box: URL: https://vagrantcloud.com/generic/ubuntu2004
==> box: Adding box 'generic/ubuntu2004' (v4.0.2) for provider: libvirt
box: Downloading: https://vagrantcloud.com/generic/boxes/ubuntu2004/versions/4.0.2/providers/libvirt.box
box: Download redirected to host: vagrantcloud-files-production.s3-accelerate.amazonaws.com
box: Calculating and comparing box checksum...
==> box: Successfully added box 'generic/ubuntu2004' (v4.0.2) for 'libvirt'!Uma variação dessa comando também pode ser usada para fornecer o provider:
vagrant box add generic/ubuntu2004 --provider=libvirt
Agora podemos verificar as nossas boxes:
$ vagrant box list
DIGITALR00TS/ubuntu1404 (libvirt, 0.1.0)
centos/8 (libvirt, 2011.0)
generic/centos7 (libvirt, 4.0.2)
generic/centos8 (libvirt, 3.6.4)
generic/debian11 (libvirt, 3.4.2)
generic/freebsd13 (libvirt, 3.3.4)
generic/rocky8 (libvirt, 3.6.14)
generic/ubuntu1604 (libvirt, 3.4.2)
generic/ubuntu2004 (libvirt, 3.2.14)
generic/ubuntu2004 (libvirt, 4.0.2)
generic/ubuntu2104 (libvirt, 3.3.2)
# Perceba que no comando para adicionar é baixado a versão '4.0.2',
# sendo que eu já tinha a versão '3.2.14'.Baixar e inicializar a Box
Este na verdade é um método usado para iniciar uma box, caso você tenha a box a máquina virtual será iniciada, mas caso não tenha, será feito o download da box antes de iniciar a VM.
$ vagrant up --provider=libvirt
Gerenciando as Boxes
Como deve imaginar, é muito importante saber como gerenciar as nossas boxes via Cli, é a partir de uma box que uma VM é criada, por padrão, ao adicionar uma nova Box ao seu sistema ela ficará disponível apenas para você e será armazenada em ~/.vagrant
, com isso em mente, vamos ver alguns comandos úteis.
Comando | Descrição |
---|---|
vagrant box list | Lista as Boxes que temos no sistema. |
vagrant box outdated --global | Verifica em todas as Boxes quais estão atualizadas e quais não estão. |
vagrant box prune | Remove todas as versões de Boxes antigas (pergunta antes de remover). |
vagrant box update --box BOXNAME | Esse comando vai atualizar um Box para uma versão mais recente sem perder os dados da VM ou apagar ela. |
vagrant box remove BOXNAME | Remove a imagem de uma Box. |
Agora vamos ver alguns comandos na prática:
# Listando as boxes do sistema:
$ vagrant box list
DIGITALR00TS/ubuntu1404 (libvirt, 0.1.0)
centos/8 (libvirt, 2011.0)
generic/centos7 (libvirt, 4.0.2)
generic/centos8 (libvirt, 3.6.4)
generic/debian11 (libvirt, 3.4.2)
generic/freebsd13 (libvirt, 3.3.4)
generic/rocky8 (libvirt, 3.6.14)
generic/ubuntu1604 (libvirt, 3.4.2)
generic/ubuntu2004 (libvirt, 3.2.14)
generic/ubuntu2004 (libvirt, 4.0.2)
generic/ubuntu2104 (libvirt, 3.3.2)
# Verificar quais boxes estão desatualizadas:
$ vagrant box outdated --global
.
.
.
method `load_metadata' is defined here
* 'generic/ubuntu2104' for 'libvirt' is outdated! Current: 3.3.2. Latest: 4.0.2
* 'generic/ubuntu2004' for 'libvirt' (v4.0.2) is up to date
* 'generic/ubuntu2004' for 'libvirt' is outdated! Current: 3.2.14. Latest: 4.0.2
* 'generic/ubuntu1604' for 'libvirt' is outdated! Current: 3.4.2. Latest: 4.0.2
* 'generic/rocky8' for 'libvirt' is outdated! Current: 3.6.14. Latest: 4.0.2
* 'generic/freebsd13' for 'libvirt' is outdated! Current: 3.3.4. Latest: 4.0.2
* 'generic/debian11' for 'libvirt' is outdated! Current: 3.4.2. Latest: 4.0.2
* 'generic/centos8' for 'libvirt' is outdated! Current: 3.6.4. Latest: 4.0.2
* 'generic/centos7' for 'libvirt' (v4.0.2) is up to date
* 'centos/8' for 'libvirt' (v2011.0) is up to date
* 'DIGITALR00TS/ubuntu1404' for 'libvirt' (v0.1.0) is up to date
# Vamos remover a box 'centos/8':
vagrant box remove centos/8
Removing box 'centos/8' (v2011.0) with provider 'libvirt'...
Vagrant-libvirt plugin removed box only from you LOCAL ~/.vagrant/boxes directory
From libvirt storage pool you have to delete image manually(virsh, virt-manager or by any other tool)
# Removendo uma versão específica:
$ vagrant box remove generic/ubuntu2004 --box-version 4.0.2
Removing box 'generic/ubuntu2004' (v4.0.2) with provider 'libvirt'...
Vagrant-libvirt plugin removed box only from you LOCAL ~/.vagrant/boxes directory
From libvirt storage pool you have to delete image manually(virsh, virt-manager or by any other tool)
## Atualizar a imagem de uma box, como vimos você precisa usar uma flag,
## a menos que esteja dentro da pasta onde exista um Vagrantfile:
# Entre na pasta da VM:
$ cd /home/bsilva/vagrant/teste
# Atualize a box:
$ vagrant box update --force
==> default: Checking for updates to 'generic/ubuntu2004'
default: Latest installed version: 3.2.14
default: Version constraints:
default: Provider: libvirt
==> default: Updating 'generic/ubuntu2004' with provider 'libvirt' from version
==> default: '3.2.14' to '4.0.2'...
==> default: Loading metadata for box 'https://vagrantcloud.com/generic/ubuntu2004'
==> default: Adding box 'generic/ubuntu2004' (v4.0.2) for provider: libvirt
default: Downloading: https://vagrantcloud.com/generic/boxes/ubuntu2004/versions/4.0.2/providers/libvirt.box
default: Download redirected to host: vagrantcloud-files-production.s3-accelerate.amazonaws.com
default: Calculating and comparing box checksum...
==> default: Successfully added box 'generic/ubuntu2004' (v4.0.2) for 'libvirt'!
Vagrantfile
A principal função do Vagrantfile é descrever o tipo de máquina vamos usar no projeto e como configurar/provisionar a(s) máquina(s), cada VM deve possuir seu próprio Vagrantfile e ele será "controlado" usando uma versão (a versão da Box).
Quando rodamos qualquer comando vagrant
o Vagrant vai procurar na árvore de diretório pelo primeiro Vagrantfile que ele encontrar, sempre iniciando a busca pelo diretório corrente. Para simplificar, imaginamos que você rode um comando do Vagrant dentro de /home/fulano/projetos/ansible/foo
, caso ele não encontre o Vagrantfile nesse diretório, o sistema procuraria por esse arquivo seguindo a árvore de diretórios abaixo:
/home/fulano/projetos/ansible/foo/Vagrantfile
/home/fulano/projetos/ansible/Vagrantfile
/home/fulano/projetos/Vagrantfile
/home/fulano/Vagrantfile
/home/Vagrantfile
/Vagrantfile
Você pode mudar esse ponto de partida (onde o Vagrant procura por um Vagrantfile) configurando uma variável chamada
VAGRANT_CWD
para outro caminho que deseje começa a procura do arquivo.
O Vagrant possui uma maneira de carregar o arquivo Vagrantfile, na verdade não é apenas um arquivo que será carregado, serão vários Vagrantfiles a medida que o sistemas percorre todo o caminho necessário, sempre mesclando as configurações de um Vagrantfile com os outros à medida que vai avançando.
Obtendo um Vagrantfile padrão
O Vagrantfile do projeto é nos fornecido assim que iniciamos o diretório, esse arquivo é fornecido como default para o projeto da Box que vamos usar, ele inicialmente é apenas um arquivo com poucas configurações que vão dizer o que eu desejo dessa VM.
# Vamos criar um diretório para nosso projeto:
$ mkdir -p ~/var-project/ubuntu2004_test
# Entre no diretório:
$ cd ~/var-project/ubuntu2004_test
# Agora, vamos escolher qual box usar nesse projeto, como o nome sugere será o Ubuntu:
$ vagrant box list | grep 'ubuntu2004'
generic/ubuntu2004 (libvirt, 3.2.14)
generic/ubuntu2004 (libvirt, 4.0.2)
## Vamos usar a versão mais recente!
# Por fim inicie o projeto:
$ vagrant init generic/ubuntu2004 --box-version 4.0.2
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.
Agora podemos verificar que no diretório atual (do nosso projeto) já temos o Vagrantfile padrão, e nele possui algumas configurações que a nossa vm vai usar:
$ ls -l
total 4
-rw-rw-r-- 1 fulano fulano 3059 jun 7 11:28 Vagrantfile
# Vamos ver o que tem dentro desse arquivo:
$ grep -vE '^.*#|^$' Vagrantfile
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
end
Como podemos ver, basicamente temos o início da configuração que é Vagrant.configure("2")
, isso informa que a configuração usada desse ponto em diante está na versão 2 (a versão 1 está legada e pode não funcionar) e depois nós temos o nome da box que vamos usar (config.vm.box
) e a versão dessa box (config.vm.box_version
).
Agora para iniciar realmente a VM podemos rodar o comando abaixo:
$ vagrant up
Bringing machine 'default' up with 'libvirt' provider...
==> default: Checking if box 'generic/ubuntu2004' version '4.0.2' is up to date...
==> default: Uploading base box image as volume into libvirt storage...
==> default: Creating image (snapshot of base box volume).
==> default: Creating domain with the following settings...
==> default: -- Name: teste1_default
==> default: -- Domain type: kvm
==> default: -- Cpus: 2
==> default: -- Feature: acpi
==> default: -- Feature: apic
==> default: -- Feature: pae
==> default: -- Memory: 2048M
==> default: -- Management MAC:
==> default: -- Loader:
==> default: -- Nvram:
==> default: -- Base box: generic/ubuntu2004
==> default: -- Storage pool: default
==> default: -- Image: /var/lib/libvirt/images/teste1_default.img (128G)
==> default: -- Volume Cache: default
==> default: -- Kernel:
==> default: -- Initrd:
==> default: -- Graphics Type: vnc
==> default: -- Graphics Port: -1
==> default: -- Graphics IP: 127.0.0.1
==> default: -- Graphics Password: Not defined
==> default: -- Video Type: cirrus
==> default: -- Video VRAM: 256
==> default: -- Sound Type:
==> default: -- Keymap: en-us
==> default: -- TPM Path:
==> default: -- INPUT: type=mouse, bus=ps2
==> default: Creating shared folders metadata...
==> default: Starting domain.
==> default: Waiting for domain to get an IP address...
==> default: Waiting for SSH to become available...
default:
default: Vagrant insecure key detected. Vagrant will automatically replace
default: this with a newly generated keypair for better security.
default:
default: Inserting generated public key within guest...
default: Removing insecure key from the guest if it's present...
default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Configuring and enabling network interfaces...
# Com a VM criada, podemos conectar nela:
$ vagrant ssh
O Vagrant após instalar o sistema cria uma chave ssh privada e uma pública, durante o comando vagrant ssh
ele usa essas chaves para fazer a conexão com a VM.
Criando um Vagrantfile básico
Vamos agora criar uma Vagrantfile do zero mas bem simples para começar a entender a estrutura desse arquivo.
Primeiro crie uma pasta para armazenar esse arquivo!
# Conteúdo de Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.hostname = "vfile"
config.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 2
kvm.default_prefix = "Vagrantfile_Test"
end
# Definindo o nome da VM (nome reconhecido apenas pelo Vagrant)
config.vm.define :Ubuntu_Test do |name|
end
end
Note que o kvm
em config.vm.provider "libvirt" do |kvm|
é apenas uma nome, você pode definir qualquer outro nome aqui, só precisa alterar também na declaração da configuração.
Sempre que criamos uma VM assim, existem dois nomes para trabalharmos, um deles é o nome da VM reconhecido apenas pelo Vagrant, esse nome normalmente é default
. O outro nome é conhecido pelo Hypervisor, só que nesse caso, ele junta o nome conhecido pelo Hypervisor com o nome reconhecido apenas pelo Vagrant.
Imagine que você por padrão tenha criado uma VM chamada Ubuntu-teste
usando apenas o default_prefix=Ubuntu-teste
, quando a VM for iniciada usando o comando vagrant up
, a VM será nomeada como sendo Ubuntu-teste_default
.
default
É o nome da VM reconhecido apenas pelo Vagrant.
Ubuntu-test_default
É o nome da VM reconhecido pelo Hyervisor, ele junta o nome que fornecemos ao nome fornecido pelo Vagrant.
Por isso é bom declarar bons nomes, para que sempre saiba do que se trata essa VM, não importa por onde esteja vendo.
Agora vamos iniciar nossa VM:
$ vagrant up
Bringing machine 'Ubuntu_Test' up with 'libvirt' provider...
==> Ubuntu_Test: Checking if box 'generic/ubuntu2004' version '4.0.2' is up to date...
==> Ubuntu_Test: Creating image (snapshot of base box volume).
==> Ubuntu_Test: Creating domain with the following settings...
==> Ubuntu_Test: -- Name: Vagrantfile_Test_Ubuntu_Test
==> Ubuntu_Test: -- Domain type: kvm
==> Ubuntu_Test: -- Cpus: 2
==> Ubuntu_Test: -- Feature: acpi
==> Ubuntu_Test: -- Feature: apic
==> Ubuntu_Test: -- Feature: pae
==> Ubuntu_Test: -- Memory: 1024M
==> Ubuntu_Test: -- Management MAC:
==> Ubuntu_Test: -- Loader:
==> Ubuntu_Test: -- Nvram:
==> Ubuntu_Test: -- Base box: generic/ubuntu2004
==> Ubuntu_Test: -- Storage pool: default
==> Ubuntu_Test: -- Image: /var/lib/libvirt/images/Vagrantfile_Test_Ubuntu_Test.img (128G)
==> Ubuntu_Test: -- Volume Cache: default
==> Ubuntu_Test: -- Kernel:
==> Ubuntu_Test: -- Initrd:
==> Ubuntu_Test: -- Graphics Type: vnc
==> Ubuntu_Test: -- Graphics Port: -1
==> Ubuntu_Test: -- Graphics IP: 127.0.0.1
==> Ubuntu_Test: -- Graphics Password: Not defined
==> Ubuntu_Test: -- Video Type: cirrus
==> Ubuntu_Test: -- Video VRAM: 256
==> Ubuntu_Test: -- Sound Type:
==> Ubuntu_Test: -- Keymap: en-us
==> Ubuntu_Test: -- TPM Path:
==> Ubuntu_Test: -- INPUT: type=mouse, bus=ps2
==> Ubuntu_Test: Creating shared folders metadata...
==> Ubuntu_Test: Starting domain.
==> Ubuntu_Test: Waiting for domain to get an IP address...
==> Ubuntu_Test: Waiting for SSH to become available...
Ubuntu_Test:
Ubuntu_Test: Vagrant insecure key detected. Vagrant will automatically replace
Ubuntu_Test: this with a newly generated keypair for better security.
Ubuntu_Test:
Ubuntu_Test: Inserting generated public key within guest...
Ubuntu_Test: Removing insecure key from the guest if it's present...
Ubuntu_Test: Key inserted! Disconnecting and reconnecting using new SSH key...
==> Ubuntu_Test: Setting hostname...
==> Ubuntu_Test: Configuring and enabling network interfaces...
Agora apenas para exemplificar, vamos ver o nome que o hypervisor reconhece e o nome que o Vagrant reconhece:
# Nome fornecido pelo Hypervisor:
$ virsh list
Id Name State
----------------------------------------------
1 Vagrantfile_Test_Ubuntu_Test running
## Como estou usando o kvm, o comando para ver as VMs é o usado acima,
## o '_Ubuntu_Test' é um prefixo anexado pelo vagrant.
# Agora vamos ver o nome da VM no Vagrant:
$ vagrant status
Current machine states:
Ubuntu_Test running (libvirt)
Provisionamento
O Vagrant fornece um método de instalar softwares, alterar configurações e muito mais durante a inicialização de uma VM, tudo isso ocorre durante o provisionamento da VM após executar o comando vagrant up
.
O maior benefício é poder deixar o ambiente do jeito que deseja ou bem próximo do esperado durante o privisonamento, para, assim que acessar a VM não ter que fazer muitas mudanças. Todo o processo é automático e não requer interação humana e elimina o trabalho repetitivo e manual.
Para este tópico é recomendado o entendimento sobre Linux e Shell Scripts, quanto maior o seu conhecimento, mais poderá tirar proveito do privisionamento no Vagrant.
O provisionamento pode ser usado nas configurações gerais das VMs ou na configuração específica de uma VM, e por padrão só rodará um único comando, mas podemos fazer um bypass para executar múltiplos comandos.
Executando o provisionamento
O provisionamento é fato de criar o ambiente descrito no Vagrantfile usando Boxes, portanto, ele só acontece de fato uma única vez; ao criar o embiente com o comando vagrant up
, se as VMs foram desligadas e estão sendo inicializadas com o mesmo comando o provisionamento não vai acontecer (porque ele já aconteceu), nesse momento só estamos ligando as VMs, não estamos criando o ambiente novamente.
Caso você queira que o sistema do provisionamento seja re-executado (após o ambiente estar criado), basta rodar o comando vagrant up --provision
.
Caso o ambiente esteja rodando poderá usar o comando vagrant provision
para que também seja re-executado. Se quiser reiniciar as VMs e rodar o provisionamento basta usar o comando vagrant reload --provision
.
O contrário também pode ser realizado (não rodar o provisionamento), para isso use a flag
--no-provision
.
Privisionadores
O Vagrant possui alguns provisionadores e cada um possui uma sintaxe e aplicações próprias, por exemplo, temos os provisionadores: Shell, File, Ansible, Chef, Salt, Docker e muitos outros.
Antes de mostrar alguns provisionadores vou mostrar algumas opções que servem para qualquer provisionador, na verdade são opções de provisionamento.
Type
O tipo é a classe de privisionador que será configurado, no caso é
shell
oufile
, falarei sobre cada um mais adiante.before ou after
Quando esse privionamento deve acontecer.
before
Vai ser executado antes do provisionador que informarmos (nosso privisioning terá prioridade).
Os valores válidos são
:each
ou:all
, o que faz com que o provisionador seja executado antes de cada provisionador raiz:each
ou antes de todos os provisionadores:all
.after
Vai ser executado depois do provisionador que informarmos (nosso privisioning será o último).
Os valores válidos são
:each
ou:all
, o que faz com que o provisionador seja executado após cada provisionador raiz:each
ou antes de todos os provisionadores:all
.Além dos dois mencionados acima
:each
e:all
, podemos fornecer o nome de um provisionador para executar depois ou antes dele, um exemplo seria:node.vm.provision "depois", after: "primeiro", type: "shell", inline: <<-SHELL
echo "bar"
echo "foo"
SHELL
node.vm.provision "primeiro", type: "shell", inline: <<-SHELL
echo "bar 1"
echo "foo 1"
SHELLO privisionador
depois
(descrito na linhanode.vm.provision "depois"
) será executado depois que o provisionadorprimeiro
executar com sucesso.
Bypass para rodar um provisionador
É possível configurar um porivisionador para ser executado sempre que dermos um
vagrant up
ouvagrant reload
, para isso temos algumas configurações, são elas:always
Vai rodar sempre que um
vagrant up
ouvagrant reload
for executado.Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: "echo hello",
run: "always"
endnever
Não será executado automaticamente a menos que seja invocado.
Vagrant.configure("2") do |config|
config.vm.provision "bootstrap", type: "shell", run: "never" do |s|
s.inline = "echo hello"
end
endVocê pode chamar ele com o comando
vagrant provision --provision-with bootstrap
.
Provisionador Shell
Usado para fornecer uma maneira de excutar comando na VM ou fazer o upload de um script para ser executado dentro da VM. Vamos ver algumas das opções:
inline
Usada para executar um comando na VM.
Vagrant.configure("2") do |config|
config.vm.provision "shell",
inline: "echo Hello, World"
endPodemos ainda fornecer outros métodos de aplicação para rodar mais de um comando:
$script = <<-SCRIPT
echo I am provisioning...
date > /etc/vagrant_provisioned_at
SCRIPT
Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: $script
endUma variação do modelo acima pode ser vista abaixo também, nesse caso
SCRIPT
é só o delimitador de onde começam e terminam os comandos:Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: <<-SHELL
sudo apt update
sudo apt install -y mariadb-server
SHELL
path
Usado para fornecer o caminho do Shell Script que será enviado para a VM e executado.
Vagrant.configure("2") do |config|
config.vm.provision "shell", path: "script.sh"
endCaso o script esteja remoto isso não será um problema, podemos fornecer a URL:
Vagrant.configure("2") do |config|
config.vm.provision "shell", path: "https://example.com/provisioner.sh"
endAinda é possível fornecer argumentos aos scripts:
Vagrant.configure("2") do |config|
config.vm.provision "shell" do |s|
s.inline = "echo $1"
s.args = "'hello, world!'"
end
end
### Se não quiser usar aspa pode usar um array:
Vagrant.configure("2") do |config|
config.vm.provision "shell" do |s|
s.inline = "echo $1"
s.args = ["hello, world!"]
end
end
Como exemplo vamos criar um Vagrantfile que instale dois pacotes para nós:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.hostname = "vfile"
config.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 2
kvm.default_prefix = "vagrant"
end
config.vm.define :ubuntu do |node|
# Iniciando a parte de provisioning (não precisa de sudo!):
node.vm.provision "shell", inline: <<-SHELL
apt install apache2 -y
apt install mariadb-server -y
SHELL
end
end
Provisionador File
O privisionador File faz o upload de um arquivo ou diretório da máquina hospedeira para a convidada, em outras palavras é usado para enviar coisas para a VM.
Vagrant.configure("2") do |config|
# ... other configuration
config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig"
end
Não use ~/
para o destino a menos que esteja usando o usuário vagrant na máquina hospedeira. Como alternativa você pode fazer:
Vagrant.configure("2") do |config|
# ... other configuration
config.vm.provision "file", source: "~/path/to/host/folder", destination: "$HOME/remote/newfolder"
end
Provisionador Salt
O Vagrant possui um provisionador para o SaltStack, como é uma ferramenta pouco conhecida estou deixando o link para a documentação oficial, mas não vou explicar como usar, vou deixar apenas um Vagrantfile básico que uso para testar.
# Aqui vamos definir configurações gerais, como Box, versão e Rede:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.provider :libvirt do |kvm|
kvm.default_prefix = "lab_salt"
end
# Define 3 máquinas, sendo um master e dois minions:
servers = [
{ :type => "server", :hostname => "saltmaster", :memoria => "2048", :cpu => 1, :IP => "192.168.100.10" },
{ :type => "minion", :hostname => "mv1", :memoria => "1024", :cpu => 1, :mid => "mv1", :IPM => "192.168.100.10", :IP => "192.168.100.11" },
{ :type => "minion", :hostname => "mv2", :memoria => "1024", :cpu => 1, :mid => "mv2", :IPM => "192.168.100.10", :IP => "192.168.100.12" }
]
servers.each do |server|
config.vm.define "#{server[:hostname]}" do |node|
node.vm.hostname = "#{server[:hostname]}"
node.vm.provider :libvirt do |kvm|
kvm.memory = "#{server[:memoria]}"
kvm.cpus = "#{server[:cpu]}"
end
# Configuração para o master (ou para os caso tenha mais de um):
if server[:type] == "minion"
node.vm.network "private_network",
:ip => "#{server[:IP]}",
libvirt__network_name: "Open",
libvirt__dhcp_enabled: false,
libvirt__forward_mode: "none"
node.vm.provision "installsalt", type: :salt do |salt|
salt.install_master = false
salt.install_type = "stable"
salt.minion_id = "#{server[:mid]}"
node.vm.provision "confsaltmi", type: "shell", inline: <<-SHELL
sed -i 's/^#master: salt/master: #{server[:IPM]}/' /etc/salt/minion
systemctl restart salt-minion
SHELL
end
# Configuração para os minions:
elsif server[:type] == "server"
node.vm.network "private_network",
:ip => "#{server[:IP]}",
libvirt__network_name: "Open",
libvirt__dhcp_enabled: false,
libvirt__forward_mode: "none"
node.vm.provision "installsaltmaster", before: "confsaltma", type: :salt do |salt|
salt.install_master = true
salt.no_minion = true
salt.install_type = "stable"
node.vm.provision "confsaltma", before: :all, type: "shell", inline: <<-SHELL
sed -i 's/^#interface: 0.0.0.0/interface: #{server[:IP]}/' /etc/salt/master
systemctl restart salt-master
SHELL
node.vm.provision "acceptminions", after: :each, type: "shell", inline: <<-SHELL
salt-key -y -A
SHELL
end
end
end
end
end
No virsh manager eu criei uma rede para rodar todas as VM do Salt, no qual essa rede não possui DHCP e é usada somente para essa finalidade, com isso estou adicionando uma interface a mais na configuração acima que é
libvirt__network_name: "Salt",
.
Plugin para fazer resize de Disco - VirtualBox
O método disponível para fazer o Resize do disco antes do provisionamento da VM ainda está em fase de teste, enquanto não é lançado oficilamente vamos usar um plugin de terceiro para estar fazendo isso, esse plugin funciona apenas no VirtualBox.
Vou ensinar a instalar e configurar, mas não vou mostrar funcionando porque eu não utilizo VirtualBox!
Vamos começar fazendo a instalação do Plugin e depois vamos ajustar nosso vagranfile para iniciar uma outra VM com o tamanho de disco sendo 20GB.
Se você está com a VM ligada ou não, mas está no diretório do projeto, pode rodar o comando
vagrant destroy
para eliminar essa VM, já que vamos criar outra.
# Instalando o Plugin:
$ vagrant plugin install vagrant-disksize
Installing the 'vagrant-disksize' plugin. This can take a few minutes...
Fetching vagrant-libvirt-0.9.0.gem
Fetching vagrant-disksize-0.1.3.gem
Parsing documentation for vagrant-libvirt-0.9.0
Installing ri documentation for vagrant-libvirt-0.9.0
Parsing documentation for vagrant-disksize-0.1.3
Installing ri documentation for vagrant-disksize-0.1.3
Done installing documentation for vagrant-libvirt, vagrant-disksize after 1 seconds
Installed the plugin 'vagrant-disksize (0.1.3)'!
Agora é só adicionar uma linha ao nosso Vagrantfile, a linha é config.disksize.size = '20GB'
, veja o arquivo completo abaixo:
# Conteúdo de Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.hostname = "vfile"
config.disksize.size = '20GB'
config.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 2
kvm.default_prefix = "Vagrantfile_Test"
end
# Definindo o nome da VM (nome reconhecido apenas pelo Vagrant)
config.vm.define :Ubuntu_Test do |name|
end
end
Gerenciando discos no Libvirt
O tamanho default de um disco usando o provider do Libvirt é de 128GB, até é possível criar um disco com um tamanho maio que o padrão (lembrando que isso depende da Box, a Box do generic normalmente são de 128GB) mas você teria que fazer o resize manual do Disco/File System, e essa informações fica disponível quando usamos a opção machine_virtual_size = 20
(20GB de disco por exemplo).
Caso precise de uma VM com mais de 128GB, ou caso obtenha uma Box com pouco espaço de disco, vou deixar um Vagrantfile abaixo que vem com 180GB de Disco e já faz o Resize do disco no Sistema e após isso faz o resize do File System:
# Conteúdo de Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.hostname = "vfile"
# Faz o Risize no Sistema (linha 1) e depois no File System (linha 2)
config.vm.provision "shell", inline: <<-SHELL
sudo growpart /dev/vda 3
sudo resize2fs /dev/vda3
SHELL
config.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 2
kvm.default_prefix = "Vagrantfile_Test"
# Define o tamanho do disco para 180GB:
kvm.machine_virtual_size = 180
end
# Definindo o nome da VM (nome reconhecido apenas pelo Vagrant)
config.vm.define :Ubuntu_Test do |name|
end
end
Criando mais de um Disco
Para que possamos criar mais de um disco vamos usar a opção storage :file
, vamos ver um exemplo abaixo:
# Conteúdo de Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.hostname = "vfile"
config.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 2
kvm.default_prefix = "Vagrantfile_Test"
kvm.storage :file, :size => '20G'
end
# Definindo o nome da VM (nome reconhecido apenas pelo Vagrant)
config.vm.define :Ubuntu_Test do |name|
end
end
No exemplo acima estamos criando um disco adicional com tamanho de 20GB kvm.storage :file, :size => '20G'
.
Gerenciando VM com Vagrant
Vamos ver como estar gerenciando nossas VMs com o Vagrant, aqui vamos ver alguns dos comandos que mais serão usados no dia a dia.
Comando | Descrição |
---|---|
vagrant status | Mostra as VM, se estão em execução (running), paradas ou outros status. |
vagrant halt | Desliga a VM. |
vagrant up | Inicia a VM caso ela exista, caso não exista irá criar. |
vagrant suspend | Salva o estado atual da máquina e suspende ela. |
vagrant resume | Inicia a VM que foi suspensa anteriormente. |
vagrant reload | Faz um reboot na VM, é o mesmo que rodar vagrant halt e depois vagrant up . |
vagrant destroy | Remove a VM, destrói ela, com isso ela deixa de existir. Para nao ter que responder Y (yes) para destruir a VM, podemos usar o -f para forçar. |
vagrant upload (source) (destination) | Faz o upload de arquivos para a VM (igual o comando SCP , só que mais simples)Exemplo: vagrant upload /tmp/teste.txt /home/vagrant/teste.txt . |
vagrant snapshot list | Lista os snapshots para a VM. |
vagrant snapshot save (nome) | Cria um snaphost para a VM. |
vagrant snapshot restore (nome) | Restaura para o snapshot informado. |
vagrant snapshot delete (nome) | Deleta o snapshot informado. |
vagrant validate (arquivo) | Valida a configuração de um Vagrantfile. |
Gerenciando Redes
Agora vamos ter um overview sobre os tipos de Rede e como configurar elas, são dois tipos, o NAT e o Bridge.
Rede com NAT
Com a rede NAT (mais comum e default na maioria das Boxes) somente a máquina hospedeira terá acesso a VM, é criado uma interface a mais na máquina hospedeira e atribuído um IP dentro do range dessa nova interface. Existem duas formas de pegar o NAT, são elas:
DHCP
Aqui vamos usar o NAT com DHCP, para isso basta usar adicionar a linha
config.vm.network "private_network", type: "dhcp"
, ficando assim dentro do nosso Vagrantfile:# Conteúdo de Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.network "private_network", type: "dhcp"
config.vm.hostname = "vfile"
config.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 2
kvm.default_prefix = "Vagrantfile_Test"
end
# Definindo o nome da VM (nome reconhecido apenas pelo Vagrant)
config.vm.define :Ubuntu_Test do |name|
end
endStatic
Com essa configuração vamos configurar um IP específico, para isso vamos usar a configuração
config.vm.network "private_network", ip: "192.168.50.4"
:# Conteúdo de Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.network "private_network", :ip => "192.168.50.4"
config.vm.hostname = "vfile"
config.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 2
kvm.default_prefix = "Vagrantfile_Test"
end
# Definindo o nome da VM (nome reconhecido apenas pelo Vagrant)
config.vm.define :Ubuntu_Test do |name|
end
end
Rede com Bridge
Agora vamos ver como criar uma Rede para que outras máquinas que não seja a máquina hopedeira possam acessar ela, nesse caso nossa VM ficará acessível para outras máquinas na rede.
A configuração usada para endereço estático é a seguinte:
Vagrant.configure("2") do |config|
config.vm.network :public_network, :bridge => 'enxa44cc8f1a2d9', :dev => 'enxa44cc8f1a2d9', :ip => "192.168.1.202"
end
A configuração usada para endereço dinâmico (DHCP) é a seguinte:
Vagrant.configure("2") do |config|
config.vm.network :public_network, :bridge => 'enxa44cc8f1a2d9', :dev => 'enxa44cc8f1a2d9'
end
Só ressaltar que a escolha da placa de rede a ser usada na opção
enxa44cc8f1a2d9
é a placa de rede da máquina hospedeira.
Vou deixar aqui um Vagrantfile com 4 interfaces de rede, sendo 2 em bridge:
# Conteúdo de Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.hostname = "vfile"
# Cria uma interface em Bridge com DHCP:
config.vm.network :public_network, :bridge => 'enxa44cc8f1a2d9', :dev => 'enxa44cc8f1a2d9'
# Cria uma interface em Bridge com IP estático:
config.vm.network :public_network, :bridge => 'enxa44cc8f1a2d9', :dev => 'enxa44cc8f1a2d9', :ip => "192.168.1.202"
# Cria uma rede privada informando o IP:
config.vm.network "private_network", ip: "192.168.100.10"
config.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 2
kvm.default_prefix = "Vagrantfile_Test"
end
# Definindo o nome da VM (nome reconhecido apenas pelo Vagrant)
config.vm.define :Ubuntu_Test do |name|
end
end
A outra rede é a padrão criada pelo Vagrant (totalizando 4 interfaces).
Exemplo de como criar uma interface de rede na VM usando uma Rede criada no Virsh Manager do KVM:
# Conteúdo de Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.hostname = "vfile"
config.vm.network "private_network",
libvirt__network_name: "Salt",
libvirt__dhcp_enabled: true,
libvirt__forward_mode: "none"
config.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 2
kvm.default_prefix = "Vagrantfile_Test"
end
# Definindo o nome da VM (nome reconhecido apenas pelo Vagrant)
config.vm.define :Ubuntu_Test do |name|
end
end
Nesse caso estamos criando uma interface adicional na Rede Salt que foi criada no Virsh Manager do KVM
libvirt__network_name: "Salt",
.
Múltiplas VMs
Vamos ver como provisionar várias máquinas virtuais usando apenas um único Vagrantfile. Existem várias formas de provisionar mais de uma VM, a mais simples e que mais torna o Vagrantfile grande em questão de linhas é definir as configurações que vão servir a todas as VMs e configurações específicas por VM (chamaremos aqui esse método de configuração detalhada). O outro método seria criar um loop para não repetir configurações que podem ser comuns em cada VM, como nome/interface etc.
Tome como exemplo o Vagrantfile abaixo usando a configuração detalhada:
# Aqui vamos definir configurações gerais, como Box, versão e Rede:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.network :public_network, :bridge => 'enxa44cc8f1a2d9', :dev => 'enxa44cc8f1a2d9'
# Agora vamos definir configurações para as VM que usam o libvirt (todas no nosso caso):
config.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 1
kvm.default_prefix = "Lab1"
end
# Configurações para a VM do webserver:
config.vm.define :apache do |apache|
apache.vm.hostname = "webserver"
end
# Configurações para a VM do cliente:
config.vm.define :client do |client|
client.vm.hostname = "client"
end
end
Para fazero SSH basta rodar o comando
vagrant ssh (nome da VM)
, exemplo:vagrant ssh client
.
Também é possível setar configurações específicas para cada VM:
# Aqui vamos definir configurações gerais, como Box, versão e Rede:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.network :public_network, :bridge => 'enxa44cc8f1a2d9', :dev => 'enxa44cc8f1a2d9'
# Configurações default para qualquer VM com libvirt:
config.vm.provider "libvirt" do |kvm|
kvm.default_prefix = "Lab1"
end
# Configurações para a VM do webserver:
config.vm.define :apache do |apache|
apache.vm.hostname = "webserver"
apache.vm.provider "libvirt" do |kvm|
kvm.memory = "2048"
kvm.cpus = 2
end
end
# Configurações para a VM do cliente:
config.vm.define :client do |client|
client.vm.hostname = "client"
client.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 1
end
end
end
Usando Loop
Vamos ver agora um exemplo de configuração usando loop para provisionar as VMs, como o Vagrantfile é baseado em Ruby, o Loop criado será em Ruby:
# Aqui vamos definir configurações gerais, como Box, versão e Rede:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.network :public_network, :bridge => 'enxa44cc8f1a2d9', :dev => 'enxa44cc8f1a2d9'
# Configurações default para qualquer VM com libvirt:
config.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 1
kvm.default_prefix = "lab2"
end
# Vamos criar duas VMs (1..2 vai de 1 até 2), cria as VMs chamadas 'vm1' e 'vm2'.
(1..2).each do |i|
config.vm.define "vm#{i}" do |lab2|
lab2.vm.hostname = "vm#{i}"
end
end
end
Uma outra forma, além de usar um loop com números, é usar nomes dentro do loop, no caso vamos usar um Array simples:
# Aqui vamos definir configurações gerais, como Box, versão e Rede:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.network :public_network, :bridge => 'enxa44cc8f1a2d9', :dev => 'enxa44cc8f1a2d9'
# Configurações default para qualquer VM com libvirt:
config.vm.provider "libvirt" do |kvm|
kvm.memory = "1024"
kvm.cpus = 1
kvm.default_prefix = "lab2"
end
# Vamos criar duas VMs (vm1 e vm2):
vms_names = ["vm1","vm2"]
vms_names.each do |i|
config.vm.define "#{i}" do |lab2|
lab2.vm.hostname = "#{i}"
end
end
end
Usando IF e ELSE
Vamos ver como usar IF
e ELSE
para construir um provisionamento mais complexo, trabalhando com configurações individuais para cada VM:
# Aqui vamos definir configurações gerais, como Box, versão e Rede:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
# Configurações default para qualquer VM com libvirt:
config.vm.provider :libvirt do |kvm|
kvm.default_prefix = "lab2"
end
# Crio uma lista com dois nomes (duas VMs):
vms_names = ["vm1","vm2"]
vms_names.each do |i|
if "#{i}" == "vm1"
config.vm.define "#{i}" do |node|
node.vm.hostname = "#{i}"
node.vm.provider :libvirt do |kvm|
kvm.memory = "2048"
kvm.cpus = 2
end
end
else
config.vm.define "#{i}" do |node|
node.vm.hostname = "#{i}"
node.vm.provider :libvirt do |kvm|
kvm.memory = "1024"
kvm.cpus = 1
end
end
end
end
end
Como pode ver a configuração fica meio difícil de entender e a chance de cometer algum erro é grande, mas vou deixar para que possa ver como funcionaria com
IF
.
Usando Array
A configuração usando Array na minha opnião é sempre o melhor caminho, deixa o Vagrantfile mais limpo e ainda fornece uma maneira de configurar várias VMs com pouca linha de código, A configuração usada é "básica", porém, é a base para se criar uma configuração mais complexa:
# Aqui vamos definir configurações gerais, como Box, versão e Rede:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
# Configurações default para qualquer VM com libvirt:
config.vm.provider :libvirt do |kvm|
kvm.default_prefix = "lab2"
end
# Array com as informações das VMs:
servers = [
{ :hostname => "apache", :memoria => "2048", :cpu => 1 },
{ :hostname => "sql", :memoria => "1024", :cpu => 1 },
{ :hostname => "client", :memoria => "560", :cpu => 1 }]
# Loop que cria as Vms (criar 3 VMs):
servers.each do |server|
config.vm.define "#{server[:hostname]}" do |node|
node.vm.hostname = "#{server[:hostname]}"
node.vm.provider :libvirt do |kvm|
kvm.memory = "#{server[:memoria]}"
kvm.cpus = "#{server[:cpu]}"
end
end
end
end
Segue uma configuração similar a de cima, porém, aqui vamos instalar aplicações dependendo da VM que vai estar sendo provisionada:
# Aqui vamos definir configurações gerais, como Box, versão e Rede:
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.box_version = "4.0.2"
config.vm.provider :libvirt do |kvm|
kvm.default_prefix = "lab2"
end
servers = [
{ :hostname => "apache", :memoria => "2048", :cpu => 1 },
{ :hostname => "sql", :memoria => "1024", :cpu => 1 },
{ :hostname => "client", :memoria => "560", :cpu => 1 }]
servers.each do |server|
config.vm.define "#{server[:hostname]}" do |node|
node.vm.hostname = "#{server[:hostname]}"
node.vm.provider :libvirt do |kvm|
kvm.memory = "#{server[:memoria]}"
kvm.cpus = "#{server[:cpu]}"
end
end
# Se for a VM do apache, vamos atualizar o repo e instalar o apache2:
if server[:hostname] == "apache"
config.vm.provision "shell", inline: <<-SHELL
sudo apt update
sudo apt install -y apache2
SHELL
# Se for a VM do sql, vamos atualizar o repo e instalar o mariadb-server:
elsif server[:hostname] == "sql"
config.vm.provision "shell", inline: <<-SHELL
sudo apt update
sudo apt install -y mariadb-server
SHELL
end
end
end
Criando nossas próprias Boxes
Agora vamos ver como criar a nossa própria Box que será disponibilizada para outras pessoas acessarem e utilizarem caso elas desejem. Antes de iniciarmos a criação da Box é importante que você já tenha uma conta no Vagrant Cloud, para fazer o download e uso de Box alheias não é necessário, mas para criar uma é requisito mínimo porque vamos precisar enviar nossa Box para o Vagrant Cloud.
O método de criar uma Box a partir de outra é muito simples, você pode seguir os comandos abaixo, o problema é que normalmente não sabemos da procedencia dessas máquinas, não sabemos como elas foram construídas e normalmente para libvirt
é difícil ter imagens de Box que foram upadas pelas mantenedoras do Sistema.
# Dentro do diretório onde está a imagem da VM:
$ sudo vagrant package --output ubuntu_apache.box
# Se quiser começar a usar essa Box, basta adicionar ela ao sistema:
$ vagrant box add --name ubuntu_apache ubuntu_apache.box
# Agora você já pode enviar essa Box para o Vagrant Cloud.
Criando uma Box a partir da ISO usando LIBVIRT
Para criar uma box usando uma ISO, basta usar o Hypervisor de sua escolha, instalar o sistemas a partir da ISO como faria normalmente para usar no dia a dia, só tem alguns requisitos aqui:
Username
O nome de usuário deve obrigatóriamente ser
vagrant
e a senhavagrant
, poderia ser outro, mas como é padronizado esse username e senha, mantenha ele.SSH
Crie a pasta
.ssh
na Home do usuário vagrant com as permissões corretas:$ chmod 700 ~/.ssh
Chaves
Se você quiser que novos usuários possam acessar a VM usando o comando
vagrant ssh
é necessário adicionar o que chamam deInsecure Keys pair
que são as chaves usadas pelo Vagrant para acessar essas máquinas e são inseguras (insecure) porque a chave privada fica diponível aqui.# Baixando a chave publica:
$ curl –O https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub > ~/.ssh/authorized_keys
# Acerte a permissão das chaves:
$ chmod 600 ~/.ssh/*Permissão com
sudo
Quando usamos
sudo
em uma VM com Vagrant não é pedido para digitar a senha, então vamos acertar osudoers
para que possamos usar osudo
sem senha, existem algumas formas de acessar osudoers
, então vou deixar apenas uma delas abaixo:# acessando o 'sudoers':
$ sudo bash -c 'echo "vagrant ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/vagrant'Se existir a opção
requiretty
comente ela adicionando um#
ao começo da linha.SSH
Vamos fazer algumas configurações no SSH, primeiro desative a consulta de DNS reversa:
$ sudo bash -c 'echo " UseDNS no" >> /etc/ssh/ssh_config'
Agora mude algumas configurações do servidor SSH:
# sudo sed -i '/PubkeyAuthentication yes/ s/^#//; /PermitEmptyPasswords no/ s/^#//; s/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
# sudo sed -i "s:#AuthorizedKeysFile.*:AuthorizedKeysFile %h/\.ssh/authorized_keys:" /etc/ssh/sshd_configAcerte algumas configurações
Adicione uma conf para desativar o IPv6 (isso é padrão nas VM do Vagrant):
$ sudo bash -c 'echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf'
Agora vamos acertar a configuração de rede para manter o padrão
ethX
no nome das interfaces, e depois vamos configurar o Netplan (no caso do Ubuntu) para subir com DHCP na interface, assim vamos poder acessar a VM usando comandovagrant ssh
:# Acerte a conf no grub:
$ sudo sed -i 's/^GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"/' /etc/default/grub
# Faça o update do grub para regerar os arquivos:
### Para Redhat:
$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg
### Para padrão Debian:
$ sudo update-grub
# Agora configure o Netplan:
$ sudo rm /etc/netplan/00-installer-config.yaml
$ sudo bash -c "echo 'network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: true
dhcp6: false
optional: true
nameservers:
addresses: [8.8.8.8]' > /etc/netplan/01-netcfg.yaml"
$ sudo bash -c "echo '---
network:
version: 2
renderer: networkd
ethernets: {}' > /etc/netplan/50-vagrant.yaml"Na Redhat você precisa editar o arquivo
/etc/sysconfig/network-scripts/ifcfg-XXX
para configurar a placa de rede com DHCP no Boot. Abaixo segue um exemplo da conf no Centos:$ sudo cat /etc/sysconfig/network-scripts/ifcfg-eth0
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=dhcp
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=eth0
DEVICE=eth0
ONBOOT=yesFinalizando
Após tudo isso vamos salvar todos os arquivos abertos (não é para ter nenhum) e depois desligar a VM.
# Para desligar a VM:
$ sudo shutdown -P now
Obtenha o local de onde está armazenado o disco da VM, normalmente fica em /var/lib/libvirt/images/
e vamos começar a construi nossa Box:
# Crie uma pasta para colocar o disco da VM e outros arquivos:
$ mkdir ubuntu-vag
# Copie o disco da VM para dentro de uma pasta:
$ sudo cp /var/lib/libvirt/images/ubuntu_20.04.qcow2 ubuntu-vag/
# Acerte a permissão do arquivo:
$ sudo chmod 777 ubuntu-vag/ubuntu_20.04.qcow2
Dentro desse diretório vamos criar dois arquivos, um será o metadata.json
e o outro será nosso querido amigo Vagrantfile
.
# Vamos começar com 'metadata.json':
$ vim ubuntu-vag/metadata.json
################ Cole o exemplo abaixo ################
{
"format" : "qcow2",
"provider" : "libvirt",
"virtual_size" : 15
}
#### Como é de costume nas VMs do Vagrant, vou deixar no formato abaixo:
{"format":"qcow2","provider":"libvirt","virtual_size":15}
Como usamos um disco de 15G vamos deixar ele com 15 no virtual size.
Agora vamos criar o vagrantfile
:
# Crie o arquivo Vagrantfile:
$ vim ubuntu-vag/Vagrantfile
################ Cole o exemplo abaixo ################
Vagrant.configure("2") do |config|
config.vm.provider :libvirt do |libvirt|
libvirt.driver = "kvm"
end
end
Vagrant.configure(2) do |config|
config.vm.boot_timeout = 1800
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.box_check_update = true
# config.vm.post_up_message = ""
config.vm.boot_timeout = 1800
# config.vm.box_download_checksum = true
config.vm.boot_timeout = 1800
# config.vm.box_download_checksum_type = "sha256"
config.vm.provider :libvirt do |v, override|
v.disk_bus = "virtio"
v.driver = "kvm"
v.video_vram = 256
v.memory = 1024
v.cpus = 1
end
end
Caso sua imagem esteja no formato
.img
você pode usar o comando abaixo para converter ela paraqcow2
:sudo qemu-img convert -f raw -O qcow2 nome.img nome.qcow2
.
Ainda podemos criar um arquivo de informações:
# Crie o arquivo 'info.json':
$ vim ubuntu-vag/info.json
################ Cole o exemplo abaixo ################
{
"Author": "XXXXXX",
"Website": "XXXXXX",
"Artifacts": "https://vagrantcloud.com/XXXXXX/",
"Description": "XXXXXXXXX"
}
Renomeie o disco para box.img
(a extensão é apenas um nome, o arquivo ainda está no formato qcow2
):
# Entrando na pasta:
$ cd ubuntu-vag
# Renomeando:
mv ubuntu_20.04.qcow2 box.img
Mudamos o nome para box.img porque é o padrão usado pelo Vagrant.
Agora vamos criar a nossa Box:
$ tar cvzf ubuntu_20.04.box ./metadata.json ./info.json ./Vagrantfile ./box.img
Agora podemos adicionar a nossa Box ao Vagrant e daqui em diante o processo é o comum para fazer o upload da Box:
$ vagrant box add --name ubuntu_20.04 ubuntu_20.04.box --provider=libvirt
Backup e Migração
Para fazer backup das VM basta fazer backup do Vagrantfile
que temos, vale lembrar que o Vagrant é construído no modelo de máquina virtual flexível e portátil, ou seja, tudo o que você precisa está dentro do Vagrantfile
, outro detalhe muito importante é fazer backup da pasta .vagrant
que fica no mesmo diretório do Vagrantfile
. Mas quase sempre temos um ambiente ou máquina onde já temos diversas coisas feitas e tudo isso foi feito manualmente e não queremos perder os dados ou o trabalho feito, nesses casos vou ensinar como migrar essas máquinas e manter a compatibilidade com o Vagrant, vale notar que esse processo não existe por padrão, mas é possível fazer.
Comece fazendo backup dos Vagrantfiles
e então faça backup dos volumes (discos das VMs), por padrão eles ficam em /var/lib/libvirt/images/
, se você preferir ou achar mais fácil, pode fazer backup de tudo /var/lib/libvirt/
. No novo sistema basta ter os volumes (discos das VMs), os Vagrantfiles
, o .vagrant
, instalar o plugin do libvirt e se certificar que estão ou na mesma versão ou mais atualizados no sistema novo.
Vou tomar como exemplo a migração de uma vm que tem o Apache2 rodando no CentOS, se simplesmente migrarmos os volumes e os Vagrantfiles
(até mesmo se incluirmos os .vagrant
) vamos ter o erro abaixo:
$ vagrant up
Bringing machine 'default' up with 'libvirt' provider...
==> default: Checking if box 'generic/centos7' version '4.2.2' is up to date...
==> default: A newer version of the box 'generic/centos7' for provider 'libvirt' is
==> default: available! You currently have version '4.2.2'. The latest is version
==> default: '4.2.10'. Run `vagrant box update` to update.
==> default: Creating image (snapshot of base box volume).
Volume for domain is already created. Please run 'vagrant destroy' first.
Esse erro indica que o volume da VM já existe e pede para rodar um comando que além de deletar a VM vai apagar seu disco, perdendo tudo que temos naquele disco, então não faça nada do que é explicado alí.
Vamos ver como resolver esse erro:
# Entre no diretório onde está o 'Vagrantfile' (mude para o diretório correspondente no seu sistema):
$ cd ~/vagrant/apache2_centos
# Como nesse ponto não temos a VM no sistema se procurarmos pelo vol não vamos encontrar:
$ virsh domblklist --domain apache2_centos_default
error: failed to get domain 'apache2_centos_default'
# Tem outro método de encontrar a imagem para o sistema que estamos usando:
$ virsh vol-list default | grep -i apache2_centos
apache2_centos_default.img /var/lib/libvirt/images/apache2_centos_default.img
# Renomeie o volume da VM:
$ sudo mv /var/lib/libvirt/images/apache2_centos_default.img /var/lib/libvirt/images/apache2_centos_default.img-bkp
# Reinicie o daemon do libvirt:
$ sudo systemctl restart libvirtd
$ vagrant up
Bringing machine 'default' up with 'libvirt' provider...
==> default: Checking if box 'generic/centos7' version '4.2.2' is up to date...
==> default: Creating image (snapshot of base box volume).
==> default: Creating domain with the following settings...
...
...
==> default: Machine booted and ready!
# Desligue a VM:
$ vagrant halt
# Apague o disco novo que foi criado:
$ sudo rm /var/lib/libvirt/images/apache2_centos_default.img
# Renomeie o disco antigo para nome que tinha antes:
$ sudo mv /var/lib/libvirt/images/apache2_centos_default.img-bkp /var/lib/libvirt/images/apache2_centos_default.img
## Nesse ponto a VM já pode ser iniciada sem problemas, mas acontece que no sistema da VM,
## temos uma chave ssh diferente da que está dentro do '.vagrant'.
# Copie a chave ssh do backup que fizemos
$ cp /Backup/vagrant/apache2_centos/.vagrant/machines/default/libvirt/private_key .vagrant/machines/default/libvirt/private_key
# Inicie novamente a VM:
$ vagrant up
Bringing machine 'default' up with 'libvirt' provider...
==> default: Checking if box 'generic/centos7' version '4.2.2' is up to date...
==> default: Creating shared folders metadata...
==> default: Starting domain.
==> default: Waiting for domain to get an IP address...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 192.168.121.30:22
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Host unreachable. Retrying...
==> default: Machine booted and ready!
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: flag to force provisioning. Provisioners marked to run always will still run.
Vale notar que existe outro método de migração do KVM exige que você faça backup do XML
do disco virtual para importar de forma mais simples, mas com esse processo o Vagrant faz isso para nós.
Fontes
https://opensource.com/resources/vagrant
https://www.redhat.com/pt-br/topics/virtualization/what-is-a-hypervisor
https://www.sysnetbr.eng.br/docs/Certificacao/LPIC-1/1026/
https://www.vagrantup.com/docs/provisioning
https://www.vagrantup.com/docs/provisioning/shell
https://www.vagrantup.com/docs/provisioning/file
https://www.vagrantup.com/docs/provisioning/salt
https://www.udemy.com/course/vagrant-para-iniciantes
https://ostechnix.com/how-to-use-vagrant-with-libvirt-kvm-provider/
https://www.vagrantup.com/docs/vagrantfile
https://github.com/sprotheroe/vagrant-disksize
https://www.vagrantup.com/docs/disks
https://www.vagrantup.com/docs/provisioning/shell
https://github.com/vagrant-libvirt/vagrant-libvirt#additional-disks
https://www.rubydoc.info/gems/vagrant-libvirt/0.0.31
https://www.rodolfocarvalho.net/blog/resize-disk-vagrant-libvirt/
https://leftasexercise.com/2020/05/15/managing-kvm-virtual-machines-part-i-vagrant-and-libvirt/
https://wiki.libvirt.org/page/VirtualNetworking
https://gitter.im/vagrant-libvirt/vagrant-libvirt?at=5980d0a44bcd78af560590fa
https://www.vagrantup.com/docs/multi-machine
https://github.com/hashicorp/vagrant/issues/11045
https://www.tutorialspoint.com/ruby/ruby_if_else.htm