Dê adeus ao “na minha máquina funciona!”

Hora de abandonar o XAMPP/WAMP

O problema

Um dos problemas mais recorrentes no desenvolvimento de software é aplicação apresentar erros após o deploy. “Na minha máquina funciona”, diz o programador.

Quando um código é transferido da máquina do desenvolvedor para um ambiente de homologação ou produção, esta aplicação deveria funcionar exatamente da mesma forma, mas isso nem sempre é uma realidade. Vários são os fatores que influenciam, em especial diferenças entre:

  • Sistemas operacionais
  • Servidor web
  • Versão da linguagem
  • Versão do banco de dados

Um time de devs, cada um na sua máquina, uns com windows, outros linux, alguns como php server built in, outro apache 2.2, outro apache 2.4, PHP 5.6, 7, 7.1 e por aí vai. Em algum momento, alguma biblioteca, alguma atualização da linguagem ou qualquer outra coisa irá mudar o comportamento do código executado, trazendo resultados diferentes.

Para resolver isso, uma das melhores práticas é utilizar o Vagrant. O Vagrant é “uma ferramenta para construir e gerenciar ambientes de máquinas virtuais em fluxo de trabalho único” (https://www.vagrantup.com/intro/index.html — tradução livre).

Vagrant — Development Environments Made Easy

Algumas são as vantagens de se utilizar essa abordagem:

  • Configuração de ambiente única. Todos os desenvolvedores utilizam o mesmo ambiente de desenvolvimento, mesmo SO, web server, versão da linguagem, drivers, bibliotecas, etc;
  • Possibilidade de utilizar o mesmo ambiente de desenvolvimento, homologação e produção;
  • Configuração pode ser versionada e colocada no repositório do projeto, sendo acessível facilmente por todos;
  • Configurar nova máquina de desenvolvimento é extremamente rápido.

Então, vamos deixar a conversa para lá e mãos à obra.

Instalação/Configuração

Primeiramente, vamos precisar habilitar na BIOS a virtualização.

Procure qualquer coisa que esteja escrito como Virtualization Technology, ou algo parecido, e coloque como “Enabled

Feito isso, precisamos instalar um gerenciador de máquina virtual. A sugestão é o VirtualBox (https://www.virtualbox.org), uma vez que é gratuito e roda em Linux, Windows ou Mac. Faça o download da sua versão e instale na sua máquina. Pode ser necessário reiniciar.

Download do VirtualBox

Com o VirtualBox instalado, hora de instalar o Vagrant. Acesse o link https://www.vagrantup.com/downloads.html e baixe e instale de acordo com seu sistema operacional. Pode ser necessário reiniciar.

Passo opcional: Instalar o git, caso ainda não tenha: https://git-scm.com/downloads. O git é uma ferramenta de versionamento de software, e é parte fundamental para quem quer se tornar um desenvolvedor. No caso cito o git aqui pois utilizo o git bash (MINGW). Não irei me aprofundar no git aqui neste tópico.

No Git Bash/Mingw/Powershell/Prompt de Comando, vá até o diretório desejado e inicie uma nova máquina com o comando vagrant init <nome da máquina>.

Neste site https://app.vagrantup.com/boxes/search possui uma série de máquinas virtuais já preparadas. Para fins de exemplo utilizarei o ubuntu xenial64, que é a última versão LTS do ubuntu até o momento.

Criando Vagrantfile

O arquivo Vagrantfile foi criado no diretório. Abra com qualquer editor de texto e vamos editá-lo. O arquivo possui várias linhas comentadas (com #). Para simplificar a visualização, irei remover todos os comentários.

# -*- mode: ruby -*-
# vi: set ft=ruby :Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial64"
end

Perceba a diretiva config.vm.box = "ubuntu/xenial64". Esta é a máquina virtual que iremos subir. O próprio Vagrant cuidará de tudo.

Digite vagrant up. Na primeira execução poderá demorar um pouco para baixar a distro, instalar o OS e os plugins necessários, mas depois o resultado será parecido com a imagem abaixo.

Subindo a máquina virtual via Vagrant

Pronto, temos agora uma máquina virtual com ubuntu xenial64 rodando. Para desligar basta executar o comando vagrant halt.

Para acessá-la, basta digitar o comando vagrant ssh e você estará dentro da máquina. A partir daí, pode-se começar os procedimentos para instalação do PHP, MySQL, Apache, etc, mas existem técnicas melhores para reaproveitar todo esse processo e replicar em todas as máquinas que utilizarão o Vagrant.

Você pode pesquisar por Chef, Puppet, Ansible entre outros. Você pode também fazer tudo manualmente e depois exportar sua máquina virtual para ser reaproveitada pelos demais. Estas ferramentas não serão abordadas aqui. Neste tutorial, iremos apenas salvar todos os comandos utilizados (shell) em um arquivo texto e fazer com que o Vagrant execute todos eles.

No site do Vagrant existem tutoriais para várias ferramentas. Aqui utilizaremos shell: https://www.vagrantup.com/docs/provisioning/shell.html

Abra o Vagrantfile, e edite para o conteúdo abaixo:

# -*- mode: ruby -*-
# vi: set ft=ruby :
$script = <<SCRIPT
echo Hello, world!
SCRIPT
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial64"
config.vm.provision "shell", inline: $script
end

Suba novamente a máquina (vagrant up). Com a máquina rodando, execute vagrant provision.

Script de provisionamento

É importante aqui destacar que, sempre que você começar a mexer com alguma tecnologia nova, deve-se fazer um “Hello, world!” para evitar a maldição no aprendizado :D.

Brincadeiras a parte, o importante é entender o funcionamento do script. Ele irá executar como se o usuário digitasse o comando diretamente no terminal.

Feito isso, vamos ao que interessa. No ubuntu, utiliza-se o apt-get para instalar os pacotes. Vamos criar um script útil com o que interessa. Neste caso será o PHP, com diversas extensões, MySQL e Apache.

Altere o Vagrantfile para o código abaixo:

# -*- mode: ruby -*-
# vi: set ft=ruby :
$script = <<SCRIPTecho -e "\n--- Atualizando pacotes ---\n"
sudo apt-get -qq update
#Variáveis para o MySQL - Apenas para máquina de desenvolvimento
#Altere para os dados que achar relevante
DBHOST=localhost
DBNAME=dbname
DBUSER=dbuser
DBPASSWD=dbpass
echo -e "\n--- Instalando e configurando MySQL ---\n"
debconf-set-selections <<< "mysql-server mysql-server/root_password password $DBPASSWD"
debconf-set-selections <<< "mysql-server mysql-server/root_password_again password $DBPASSWD"
sudo apt-get -y install mysql-server
mysql -uroot -p$DBPASSWD -e "CREATE DATABASE $DBNAME"
mysql -uroot -p$DBPASSWD -e "grant all privileges on $DBNAME.* to '$DBUSER'@'%' identified by '$DBPASSWD'"
systemctl enable mysqlsed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/mysql.conf.d/mysqld.cnf
sudo service mysql restart
echo -e "\n--- Instalando Apache 2 ---\n"
sudo apt-get install -y apache2
echo -e "\n--- Instalando o PHP 7.2 ---\n"
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:ondrej/php
sudo apt-get -qq update
sudo apt-get install -y php7.2 libapache2-mod-php7.2 php7.2-cli php7.2-common php7.2-mbstring php7.2-gd php7.2-intl php7.2-xml php7.2-mysql php7.2-zip
SCRIPTVagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial64"
config.vm.provision "shell", inline: $script
end

Com esta configuração, será instalado o Apache, o MySql e o PHP 7.2. Também alguns comandos são realizados para compatibilizar as aplicações que rodam dentro da máquina virtual com o Vagrant, para serem acessíveis pela máquina hospedeira. Altere o script para suas configurações conforme achar conveniente.

Certo, mas agora como efetivamente fazer o código rodar?

O Vagrant trabalha com redirecionamento de portas. No caso do Apache, o padrão dele é a porta 80. Vamos fazer com que o Vagrant aponte a porta 80 da máquina virtual para a porta 8000 local. O mesmo para a porta do MySQL 3306.

Para tanto, basta adicionar nas configurações a instrução abaixo:

Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial64"
config.vm.network "forwarded_port", guest: 80, host: 8000 #apache
config.vm.network "forwarded_port", guest: 3306, host: 3306 #mysql
config.vm.provision "shell", inline: $script
end

Reinicie a máquina virtual e vamos no navegador, acessar http://localhost:8000

Você verá a página do Apache.

Mas e agora, como fazer meu código, que está na minha máquina, executar na máquina virtual?

O Vagrant trabalha com sincronização constante dos arquivos. Durante o procedimento de inicialização da máquina virtual, você verá uma linha com os seguintes dizeres:

==> default: Mounting shared folders...
default: /vagrant => C:/caminho/do/vagrant

Isso significa que a sua pasta está sendo espelhada na pasta /vagrant da máquina virtual. Então, só o que precisamos é fazer com que o apache entenda que este é o nosso diretório.

Vamos criar um link simbólico entre esta pasta e a pasta padrão do apache /var/www/html .

Adicione na parte do script o texto abaixo:

echo -e "\n--- Definindo diretório público ---\n"
rm -rf /var/www/html
ln -fs /vagrant /var/www/html

Isso fará com que todos os arquivos na pasta do apache sejam apagados e então o link simbólico seja criado corretamente.

Vamos criar na pasta raiz um arquivo index.php :

<?phpecho "Hello, world";

Lembre-se da maldição do Hello, world!

Com isso, ao acessar http://localhost:8000/ você verá a aplicação rodando conforme esperado.

Sucesso!

Tente também se conectar ao MySQL na porta 3306, com as credenciais que você utilizou no Vagrantfile.

Agora, só mais um detalhe. Por padrão, o PHP não vem configurado para exibir os erros. Vamos editar nosso script para modificar este comportamento, afinal é uma máquina de desenvolvedor:

echo -e "\n--- Configurando PHP.ini ---\n"
sudo sed -i "s/error_reporting = .*/error_reporting = E_ALL/" /etc/php/7.2/apache2/php.ini
sudo sed -i "s/display_errors = .*/display_errors = On/" /etc/php/7.2/apache2/php.ini
sudo service apache2 restart

Perfeito, agora podemos visualizar qualquer erro gerado pela aplicação, não apenas a mensagem HTTP 500.

Pronto, tudo configurado, agora é só jogar no nosso repositório git e compartilhar com outras pessoas que usarão esta máquina virtual.

# inicializa repositório git
$ git init
# ignora no versionamento a pasta do vagrant
$ echo $'.vagrant/\n!.gitignore' > .gitignore
# adiciona arquivos para o commit
$ git add Vagrantfile index.php .gitignore
# commit
$ git commit -m "Texto do commit"
# configura repositório remoto
$ git remote add origin https://github.com/felippeduarte/nome-do-repositorio.git
# push
$ git push -u origin master

Então é isso, espero que tenham gostado. Façam isso para todos os projetos, sempre criando uma máquina virtual diferente, mesmo que as configurações sejam idênticas.

Os arquivos estão em disponíveis em https://github.com/felippeduarte/medium/tree/master/vagrant-provision-sample

Abraço!

--

--