Provisionando VMs com Vagrant + YAML + Shell Script
Tags: vagrant, yaml, virtualbox, shellscript
Published: 2020-11-19 14:42:47

Heey!

Vagrant é uma ferramenta poderosa para provisonar VMs (Virtual Machine), recentemente comecei a utilizá-la para subir alugns labs e decidi fazer um post de como provisionar e configurar várias máquinas de forma rápida ( e organizada) com o YAML. 

> Antes de tudo, vamos utilizar o Virtual Box como provider, então precisamos dele instalado.

Uma vez que o vagrant está instalado e rodamos o `vagrant init` percebemos que ele cria o `Vagrantfile`. 

```
$ vagrant init

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.

```

É nesse arquivo que a mágica realmente acontece.
![Alt text of image](https://media.giphy.com/media/3o7TKP9ln2Dr6ze6f6/giphy.gif)



###**Comandos básicos e a nossa primeira VM**

Ao abrir o `Vagrantfile` ele estará desta forma:
```
# vim Vagrantfile

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

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
  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.
  # NOTE: This will enable public access to the opened port
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

  # 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"

  # 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|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Enable provisioning with a shell script. Additional provisioners such as
  # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
  # documentation for more information about their specific syntax and use.
  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
end
```

Caso seja sua primeira vez mexendo com o vagrant, você consegue subir um CentOs7 alterando a configuração do box:
```
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
   config.vm.box = "centos/7"
end

```

Uma vez com o `Vagrantfile` configurado, você já consegue verificar o status da vm:
```
$ vagrant status

Current machine states:

default                   not created (virtualbox)

The environment has not yet been created. Run `vagrant up` to
create the environment. If a machine is not created, only the
default provider will be shown. So if a provider is not listed,
then the machine is not created for that environment.
```

Como não definimos nada além do box, ele criou uma maquina com configurações padrões e o nome "default" para iniciá-la basta rodar:

```
$ vagrant up default

Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'centos/7'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'centos/7' version '2004.01' is up to date...
==> default: Setting the name of the VM: devto_default_1605719030819_60986
==> default: Fixed port collision for 22 => 2222. Now on port 2202.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2202 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2202
    default: SSH username: vagrant
    default: SSH auth method: private key
    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: Machine booted and ready!

```

Uma vez que ela está rodando, você já consegue acessá-la:
```
$ vagrant ssh default

Last login: Wed Nov 18 17:13:10 2020 from 10.0.2.2
[vagrant@localhost ~]$ cat /etc/centos-release
CentOS Linux release 7.8.2003 (Core)
[vagrant@localhost ~]$ 

```

Tudo pronto! Com apenas esses passos nós criamos e subimos um VM com CentOS7. O vagrant possui vários tipos de boxes e você pode verificar através do site https://app.vagrantup.com/boxes/search :D

Agora vamos para o que interessa e utilizar o YAML o/

Primeiro vamos destruir a máquina que subimos:
```
$ vagrant destroy default

    default: Are you sure you want to destroy the 'default' VM? [y/N] y
==> default: Forcing shutdown of VM...
==> default: Destroying VM and associated drives...

```

###**ENV.YAML**

Primeiro vamos criar um arquivo YAML onde iremos inserir as informações das nossas máquinas:

> Vou montar pequeno lab com a stack ELG

```
# env.yaml

---
- name: graylog-lab
  box: centos/7
  hostname: graylog.lab
  ipaddress: 192.168.1.101
  memory: 2048
  provision: script/lab.sh

- name: elastic-lab
  box: centos/7
  hostname: elastic.lab
  ipaddress: 192.168.1.102
  memory: 2048
  provision: script/lab.sh

- name: logstash-lab
  box: centos/7
  hostname: logstash.lab
  ipadress: 192.168.1.103
  memory: 1024
  provision: script/lab.sh

```

Basicamente vamos subir 3 máquinas CentOS7 (<3) onde definimos o `name`, `box`, `hostname`, `ipaddress`, `memory` e `provision`. 

#####**Entendendo o campo Provision**

O vagrant disponibiliza provisionadores que permite que você instale pacotes e configure serviços no processo de criação das máquinas (`vagrant up`). Ou seja, você consegue criar as máquinas com uma pré-configuração. Entre os principais provisionadores temos: Shell, Ansible, Docker, Chef.

Esse recurso é muito bom para automatizar alguns processos, o provisionamento só vai acontecer automaticamente no processo de criação das máquinas mas você consegue forçar para que ele seja executado novamente. 

Vou utilizar Shell Script para instalar pacotes que irei precisar em todos os servidores e configurar o arquivo `/etc/hosts` com os DNS do nosso lab.

Ficou desta forma:
```
$ vim script/lab.sh

#!/bin/bash

echo "HEEEEY o/"
echo "Instalando pacotes..."
yum update -y && yum install -y vim java-1.8.0-openjdk-headless.x86_64
echo "Configurando alguns DNS..."
file="/etc/hosts"
( 
 echo "192.168.1.101    graylog.lab"
 echo "192.168.1.102    elastic.lab"
 echo "192.168.1.103    logstash.lab"
) >> $file

```

Bom, criamos o env.yaml e nosso script de provisionamento, agora só falta utilizá-los no nosso `Vagrantfile`.


###**Vagrantfile**

Agora vamos caregar o arquivo env.yaml e configurar nossas máquinas de acordo com as variáveis que inserimos nele:

```
# vim Vagrantfile

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

require 'yaml'

env = YAML.load_file('env.yaml')

Vagrant.configure("2") do |config|

  env.each do |env|
    config.vm.define env['name'] do |host|
      host.vm.box = env['box']
      host.vm.hostname = env['hostname']
      host.vm.network 'public_network', ip: env['ipaddress']
      host.vm.provider 'virtualbox' do |vb|
        vb.name = env['name']
        vb.memory = env['memory']
      end

      host.vm.provision "shell", path: env['provision']
    end
  end
end

```

Com o `Vagrantfile` configurado, vamos verificar se está tudo ok:

```
$ vagrant status

Current machine states:

graylog-lab               not created (virtualbox)
elastic-lab               not created (virtualbox)
logstash-lab              not created (virtualbox)

This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.
```

Você pode subir uma de cada vez `vagrant up graylog` ou apenas rodar `vagrant up` ele vai provisionar todas respectivamente.

Assim que o vagrant termina as configurações das máquinas,ele executa nosso script. Após terminar todo o processo temos 3 máquinas CentOS7 com o vim e java pré-instalados.
```
$ vagrant ssh graylog-lab

[vagrant@graylog ~]$ cat /etc/centos-release
CentOS Linux release 7.9.2009 (Core)
[vagrant@graylog ~]$ java -version
openjdk version "1.8.0_272"
OpenJDK Runtime Environment (build 1.8.0_272-b10)
OpenJDK 64-Bit Server VM (build 25.272-b10, mixed mode)
[vagrant@graylog ~]$ vim -version
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Oct 13 2020 16:13:17)
Garbage after option argument: "-version"
More info with: "vim -h"
[vagrant@graylog ~]$ 
```

Curti bastante essa configuração do Vagrantfile, desta forma, caso for criar outro tipo de lab, apenas é preciso alterar o env.yaml e configurar o script de provisionamento :)

É isso, abs o/