Alisson Machado
07 September 2017

Vagrant - Ambiente de Desenvolvimento Ágil

DevOps tem como objetivo diminuir o Time To Market de um serviço, ou seja, diminuir o máximo possível do tempo em que um código é feito até a entrega e feedback do meu cliente sobre o meu serviço. Para acelerar esse tempo uma série de fatores estão envolvidos, como:  
  • Provisionamento de Ambientes de Desenvolvimento
  • Provisionamento de Infraestrutura
  • Testes
  • Deploy
  • Gerência de Configuração e etc.
A HashiCorp é uma empresa que tem uma suíte de ferramentas que são pensadas em DevOps, mas nem todos sabem como e quando usar essas ferramentas, então vou fazer uma série de posts explicando cada uma delas e como utiliza-las no dia a dia, já fiz um post sobre Vault, mas ele foi com o objetivo de fazer um resumo simples sobre como integra-lo ao SSH, então em breve farei outro usando ele integrado com as ferramentas dessa suíte.   Esse primeiro post será sobre Vagrant, pois tudo começa a partir do desenvolvimento.   O primeiro passo é fazer a instalação do VirtualBox, pois o Vagrant precisa de um provisionador para criar as VMs, ele supor vários provisionadores, mas vou usar o VirtualBox aqui pois é o que eu mais uso no meu dia a dia. https://www.virtualbox.org/wiki/Downloads O segundo passo é fazer o Download e a instalação do Vagrant: https://www.vagrantup.com/downloads.html Nesse momento estou usando uma máquina Windows, então baixei o arquivo .msi e fiz a instalação. Uma vez com o Vagrant já instalado podemos ver os seus subcomandos simplesmente digitando vagrant.
PS C:\Users\alisson\blog\vagrant_post> vagrant
Usage: vagrant [options]  []

    -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
     global-status   outputs status Vagrant environments for this user
     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 HashiCorp's Vagrant Cloud
     package         packages a running vagrant environment into a box
     plugin          manages plugins: install, uninstall, update, etc.
     port            displays information about guest port mappings
     powershell      connects to machine via powershell remoting
     provision       provisions the vagrant machine
     push            deploys code in this environment to a configured destination
     rdp             connects to machine via RDP
     reload          restarts vagrant machine, loads new Vagrantfile configuration
     resume          resume a suspended vagrant machine
     share           share your Vagrant environment with anyone in the world
     snapshot        manages snapshots: saving, restoring, etc.
     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
     validate        validates the Vagrantfile
     version         prints current and latest Vagrant version

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`.
Não vou entrar em detalhes sobre todos os subcomandos, pois o foco não é mostrar tudo que o Vagrant pode fazer, mas sim uma rápida aplicação no dia a dia. Vamos começar vendo o subcomando init.
PS C:\Users\alisson\blog\vagrant_post> 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.
PS C:\Users\alisson\blog\vagrant_post>
Esse comando serve basicamente para criar um arquivo Vagrantfile, esse arquivo contem todas as informações sobre provisionamento da máquina. Agora vamos entender e modificar algumas delas. config.vm.box = "bento/ubuntu-16.04" Esse parâmetro define qual imagem será utilizada ao provisionar a máquina, a imagem utilizada será um ubuntu versão 16.04, a imagem será baixada deste endereço: https://app.vagrantup.com/bento Bento é um projeto que utiliza o packer para criar imagens que podem ser usadas no Vagrant.
config.vm.network "forwarded_port", guest: 5000, host: 8080
Esse parâmetro faz um redirecionamento de uma porta da minha máquina local para dentro da máquina virtual criada pelo vagrant, ou seja, quando eu acessar no navegador http://localhost:8080, a conexão será redirecionada para a porta 80 da máquina virtual criada pelo Vagrant.
config.vm.synced_folder "simple-vault-interface", "/vagrant_data"
Esse parâmetro define um diretório local que será mapeado para dentro da máquina virtual, sendo assim eu posso usar um editor de texto ou uma IDE na minha máquina local e assim que eu salvar os arquivos eles serão atualizados dentro da máquina virtual.
  config.vm.provider "virtualbox" do |vb|
       vb.memory = "1024"
  end
Essa configuração serve para definir quanto de memória você quer usar na sua máquina virtual.
config.vm.provision "shell", inline: <<-SHELL
     apt-get clean
     apt-get update
     apt-get install -y python python-pip python-dev
     pip install -r /vagrant/requirements.txt
     python /vagrant/app.py &
  SHELL
Essa última parte é o provisionamento da VM, nela podemos definir quais comando serão executados quando a máquina virtual for criada, nessa parte estou utilizando o próprio shell script do linux para provisionar, mas pode ser usado chef, puppet, ansible, docker e outros. Então o arquivo Vagrantfile ao final ficou da seguinte maneira:
# -*- 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|

  config.vm.box = "bento/ubuntu-16.04"

  
  config.vm.network "forwarded_port", guest: 5000, host: 8080

  config.vm.synced_folder "./simple-vault-interface", "/vagrant_data"

  config.vm.provider "virtualbox" do |vb|
       vb.memory = "1024"
  end
  
  
  config.vm.provision "shell", inline: <<-SHELL
     apt-get clean
     apt-get update
     apt-get install -y python python-dev python-pip
     pip install -r /vagrant_data/requirements.txt
     python /vagrant_data/app.py &
  SHELL
end

Atualmente o meu diretório de trabalho está assim.
PS C:\Users\alisson\blog\vagrant_post> pwd

Path
----
C:\Users\alisson\blog\vagrant_post


PS C:\Users\alisson\blog\vagrant_post> ls


    Diretório: C:\Users\alisson\blog\vagrant_post


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       07/09/2017     20:23                .vagrant
d-----       07/09/2017     20:31                simple-vault-interface
-a----       07/09/2017     20:16           3081 Vagrantfile


PS C:\Users\alisson\blog\vagrant_post>

Dentro de simple-vault-interface eu tenho os seguintes arquivos:
PS C:\Users\alisson\blog\vagrant_post> ls .\simple-vault-interface\


    Diretório: C:\Users\alisson\blog\vagrant_post\simple-vault-interface


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       07/09/2017     20:42            218 app.py
-a----       07/09/2017     20:41              5 requirements.txt
Conteúdo do app.py
#!/usr/bin/python

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Simple Vault Interface"

if __name__ == '__main__':
    app.run(debug=True,host="0.0.0.0",port=5000)
Conteúdo de requirements.txt
flask
Agora estamos prontos para fazer o provisionamento da máquina, lembrando que o Vagrantfile pode e deve ser mudado caso você precise fazer alterações no ambiente. No console digite o seguinte comando vagrant up:
PS C:\Users\alisson\blog\vagrant_post> vagrant up

Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'bento/ubuntu-16.04'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'bento/ubuntu-16.04' is up to date...
==> default: Setting the name of the VM: vagrant_post_default_1504827954112_31424
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 5000 (guest) => 8080 (host) (adapter 1)
    default: 22 (guest) => 2222 (host) (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:
    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!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
    default: /vagrant => C:/Users/alisson/blog/vagrant_post
    default: /vagrant_data => C:/Users/alisson/blog/vagrant_post/simple-vault-interface
==> default: Running provisioner: shell...
    default: Running: inline script
Todo o provisionamento da VM será mostrado no console e você pode acompanhar. Caso tudo ocorra com sucesso se você acessar no navegador, http://localhost:8080 terá uma aplicação respondendo nessa porta, no entanto essa aplicação dentro da VM roda na porta 5000, esse redirecionamento foi feito dentro do Vagrantfile. Caso dê algum problema, você pode digitar os seguintes comandos:
vagrant halt
vagrant up --provision
O subcomando halt, envia um sinal de desligamento para a máquina virtual, já o subcomando up liga a vm e provisiona, no entando se ela já tiver sido provisionada anteriormente ele não irá rodar os comandos de novo, para forçar é necessário usar o parâmetro --provision. Uma vez com tudo funcionando você pode tentar modificar a aplicação e dar um atualizar no navegador que você verá que ela é atualizada automaticamente devido a sincronização de pastas que fizemos no Vagrantfile. Caso você queira entrar na VM, é necessário digitar a instrução vagrant ssh:
PS C:\Users\alisson\blog\vagrant_post> vagrant ssh
Welcome to Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-92-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

7 packages can be updated.
1 update is a security update.


Last login: Fri Sep  8 00:12:30 2017 from 10.0.2.2
vagrant@vagrant:~$

Lembrando que todos os comandos devem ser executados dentro da pasta onde está o Vagrantfile. Caso você não precise mais da VM, ou queira fazer a criação dela a partir da imagem, deve-se digitar a a instrução vagrant destroy.
PS C:\Users\alisson\blog\vagrant_post> vagrant destroy
    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...
PS C:\Users\alisson\blog\vagrant_post>
As boxes usadas no Vagrant, são baixadas automaticamente ao provisionar um ambiente, no entanto existe a instrução vagrant box add, que pode ser utilizada para baixar uma nova imagem.
PS C:\Users\alisson\blog\vagrant_post> vagrant box add bento/centos-7
==> box: Loading metadata for box 'bento/centos-7'
    box: URL: https://vagrantcloud.com/bento/centos-7
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) parallels
2) virtualbox
3) vmware_desktop

Enter your choice: 2
==> box: Adding box 'bento/centos-7' (v201708.22.0) for provider: virtualbox
Para ver as boxes que você já baixou existe a instrução vagrant box list.
PS C:\Users\alisson\blog\vagrant_post> vagrant box list
bento/centos-7     (virtualbox, 201708.22.0)
bento/ubuntu-16.04 (virtualbox, 201708.22.0)
ubuntu/xenial64    (virtualbox, 20170830.1.1)
Caso queira remover uma box utilize a instrução vagrant box remove. Bom, acho que o básico para iniciar com Vagrant e as ferramentas da Hashicorp é esse, eu mapeei o projeto simple-vault-interface dentro da VM, pois é um projeto que pretendo construir e fazer o deploy utilizando toda a suíte da Hashicorp. Então no final teremos uma interface para criar chaves no Vault, uma infraestrutura criada na AWS utilizando o Terraform, uma imagem da aplicação criada pelo Packer e a aplicação executará em Docker também e será feito o deploy dela utilizando o Nomad.