DevOps na prática – entrega de software confiável e automatizada
Página 76
3.6. Um problema atinge produç ão, e agora? Casa do Código Figura 3.6: Verificações falhando quando um problema atinge produç ão Para que tudo volte ao normal, você precisará reinstalar o servidor de banco de dados. No entanto, fizemos isto de forma manual no capítulo2. Re- petir todos aqueles passos manualmente levará muito tempo e, em momentos de crise como este, tempo é um recurso escasso. Será que não existe uma ma- neira melhor de instalar e configurar esses servidores?

Página 77
Capítulo4 Infraestruturacomocódigo Administradores de sistema aprendem o poder da linha de comando desde cedo e passam boa parte do dia no terminal controlando a infraestrutura da sua empresa. É comum dizer que eles estão alterando aconfiguraç ão do sis- tema. Seja instalando novos servidores, instalando novo software, fazendo upgradede software existente, editando arquivos de configuraç ão, reiniciando processos, lendo arquivos de log, efetuando e restaurandobackups, criando novas contas de usuário, gerenciando permissões, ajudando desenvolvedores a investigar algum problema ou escrevendoscriptspara automatizar tarefas repetíveis.
Cada uma dessas tarefas altera ligeiramente o estado do servidor e pode potencialmente causar problemas se a mudança não for executada correta- mente. É por isso que muitos administradores de sistema não dão acesso aos servidores de produç ão para desenvolvedores: para evitar mudanças indese- jáveis e pela falta de confiança. No entanto, em muitas empresas, essas tarefas
Página 78
4.1. Provisionamento, configuraç ão ou deploy? Casa do Código são executadas manualmente nos servidores de produç ão pelos próprios ad- ministradores de sistema e eles também podem cometer erros.
Um dos principais princípios de DevOps é investir em automaç ão. Auto- mação permite executar tarefas mais rapidamente e diminui a possibilidade de erros humanos. Um processo automatizado é mais confiável e pode ser auditorado com mais facilidade. Conforme o número de servidores que pre- cisam ser administrados aumenta, processos automatizados se tornam essen- ciais. Alguns administradores de sistema escrevem seus própriosscriptspara automatizar as tarefas mais comuns. O problema é que cada um escreve sua própria versão dosscriptse fica difícil reutilizá-los em outras situações. Por outro lado, desenvolvedores são bons em escrever código modularizado e reu- tilizável.
Com o avanço da cultura DevOps e o aumento da colaboraç ão entre ad- ministradores de sistema e desenvolvedores, diversas ferramentas têm evo- luído para tentar padronizar o gerenciamento automatizado de infraestru- tura. Tais ferramentas permitem tratar infraestrutura da mesma forma que tratamos código: usando controle de versões, realizando testes, empacotando e distribuindo módulos comuns e, obviamente, executando as mudanças de configuraç ão no servidor.
Essa prática é conhecida comoinfraestrutura como códigoe nos permi- tirá resolver o problema que encontramos no final do capítulo3. Em vez de reinstalar tudo manualmente, vamos usar uma ferramenta de gerenciamento de configurações para automatizar o processo de provisionamento, configu- ração edeployda loja virtual.
4.1 Provisionamento,configuração ou deploy?
Ao comprar um laptop ou um celular novo, você só precisa ligá-lo e ele já está pronto para uso. Em vez de mandar as peças individuais e um manual de como montar sua máquina, o fabricante já fez todo o trabalho necessário para que você usufrua seu novo aparelho sem maiores problemas. Como usuário, você só precisa instalar programas e restaurar seus arquivos para considerar a máquina sua. Esse processo de preparaç ão para o usuário final é conhecido comoprovisionamento.
Página 79
Casa do Código Capítulo 4. Infraestrutura como código O termoprovisionamentoé comumente usado por empresas de teleco- municações e por equipes de operações para se referir às etapas de preparaç ão iniciais de configuraç ão de um novo recurso: provisionar um aparelho celu- lar, provisionar acesso à internet, provisionar um servidor, provisionar uma nova conta de usuário, e assim por diante. Provisionar um aparelho celular envolve, entre outras coisas: alocar uma nova linha, configurar os equipa- mentos de rede que permitem completar ligações, configurar serviços extra como SMS ou e-mail e, por fim, associar tudo isso com o chip que está no seu celular.
No caso de servidores, o processo de provisionamento varia de empresa para empresa dependendo da infraestrutura e da divisão de responsabilida- des entre as equipes. Se a empresa possui infraestrutura própria, o processo de provisionamento envolve a compra e instalaç ão física do novo servidor no seudata center. Se a empresa possui uma infraestrutura virtualizada, o pro- cesso de provisionamento só precisa alocar uma nova máquina virtual para o servidor. Da mesma forma, se a equipe de operações considerar a equipe de desenvolvimento como “usuário final”, o processo de provisionamento acaba quando o servidor está acessível na rede, mesmo se a aplicaç ão em si ainda não estiver rodando. Se considerarmos os verdadeiros usuários como “usuá- rios finais”, então o processo de provisionamento só acaba quando o servidor e a aplicaç ão estiverem rodando e acessíveis na rede.
Para evitar maior confusão e manter integridade no decorrer do livro, vale a pena olhar para o processo de ponta a ponta e definir uma terminolo- gia adequada. Imaginando o cenário mais longo de uma empresa que possui infraestrutura própria porém não tem servidores sobrando para uso, as etapas necessárias para colocar uma nova aplicaç ão no ar seriam:
1)Compra de hardware: em empresas grandes essa etapa inicia um processo de aquisiç ão, que envolve diversas justificações e aprovações pois investir dinheiro em hardware influi na contabilidade e no planejamento finan- ceiro da empresa.
2)Instalaç ão física do hardware: essa etapa envolve montar o novo servidor numracknodata center, assim como instalaç ão de cabos de força, de rede etc.
Página 80
4.1. Provisionamento, configuraç ão ou deploy? Casa do Código 3)Instalaç ão e configuraç ão do sistema operacional: uma vez que o ser- vidor é ligado, é preciso instalar um sistema operacional e configurar os items básicos de hardware como: interfaces de rede, armazenamento (disco, partições, volumes em rede), autenticaç ão e autorizaç ão de usuá- rios, senha deroot, repositório de pacotes etc.
4)Instalaç ão e configuraç ão de serviços comuns: além das configurações base do sistema operacional, muitos servidores precisam configurar ser- viços de infraestrutura básicos como: DNS, NTP, SSH, coleta e rotaç ão de logs, backups, firewall, impressão etc.
5)Instalaç ão e configuraç ão da aplicaç ão: por fim, é preciso instalar e confi- gurar tudo que fará este servidor ser diferente dos outros: componentes de middleware, a aplicaç ão em si, assim como configurações do middleware e da aplicaç ão.
No decorrer do livro, usaremos o termoprovisionamentopara se referir ao processo que envolve as etapas 1 – 4, ou seja, todas as atividades necessárias para que o servidor possa ser usado e independente da razão pela qual ele foi requisitado. Usaremos o termodeploy, ou o equivalente em português implantaç ão, quando nos referirmos à etapa 5. Apesar dodeployprecisar de um servidor provisionado, o ciclo de vida do servidor é diferente da aplicaç ão.
O mesmo servidor pode ser usado por várias aplicações e cada aplicaç ão pode efetuardeploydezenas ou até centenas de vezes, enquanto o provisionamento de novos servidores acontece com menos frequência.
No pior caso, o processo de provisionamento pode demorar semanas ou até meses dependendo da empresa. Por esse motivo, é comum ver equipes de desenvolvimento definindo com bastante antecedência os requisitos de hard- ware para seus ambientes de produç ão e iniciando esse processo com a equipe de operações nas etapas iniciais do projeto, para evitar atrasos quando a apli- cação estiver pronta para ir ao ar. Alguma colaboraç ão pode acontecer no começo do processo, porém a maior parte do tempo as duas equipes traba- lham em paralelo sem saber o que a outra está fazendo.
Pior ainda, muitas dessas decisões arquiteturais cruciais sobre a quanti- dade de servidores, configurações de hardware ou escolha do sistema ope- racional são tomadas no começo do projeto, no momento em que se tem a
Página 81
Casa do Código Capítulo 4. Infraestrutura como código menor quantidade de informaç ão e conhecimento sobre as reais necessida- des do sistema.
Um dos aspectos mais importantes da cultura DevOps é reconhecer esse conflito de objetivos e criar um ambiente de colaboraç ão entre as equipes de desenvolvimento e de operações. O compartilhamento de práticas e ferra- mentas permite que a arquitetura se adapte e evolua conforme as equipes aprendem mais sobre o sistema rodando no mundo real: em produç ão. Esta visão holística também ajuda a encontrar soluções que simplifiquem o pro- cesso de compra e provisionamento, removendo etapas ou utilizando auto- mação para fazer com que elas aconteçam mais rápido.
Um bom exemplo dessa simplificaç ão do processo é o uso de tecnologias como virtualizaç ão de hardware e computaç ão em nuvem – também conhe- cida pelo termo em inglêscloud computingou simplesmentecloud. Provedo- res de serviço cloudde ponta permitem que você tenha um novo servidor no ar em questão de minutos através de um simples clique de botão ou chamada de API!
4.2 Ferramentas de gerenciamento de configu- ração Na seção anterior, explicamos a diferença entre provisionamento edeploy.
Com exceção dos items 1 e 2 que envolvem compra e instalaç ão física de hard- ware, as outras três etapas envolvem algum tipo de configuraç ão do sistema:
seja do sistema operacional em si, do software base instalado na máquina ou da aplicaç ão que roda em cima dele. A figura4.1mostra as diferentes etapas do ciclo de vida de um servidor e o gerenciamento de configuraç ão atual.
Figura 4.1: Escopo do gerenciamento de configuraç ão

Página 82
4.2. Ferramentas de gerenciamento de configuraç ão Casa do Código Existem diversas ferramentas para gerenciamento de configuraç ão:shell scripts(a linha de comando também é conhecida comoshell),Puppet(http:
//www.puppetlabs.com/puppet/) , Chef(http://www.opscode.com/chef/) , Ansible(http://www.ansibleworks.com/tech/) , Salt(http://saltstack.com/ community Pallet(http://palletops.com/) e CFEngine(http://cfengine.
com/) são algumas das mais populares.
A maioria dessas ferramentas possui uma empresa responsável pelo seu desenvolvimento e pelo crescimento da comunidade e ecossistema ao seu re- dor. Todas elas estão contribuindo para a evoluç ão da comunidade DevOps e, apesar de competirem entre si, seu maior adversário ainda é a falta de uso de ferramentas. Por incrível que pareça, a maioria das empresas ainda gerenciam seus servidores de forma manual ou possuemscriptsproprietários escritos há tanto tempo que ninguém consegue dar manutenção.
A grande diferença entreshell scriptsproprietários e as outras ferramen- tas é que geralmente oscriptsó funciona para instalar e configurar o servidor pela primeira vez. Ele serve como documentaç ão executável dos passos exe- cutados na primeira instalaç ão, porém se oscriptfor executado novamente, ele provavelmente não vai funcionar. O administrador de sistemas precisa ser bem disciplinado e precisa escrever código extra para lidar com as situações onde algum pacote já está instalado ou precisa ser removido ou atualizado.
As outras ferramentas especializadas têm uma característica importante, conhecida comoidempotência: você pode executá-las diversas vezes segui- das com o mesmo código e elas mudarão apenas o que for necessário. Se um pacote já está instalado, ele não será reinstalado. Se um serviço já está rodando, ele não será reiniciado. Se o arquivo de configuraç ão já possui o conteúdo correto, ele não será alterado.
Idempotência permite escrever código de infraestrutura de forma decla- rativa. Ao invés da instruç ão ser"instale o pacote X”ou"crie o usuário Y”, você diz"eu quero que o pacote X esteja instalado”ou"eu quero que o usuário Y exista”. Você declara o estado final desejado e quando a ferramenta executa, caso o pacote ou o usuário já existam, nada irá acontecer.
A próxima coisa que você pode estar se perguntando é"Qual dessas ferra- mentas devo usar?”. Neste capítulo, usaremos o Puppet por permitir exempli- ficar bem essa propriedade declarativa da linguagem, por ser uma ferramenta
Página 83
Casa do Código Capítulo 4. Infraestrutura como código madura, aceita na comunidade de administradores de sistema e por ser bem adotada na comunidade. Porém, a verdade é que usar qualquer uma dessas ferramentas é melhor que nada. As ferramentas nesse espaço estão evoluindo constantemente e é importante você se familiarizar com algumas delas antes de tomar a decisão de qual delas é melhor para sua situaç ão.
4.3 Introdução aoPuppet:recursos, provedo- res,manifestos e dependências Cada uma das ferramentas de gerenciamento de configuraç ão possui uma ter- minologia própria para se referir aos elementos da linguagem e aos compo- nentes do seu ecossistema. Em um nível fundamental, cada comando que você declara na linguagem é umadiretivae você pode definir um conjunto delas em umarquivo de diretivas, que é o equivalente a um arquivo de código-fonte de uma linguagem de programaç ão como Java ou Ruby.
No Puppet, essas diretivas são chamadas derecursos. Alguns exemplos de recursos que você pode declarar no Puppet são: pacotes, arquivos, usuá- rios, grupos, serviços, trechos de scriptexecutável, dentre outros. O arquivo no qual você declara um conjunto de diretivas é chamado demanifesto. Ao escrever código Puppet você passará a maior parte do tempo criando e edi- tando esses manifestos.
Para se familiarizar com a sintaxe da linguagem Puppet e seu modelo de execuç ão, vamos reconstruir a máquina virtual do servidor de banco de dados e logar por SSH na máquina que está zerada:
$ vagrant up db Bringing machine ’db’ up with ’virtualbox’ provider…
==> db: Importing base box ’hashicorp/precise32’…
==> db: Matching MAC address for NAT networking…
==> db: Checking if box ’hashicorp/precise32’ is up to date…
==> db: Setting the name of the VM: blank_db_1394854529922_29194 ==> db: Clearing any previously set network interfaces…
==> db: Preparing network interfaces based on configuration…
db: Adapter 1: nat db: Adapter 2: hostonly ==> db: Forwarding ports…
Página 84
4.3. Introduç ão ao Puppet: recursos, provedores, manifestos e dependênciasCasa do Código db: 22 => 2222 (adapter 1) ==> db: Running ’pre-boot’ VM customizations…
==> db: Booting VM…
==> db: Waiting for machine to boot. This may take a few minutes…
db: SSH address: 127.0.0.1:2222 db: SSH username: vagrant db: SSH auth method: private key ==> db: Machine booted and ready!
==> db: Configuring and enabling network interfaces…
==> db: Mounting shared folders…
db: /vagrant => /private/tmp/blank $ vagrant ssh db Welcome to Ubuntu 12.04 LTS (GNU/Linux …
vagrant@db$ Aproveitando que aboxdo Vagrant já possui o Puppet instalado, podemos começar a usá-lo diretamente criando um novo arquivo de manifesto vazio chamadodb.pp. Por padrão, manifestos possuem extensão.pp:
vagrant@db$ nano db.pp Como conteúdo inicial iremos declarar um recurso para o pacote mysql-servere dizer que o queremos instalado no sistema. Isso é feito pas- sando o valorinstalledpara o parâmetroensuredo recursopackage:
package:
ensure =>, } Se você comparar essa declaraç ão de recurso com o comando que execu- tamos no capítulo2–sudo apt-get install mysql-server – verá que eles são parecidos. A principal diferença é a naturezadeclarativada lin- guagem do Puppet. No comando manual, instruímos o gerenciador de paco- tes a instalar o pacotemysql-serverenquanto que no Puppet declaramos o estado final desejado do sistema.
Manifestos não são uma lista de comandos a ser executados. Quando o Puppet executa, ele compara o estado atual do sistema com o estado declarado
Página 85
Casa do Código Capítulo 4. Infraestrutura como código no manifesto, calcula a diferença e executa apenas as mudanças necessárias.
Após salvar o arquivo, execute o Puppet com o seguinte comando:
vagrant@db$ sudo puppet apply db.pp err: /Stage[main]//Package[mysql-server]/ensure: change from purged to present failed: Execution of …
…
E: Unable to fetch some archives, maybe run apt-get update or …
notice: Finished catalog run in 6.62 seconds Você pode ver que o Puppet tentou alterar o estado do pacote mysql-serverde removido (purged ) para presente (present ), no en- tanto encontrou erros pois esquecemos de executar o comandoapt-get update, como fizemos no capítulo2. Para isso, vamos declarar um novo re- cursoexece definir uma dependência dizendo que ele deve rodar antes do pacotemysql-server. Mudaremos o conteúdo do arquivo db.pppara:
exec{"apt-update":
command =>"/usr/bin/apt-get update"
} package{"mysql-server":
ensure =>installed, require =>Exec["apt-update"], } Para entender o conteúdo do manifesto, precisamos conhecer mais algu- mas características da linguagem do Puppet. Todo recurso possui um nome – a string entre aspas duplas logo após a declaraç ão e antes do “:” – que serve como um identificador único. Quando um recurso precisa se referir a outro recurso, usamos a sintaxe com a primeira letra maiúscula e o nome do recurso entre colchetes.
O Puppet não garante que a ordem de execuç ão respeite a ordem em que os recursos são declarados no manifesto. Quando existe uma dependência, você precisa declará-la explicitamente. Neste caso, adicionamos o parâme- trorequireno recursopackagepara garantir que o comandoapt-get
Página 86
4.3. Introduç ão ao Puppet: recursos, provedores, manifestos e dependênciasCasa do Código updateexecute antes da instalaç ão do MySQL. Agora o Puppet instalará o pacotemysql-serverquando executado novamente:
vagrant@db$ sudo puppet apply db.pp notice: /Stage[main]//Exec[apt-update]/returns: executed successfully notice: /Stage[main]//Package[mysql-server]/ensure: ensure changed ’purged’ to ’present’ notice: Finished catalog run in 59.98 seconds Você pode ver que o Puppet alterou o estado do pacotemysql-server de removido (purged ) para presente (present ). Para confirmar que o pacote foi realmente instalado, você pode executar o comando:
vagrant@db$ aptitude show mysql-server Package: mysql-server State: installed …
Perceba que o gerenciador de pacotes diz que o estado atual do pacote mysql-serveré “instalado” (installed ). Para entender a natureza declara- tiva do manifesto, tente rodar o Puppet novamente:
vagrant@db$ sudo puppet apply db.pp notice: /Stage[main]//Exec[apt-update]/returns: executed successfully notice: Finished catalog run in 6.41 seconds Dessa vez, o recursoapt-updateexecutou, porém nada aconteceu com o pacotemysql-server, que já estava instalado, satisfazendo o estado de- clarado em nosso manifesto do Puppet.
Outra diferença que você pode ter percebido entre o manifesto Puppet e o comando manual do capítulo2é que não precisamos dizer para o Puppet qual gerenciador de pacotes usar. Isso acontece pois recursos do Puppet são abstratos. Existem várias implementações diferentes – chamadas de prove- dores– para os diversos sistemas operacionais. Para o recursopackage, o Puppet possui diversos provedores:apt,rpm,yum,gem, dentre outros. Na
Página 87
Casa do Código Capítulo 4. Infraestrutura como código hora da execuç ão, com base em informações do sistema o Puppet irá escolher o provedor mais adequado. Para ver uma lista com todos os provedores dis- poníveis para um determinado recurso assim como documentaç ão detalhada dos parâmetros que o recurso aceita, você pode executar o comando:
vagrant@db$ puppet describe package package ======= Manage packages. …
…
Providers ——— aix, appdmg, apple, apt, aptitude, aptrpm, blastwave, dpkg, fink, freebsd, gem, hpux, macports, msi, nim, openbsd, pacman, pip, pkg, pkgdmg, pkgutil, portage, ports, portupgrade, rpm, rug, sun, sunfreeware, up2date, urpmi, yum, zypper Agora que entendemos o funcionamento básico do Puppet, vamos parar de executar comandos manuais dentro do servidor e começar a escrever có- digo de infraestrutura fora da máquina virtual. Usaremos o Vagrant para nos ajudar a provisionar o servidor.
Recomeçar usando Puppet com Vagrant Primeiramente vamos sair da máquina virtualdbe destruí-la novamente, como fizemos no fim do capítulo3:
vagrant@db$logout Connection to 127.0.0.1 closed.
$ vagrant destroy db db: Are you sure you want to destroy the ’db’ VM? [y/N] y ==> db: Forcing shutdown of VM…
==> db: Destroying VM and associated drives…
No mesmo diretório em que você criou o arquivoVagrantfile, crie um novo diretório chamadomanifestse, dentro dele, um novo arquivodb.pp
Página 88
4.3. Introduç ão ao Puppet: recursos, provedores, manifestos e dependênciasCasa do Código com o mesmo conteúdo da seção anterior. A nova estrutura de diretórios deve estar assim:
.
Vagrantfile manifests db.pp Agora é preciso alterar o arquivo de configuraç ão do Vagrant – o arquivo Vagrantfile– para usar o Puppet como ferramenta de provisionamento da máquina virtualdb:
VAGRANTFILE_API_VERSION="2"
Vagrant.configure( VAGRANTFILE_API_VERSION) do|config| config.vm.box ="hashicorp/precise32"
config.vm.define :dbdo|db_config| db_config.vm.network :private_network, :ip=>"192.168.33.10"
db_config.vm.provision "puppet"do|puppet| puppet.manifest_file ="db.pp"
end end config.vm.define :webdo|web_config| web_config.vm.network :private_network, :ip=>"192.168.33.12"
end config.vm.define :monitordo|monitor_config| monitor_config.vm.network :private_network, :ip=>"192.168.33.14"
end end Feito isso, assim que subirmos uma nova máquina virtual para o servi- dor de banco de dados, o Vagrant irá rodar o Puppet automaticamente, sem precisarmos logar no servidor por SSH e executar comandos manualmente.
Página 89
Casa do Código Capítulo 4. Infraestrutura como código A saída da execuç ão do Puppet será mostrada logo após a saída normal do Vagrant e você perceberá se algum erro acontecer. Por exemplo, a execuç ão inicial mostrará o pacotemysql-serversendo instalado:
$ vagrant up db Bringing machine ’db’ up with ’virtualbox’ provider…
==> db: Importing base box ’hashicorp/precise32’…
==> db: Matching MAC address for NAT networking…
==> db: Checking if box ’hashicorp/precise32’ is up to date…
==> db: Setting the name of the VM: blank_db_1394854957677_21160 ==> db: Clearing any previously set network interfaces…
==> db: Preparing network interfaces based on configuration…
db: Adapter 1: nat db: Adapter 2: hostonly ==> db: Forwarding ports…
db: 22 => 2222 (adapter 1) ==> db: Running ’pre-boot’ VM customizations…
==> db: Booting VM…
==> db: Waiting for machine to boot. This may take a few minutes…
db: SSH address: 127.0.0.1:2222 db: SSH username: vagrant db: SSH auth method: private key ==> db: Machine booted and ready!
==> db: Configuring and enabling network interfaces…
==> db: Mounting shared folders…
db: /vagrant => /private/tmp/blank db: /tmp/vagrant-puppet-2/manifests => /private/tmp/blank/ manifests ==> db: Running provisioner: puppet…
Running Puppet with db.pp…
stdin: is not a tty notice: /Stage[main]//Exec[apt-update]/returns: executed successfully notice: /Stage[main]//Package[mysql-server]/ensure: ensure changed ’purged’ to ’present’ notice: Finished catalog run in 71.68 seconds Agora que sabemos como usar o Vagrant e o Puppet para provisionar
Página 90
4.4. Reinstalando o servidor de banco de dados Casa do Código nosso servidor, é hora de restaurar o ambiente de produç ão da loja virtual.
4.4 Reinstalando o servidor de banco de dados Temos um manifesto simples que executa o primeiro passo da instalaç ão do servidor de banco de dados. Se você lembra do próximo passo que toma- mos no capítulo2, precisamos nesse momento criar o arquivo de configura- ção/etc/mysql/conf.d/allow_external.cnf para permitir acesso remoto ao servidor MySQL. Faremos isso usando o recursofile, que re- presenta a existência de um arquivo no sistema. Alteramos o conteúdo do arquivodb.pppara:
exec{"apt-update":
command =>"/usr/bin/apt-get update"
} package{"mysql-server":
ensure =>installed, require =>Exec["apt-update"], } file{"/etc/mysql/conf.d/allow_external.cnf":
owner => mysql, group => mysql, mode => 0644, content =>"[mysqld]˙ bind-address = 0.0.0.0", require =>Package["mysql-server"], } Por padrão, o nome do recurso representa o caminho completo onde o arquivo será criado no sistema e o parâmetrocontentpossui o conteúdo do arquivo. Para especificar um caminho diferente, você pode usar o parâmetro path. Os parâmetrosowner, groupemoderepresentam o usuário e grupo associados ao arquivo e suas permissões.
Para aplicar a nova configuraç ão, ao invés de destruir e subir uma nova máquina virtual, você pode usar o comandoprovisiondo Vagrant para simplesmente executar o Puppet na máquina virtual já existente:
Página 91
Casa do Código Capítulo 4. Infraestrutura como código $ vagrant provision db ==> db: Running provisioner: puppet…
Running Puppet with db.pp…
stdin: is not a tty notice: /Stage[main]//Exec[apt-update]/returns: executed successfully notice: /Stage[main]//File[ /etc/mysql/conf.d/ allow_external.cnf]/ ensure: defined content as ’{md5}4149205484cca052a3bfddc8ae60a71e’ notice: Finished catalog run in 4.36 seconds Dessa vez, o Puppet criou o arquivo /etc/mysql/conf.d/allow_external.cnf. Para saber quando um arquivo de configuraç ão precisa ser alterado, ele calcula umchecksum MD5 do seu conteúdo. O MD5 é um algoritmo dehashbastante usado para verificar a integridade de um arquivo. Uma pequena alteraç ão no conteúdo do arquivo faz com que o seuchecksumMD5 seja totalmente diferente.
No nosso caso, o conteúdo do arquivo de configuraç ão é pequeno e con- seguimos declará-lo por completo no manifesto. No entanto, é comum ter arquivos de configuraç ão com dezenas ou centenas de linhas. Gerenciar ar- quivos longos como uma única string em código Puppet não é uma boa ideia.
Podemos trocar o conteúdo do arquivo por umtemplate. O Puppet entende templatesERB (embedded ruby), um sistema detemplateque permite embutir código Ruby dentro de um arquivo texto.
Para usar umtemplate, primeiramente precisamos extrair o conteúdo para um novo arquivoallow_ext.cnf, que deve ficar junto do manifesto:
.
Vagrantfile manifests allow_ext.cnf db.pp Mude o conteúdo do arquivoallow_ext.cnfligeiramente, para que o Puppet altere o arquivo na próxima execuç ão:
[mysqld] bind-address =9.9.9.9
Página 92
4.4. Reinstalando o servidor de banco de dados Casa do Código Por fim, trocamos o parâmetrocontentdo recursofilepara usar o template:
exec package file:
owner => mysql, group => mysql, mode => 0644, content =>("/vagrant/manifests/allow_ext.cnf"), require =>["mysql-server"], } Ao executar o Puppet novamente, você verá que ochecksumMD5 irá mu- dar e o conteúdo do arquivo será alterado:
$ vagrant provision db ==> db: Running provisioner: puppet…
Running Puppet with db.pp…
stdin: is not a tty notice: /Stage[main]//Exec[apt-update]/returns: executed successfully notice: /Stage[main]//File[ /etc/mysql/conf.d/ allow_external.cnf]/ content: content changed ’{md5}4149205484cca052a3bfddc8ae60a71e’ to ’{md5}8e2381895fcf40fa7692e38ab86c7192’ notice: Finished catalog run in 4.60 seconds Agora precisamos reiniciar o serviço para que o MySQL perceba a altera- ção no arquivo de configuraç ão. Fazemos isso declarando um novo recurso do tiposervice:
exec…
package…
file…
service{"mysql":
Página 93
Casa do Código Capítulo 4. Infraestrutura como código ensure =>, enable =>, hasstatus =>, hasrestart =>, require =>["mysql-server"], } O serviço possui novos parâmetros: ensure => running, que ga- rante que o serviço esteja rodando; enable, que garante que o serviço rode sempre que o servidor reiniciar;hasstatusehasrestart, que declaram que o serviço entende os comandos statuserestart; por fim, o parâmetrorequire, que declara uma dependência com o recurso Package["mysql-server"].
Se você tentar executar o Puppet, verá que nada acontece pois o serviço já foi iniciado quando o pacote foi instalado.
Para reiniciar o serviço toda vez que o arquivo de configuraç ão mudar, precisamos declarar uma nova dependência no recurso File["/etc/mysql/conf.d/allow_external.cnf"]:
exec…
package…
file{"/etc/mysql/conf.d/allow_external.cnf":
owner => mysql, group => mysql, mode => 0644, content =>template("/vagrant/manifests/allow_ext.cnf"), require =>Package["mysql-server"], notify=>Service["mysql"], } service…
O parâmetronotifydefine uma dependência de execuç ão: sempre que o recursofilefor alterado, ele fará com que o recursoserviceexecute.
Dessa vez, se alterarmos o conteúdo dotemplateallow_ext.cnfde volta para0.0.0.0e executarmos o Puppet, o serviço será reiniciado:
Página 94
4.4. Reinstalando o servidor de banco de dados Casa do Código $ vagrant provision db ==> db: Running provisioner: puppet…
Running Puppet with db.pp…
stdin: is not a tty notice: /Stage[main]//Exec[apt-update]/returns: executed successfully notice: /Stage[main]//File[ /etc/mysql/conf.d/ allow_external.cnf]/ content: content changed ’{md5}8e2381895fcf40fa7692e38ab86c7192’ to ’{md5}907c91cba5e1c7770fd430182e42c437’ notice: /Stage[main]//Service[mysql]: Triggered ’refresh’ from 1 events notice: Finished catalog run in 6.88 seconds Com essa alteraç ão, o banco de dados está rodando novamente e uma das verificações do Nagios deve ficar verde. Para corrigir a próxima verificaç ão precisamos completar a configuraç ão do banco de dados criando oschemae o usuário da loja virtual.
Criaremos oschemadeclarando mais um recursoexeccom o mesmo comando usado no capítulo2:
exec…
package…
file…
service…
exec{"loja-schema":
unless =>"mysql -uroot loja_schema", command =>"mysqladmin -uroot create loja_schema", path => "/usr/bin/", require =>Service["mysql"], } Além da dependência com o recursoService["mysql"], usamos um novo parâmetrounlessque especifica um comando de teste: caso seu có- digo de saída seja zero, o comando principal não irá executar. Essa é a forma de tornar um recurso do tipoexecidempotente. Ao contrário doexec
Página 95
Casa do Código Capítulo 4. Infraestrutura como código que usamos para rodar oapt-get update, neste caso é importante que o Puppet não tente criar um novoschematoda vez que for executado.
Conforme fizemos no capítulo2, precisamos remover a conta anônima de acesso ao MySQL antes de criar o usuário para acessar nosso novoschema.
Faremos isso declarando um novo recursoexec:
exec…
package…
file…
service…
exec…
exec{"remove-anonymous-user":
command =>"mysql -uroot -e "DELETE FROM mysql.user WHEREuser=’’; FLUSH PRIVILEGES "", onlyif =>"mysql -u’ ’", path => "/usr/bin", require =>Service["mysql"], } Neste comando, ao invés de usar o parâmetrounlessusamos o parâme- tro opostoonlyifque irá executar o comando principal apenas se o código de saída do comando de teste for zero. Este comando de teste tenta acessar o MySQL usando um usuário vazio. Caso consiga conectar, o Puppet precisa executar o comando SQLDELETE …para remover a conta anônima. Por fim, criaremos um último recursoexecpara criar o usuário com permissão de acesso aoschemada loja virtual:
exec…
package…
file…
service…
exec…
exec…
exec{"loja-user":
unless =>"mysql -uloja -plojasecret loja_schema",
Página 96
4.4. Reinstalando o servidor de banco de dados Casa do Código command =>GRANT ALL PRIVILEGES ON loja_schema.* TO ’loja’@’%’ IDENTIFIED BY’lojasecret’;"", path => "/usr/bin/", require =>Exec["loja-schema"], } Ao executar o Puppet pela última vez no servidor de banco de dados, veremos uma saída parecida com:
$ vagrant provision db ==> db: Running provisioner: puppet…
Running Puppet with db.pp…
stdin: is not a tty notice: /Stage[main]//Exec[apt-update]/returns: executed successfully notice: /Stage[main]//Exec[loja-schema]/returns: executed successfully notice: /Stage[main]//Exec[loja-user]/returns: executed successfully notice: /Stage[main]//Exec[remove-anonymous-user]/returns:
executed successfully notice: Finished catalog run in 15.56 seconds Com isso conseguimos restaurar por completo o servidor de banco de da- dos e todas as verificações do Nagios referentes ao hostdbdeverão ficar ver- des. A única verificaç ão que permanecerá vermelha é a verificaç ão do Tom- cat, pois a aplicaç ão ainda não está acessível. Nas próximas seções iremos automatizar o processo de provisionamento do servidorwebe dodeployda aplicaç ão. Por enquanto, o conteúdo completo do manifestodb.ppficou:
exec{"apt-update":
command =>"/usr/bin/apt-get update"
} package{"mysql-server":
ensure =>installed, require =>Exec["apt-update"], }
Página 97
Casa do Código Capítulo 4. Infraestrutura como código file:
owner => mysql, group => mysql, mode => 0644, content =>("/vagrant/manifests/allow_ext.cnf"), require =>["mysql-server"], notify["mysql"], } service:
ensure =>, enable =>, hasstatus =>, hasrestart =>, require =>["mysql-server"], } exec:
unless =>, command =>, path =>, require =>["mysql"], } exec:
command =>DELETE FROM mysql.user WHEREuser=’’; FLUSH PRIVILEGES "", onlyif =>"mysql -u’ ’", path => "/usr/bin", require =>Service["mysql"], } exec{"loja-user":
unless =>"mysql -uloja -plojasecret loja_schema", command =>"mysql -uroot -e "GRANT ALL PRIVILEGES ON loja_schema.* TO ’loja’@’%’ IDENTIFIED BY’lojasecret’;"",
Página 98
4.5. Reinstalando o servidor web Casa do Código path =>, require =>["loja-schema"], } 4.5 Reinstalando o servidor web Agora que o servidordbestá restaurado, vamos automatizar o processo de provisionamento edeployno servidorweb. Para isto, criaremos um novo arquivo no diretóriomanifestschamadoweb.pp:
.
Vagrantfile manifests allow_ext.cnf db.pp web.pp Em vez de associar o novo manifesto com o servidorwebjá existente, vamos criar uma nova máquina virtual temporária chamadaweb2para po- dermos testar nosso código Puppet isoladamente antes de aplicá-lo no ambi- ente de produç ão. Ao final do capítulo, iremos nos livrar da máquina virtual web2e aplicaremos a mesma configuraç ão no servidorwebde verdade. O conteúdo doVagrantfilecom a nova máquina virtual deve ficar:
VAGRANTFILE_API_VERSION "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do|config| config.vm.box ="hashicorp/precise32"
config.vm.define :dbdo|db_config| db_config.vm.network :private_network, :ip=>"192.168.33.10"
db_config.vm.provision "puppet"do|puppet| puppet.manifest_file ="db.pp"
end end config.vm.define :webdo|web_config|
Página 99
Casa do Código Capítulo 4. Infraestrutura como código web_config.vm.network, :ip end config.vm.defineweb_config| web_config.vm.network, :ip web_config.vm.provision do|puppet| puppet.manifest_file ="web.pp"
end end config.vm.define :monitordo|monitor_config| monitor_config.vm.network :private_network, :ip=>"192.168.33.14"
end end Inicialmente vamos declarar apenas os recursos para executar oapt-get updatee instalar os pacotes base do servidorweb2, de forma similar aos comandos executados no capítulo2:
exec{"apt-update":
command =>"/usr/bin/apt-get update"
} package{ ["mysql-client", "tomcat7"]:
ensure =>installed, require =>Exec["apt-update"], } Ao subir a nova máquina virtual, o Puppet irá aplicar essa configuraç ão e instalar os pacotes:
$ vagrant up web2 Bringing machine ’web2’ up with ’virtualbox’ provider…
==> web2: Importing base box ’hashicorp/precise32’…
…
==> web2: Running provisioner: puppet…
Página 100
4.5. Reinstalando o servidor web Casa do Código Running Puppet with web.pp…
stdin: is not a tty notice: /Stage[main]//Exec[apt-update]/returns: executed successfully notice: /Stage[main]//Package[mysql-client]/ensure: ensure changed ’purged’ to ’present’ notice: /Stage[main]//Package[tomcat7]/ensure: ensure changed ’purged’ to ’present’ notice: Finished catalog run in 105.89 seconds Feito isso, você pode abrir seu navegador e digitar a URLhttp://192.168.33.
13:8080/e você deverá ver uma página que diz"It Works!”. Isso significa que o Tomcat está instalado e rodando corretamente.
Os próximos passos realizados no capítulo2foram a configuraç ão da co- nexão segura com HTTPS, a criaç ão dokeystorepara armazenar o certifi- cado SSL e o aumento da quantidade de memória disponível para a máquina virtual Java quando o Tomcat inicia.
Todas essas operações envolvem editar ou criar um novo arquivo no sis- tema. Já sabemos como entregar arquivos com o Puppet, então faremos os três passos de uma só vez. Primeiramente, vamos reaproveitar os arquivos de configuraç ão que já estão funcionando no servidorwebcomotemplatespara o manifesto do Puppet. Os seguintes comandos irão copiar os arquivos da máquina virtualwebpara o diretório compartilhado pelo Vagrant:
$ vagrant ssh web –’sudo cp /var/lib/tomcat7/conf/.keystore >/vagrant/manifests/’ $ vagrant ssh web –’sudo cp /var/lib/tomcat7/conf/server.xml >/vagrant/manifests/’ $ vagrant ssh web –’sudo cp /etc/default/tomcat7 >/vagrant/manifests/’ Em vez de usar o comandovagrant sshpara logar na máquina virtual, passamos um comando entre aspas após os traços –. Esse comando execu- tará dentro da máquina virtual. O caminho/vagranté onde o Vagrant mapeia o diretório onde você definiu oVagrantfiledentro da máquina virtual. Se tudo der certo, os arquivos fora do Vagrant devem ser:
Página 101
Casa do Código Capítulo 4. Infraestrutura como código .
Vagrantfile manifests .keystore allow_ext.cnf db.pp server.xml tomcat7 web.pp Como não precisamos alterar nada no conteúdo desses arquivos, basta declararmos novos recursos do tipofilepara que o Puppet entregue-os no lugar certo, ajustando seus donos e permissões:
exec package file:
owner => root, group => tomcat7, mode => 0640, source =>, require =>["tomcat7"], } file:
owner => root, group => tomcat7, mode => 0644, source =>, require =>["tomcat7"], } file:
owner => root, group => root, mode => 0644, source =>, require =>["tomcat7"],
Página 102
4.5. Reinstalando o servidor web Casa do Código } Por último, precisamos declarar o serviço tomcat7, que precisa ser rei- niciado quando os arquivos de configuraç ão são alterados. Os parâmetros do recursoservicesão os mesmos que usamos no serviço mysqlquando configuramos o servidor de banco de dados:
exec package file:
…
notify["tomcat7"], } file:
…
notify["tomcat7"], } file:
…
notify["tomcat7"], } service:
ensure =>, enable =>, hasstatus =>true, hasrestart =>true, require => Package["tomcat7"], } Podemos então rodar o manifesto todo para aplicar as últimas configura- ções no servidorweb2:
$ vagrant provision web2 ==> web2: Running provisioner: puppet…
Running Puppet with web.pp…
Página 103
Casa do Código Capítulo 4. Infraestrutura como código stdin: is not a tty notice: /Stage[main]//Exec[apt-update]/returns: executed successfully notice: /Stage[main]//File[ /var/lib/tomcat7/conf/server.xml]/ content: content changed ’{md5}523967040584a921450af2265902568d’ to ’{md5}e4f0d5610575a720ad19fae4875e9f2f’ notice: /Stage[main]//File[ /var/lib/tomcat7/conf/.keystore]/ ensure: defined content as ’{md5}80792b4dc1164d67e1eb859c170b73d6’ notice: /Stage[main]//File[ /etc/default/tomcat7]/content:
content changed ’{md5}49f3fe5de425aca649e2b69f4495abd2’ to ’{md5}1f429f1c7bdccd3461aa86330b133f51’ notice: /Stage[main]//Service[tomcat7]: Triggered ’refresh’ from 3 events notice: Finished catalog run in 14.58 seconds Feito isso, temos o Tomcat configurado para aceitar conexões HTTP e HTTPS. Podemos testar abrindo uma nova janela no navegador web e aces- sando a URLhttps://192.168.33.13:8443/. Após aceitar o certificado autoassi- nado, você verá uma página que diz"It works!”.
4.6 Fazendo deploy da aplicação Para termos um servidorwebcompleto, precisamos fazer odeployda loja virtual. Em vez de usar o Puppet para reconstruir o processo debuildden- tro da máquina virtual – como fizemos no capítulo2– vamos reaproveitar o artefato.wargerado. No capítulo6iremos revisitar essa decisão e encontra- remos uma forma melhor de gerar o artefato.warda aplicaç ão.
Vamos também reaproveitar otemplatedo arquivocontext.xml, no qual definimos os recursos JNDI para acesso ao banco de dados. Usando o mesmo truque da seção anterior, vamos copiar os arquivos de dentro da máquina virtualweb:
$ vagrant ssh web — ’sudo cp /var/lib/tomcat7/conf/ context.xml
Página 104
4.6. Fazendo deploy da aplicaç ão Casa do Código > /vagrant/manifests/’ $ >sudo cp /var/lib/tomcat7/webapps/devopsnapratica.war > /vagrant/manifests/’ Agora o conteúdo dos arquivos e diretórios fora do Vagrant devem ser:
.
Vagrantfile manifests .keystore allow_ext.cnf context.xml db.pp devopsnapratica.war server.xml tomcat7 web.pp O artefato contento a aplicaç ão webdevopsnapratica.warnão pre- cisa ser alterado, porém vamos definir variáveis dentro do manifesto para conter os dados de acesso ao banco de dados. Essas variáveis serão substi- tuídas quando o Puppet processar otemplateERB que criaremos no arquivo context.xml:
exec…
package…
file…
file…
file…
service…
$db_host ="192.168.33.10"
$db_schema="loja_schema"
$db_user ="loja"
$db_password="lojasecret"
file{"/var/lib/tomcat7/conf/context.xml":
owner => root,
Página 105
Casa do Código Capítulo 4. Infraestrutura como código group => tomcat7, mode => 0644, content =>("/vagrant/manifests/context.xml"), require =>["tomcat7"], notify["tomcat7"], } file:
owner => tomcat7, group => tomcat7, mode => 0644, source =>, require =>["tomcat7"], notify["tomcat7"], } A sintaxe do Puppet para declarar variáveis é um cifrão$seguido do nome da variável. Usamos o símbolo de igual=para atribuir valo- res às nossas variáveis. Para usar essas variáveis dentro dotemplatedo arquivocontext.xml, precisamos alterar o seu conteúdo substituindo os valores existentes pelo marcador<%= var %>, onde vardeve ser o nome da variável sem o cifrão$. O novotemplateERB do arquivo manifests/context.xml deve ser:
<?xml version=’1.0’ encoding=’utf-8’?> <Context> <!– Default set of monitored resources –> <WatchedResource>WEB-INF/web.xml</WatchedResource> <Resource"jdbc/web" auth="Container"
type="javax.sql.DataSource" maxActive="100"
maxIdle="30"
maxWait="10000"
username="<%= db_user%>"
password="<%= db_password%>"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql:// <%=db_host%>:3306/<%= db_schema%>"/> <Resourcename="jdbc/secure" auth="Container"
Página 106
4.6. Fazendo deploy da aplicaç ão Casa do Código type="javax.sql.DataSource""100" maxIdle="30"
maxWait="10000"
username="<%= db_user%>"
password="<%= db_password%>"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql:// <%=db_host%>:3306/<%= db_schema%>"/> <Resourcename="jdbc/storage" auth="Container"
type="javax.sql.DataSource" maxActive="100" maxIdle="30"
maxWait="10000"
username="<%= db_user%>"
password="<%= db_password%>"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql:// <%=db_host%>:3306/<%= db_schema%>"/> </Context> Com isso, finalizamos o manifesto Puppet para provisionar e fazerdeploy da aplicaç ão no servidorweb2. Podemos executá-lo rodando o comando:
$ vagrant provision web2 ==> web2: Running provisioner: puppet…
Running Puppet with web.pp…
stdin: is not a tty notice: /Stage[main]//Exec[apt-update]/returns: executed successfully notice: /Stage[main]//File[ /var/lib/tomcat7/conf/context.xml]/ content: content changed ’{md5}4861cda2bbf3a56fbfdb78622c550019’ to ’{md5}8365f14d15ddf99b1d20f9672f0b98c7’ notice: /Stage[main]//File[ /var/lib/tomcat7/webapps/ devopsnapratica.war]/ensure: defined content as ’{md5}cba179ec04e75ce87140274b0aaa2263’ notice: /Stage[main]//Service[tomcat7]: Triggered ’refresh’ from 2 events notice: Finished catalog run in 21.78 seconds Tente agora acessar a URLhttp://192.168.33.13:8080/devopsnapratica/no seu navegador para ver que a loja está funcionando corretamente. Sucesso!
Agora que sabemos recriar o servidorwebpor completo, podemos nos
Página 107
Casa do Código Capítulo 4. Infraestrutura como código livrar da máquina virtualweb2. Para demonstrar o poder do uso de automa- ção para provisionamento edeploy, vamos também destruir a máquina virtual webe recriá-la do zero:
$ vagrant destroy web web2 web2: Are you sure you want to destroy the ’web2’ VM?[y/N] y ==> web2: Forcing shutdown of VM…
==> web2: Destroying VM and associated drives…
==> web2: Running cleanup tasks for ’puppet’ provisioner…
web: Are you sure you want to destroy the ’web’ VM? [y/N] y ==> web: Forcing shutdown of VM…
==> web: Destroying VM and associated drives…
Antes de reiniciar a máquina virtual novamente, precisamos atualizar o arquivo de configuraç ão do Vagrant – oVagrantfile– para conter apenas um servidorweb:
VAGRANTFILE_API_VERSION="2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do|config| config.vm.box ="hashicorp/precise32"
config.vm.define :dbdo|db_config| db_config.vm.network :private_network, :ip=>"192.168.33.10"
db_config.vm.provision "puppet"do|puppet| puppet.manifest_file ="db.pp"
end end config.vm.define :webdo|web_config| web_config.vm.network :private_network, :ip=>"192.168.33.12"
web_config.vm.provision "puppet"do|puppet| puppet.manifest_file ="web.pp"
end end config.vm.define :monitordo|monitor_config|
Página 108
4.6. Fazendo deploy da aplicaç ão Casa do Código monitor_config.vm.network, :ip end end O último passo é reconstruir a máquina virtualwebdo zero:
$ vagrant up web Bringing machine ’web’ up with ’virtualbox’ provider…
==> web: Importing base box ’hashicorp/precise32’…
==> web: Matching MAC address for NAT networking…
==> web: Checking if box ’hashicorp/precise32’ is up to date…
==> web: Setting the name of the VM:
blank_web_1394856878524_4521 ==> web: Fixed port collision for 22 => 2222. Now on port 2200.
==> web: Clearing any previously set network interfaces…
==> web: Preparing network interfaces based on configuration…
web: Adapter 1: nat web: Adapter 2: hostonly ==> web: Forwarding ports…
web: 22 => 2200 (adapter 1) ==> web: Running ’pre-boot’ VM customizations…
==> web: Booting VM…
==> web: Waiting for machine to boot. This may take a few minutes…
web: SSH address: 127.0.0.1:2200 web: SSH username: vagrant web: SSH auth method: private key ==> web: Machine booted and ready!
==> web: Configuring and enabling network interfaces…
==> web: Mounting shared folders…
web: /vagrant => /private/tmp/blank web: /tmp/vagrant-puppet-2/manifests => /private/tmp/blank/manifests ==> web: Running provisioner: puppet…
Running Puppet with web.pp…
stdin: is not a tty notice: /Stage[main]//Exec[apt-update]/returns: executed successfully notice: /Stage[main]//Package[mysql-client]/ensure: ensure
Página 109
Casa do Código Capítulo 4. Infraestrutura como código changed ’purged’ to ’present’ notice: /Stage[main]//Package[tomcat7]/ensure: ensure changed ’purged’ to ’present’ notice: /Stage[main]//File[ /var/lib/tomcat7/conf/context.xml]/ content: content changed ’{md5}4861cda2bbf3a56fbfdb78622c550019’ to ’{md5}8365f14d15ddf99b1d20f9672f0b98c7’ notice: /Stage[main]//File[ /var/lib/tomcat7/conf/server.xml]/ content: content changed ’{md5}523967040584a921450af2265902568d’ to ’{md5}e4f0d5610575a720ad19fae4875e9f2f’ notice: /Stage[main]//File[ /var/lib/tomcat7/conf/.keystore]/ ensure: defined content as ’{md5}80792b4dc1164d67e1eb859c170b73d6’ notice: /Stage[main]//File[ /var/lib/tomcat7/webapps/ devopsnapratica.war]/ensure: defined content as ’{md5}cba179ec04e75ce87140274b0aaa2263’ notice: /Stage[main]//File[ /etc/default/tomcat7]/content:
content changed ’{md5}49f3fe5de425aca649e2b69f4495abd2’ to ’{md5}1f429f1c7bdccd3461aa86330b133f51’ notice: /Stage[main]//Service[tomcat7]: Triggered ’refresh’ from 5 events notice: Finished catalog run in 106.31 seconds Pronto! Conseguimos reconstruir o servidorwebe fazerdeployda loja virtualem 1 minuto!
A verificaç ão do Nagios deve ficar verde e a loja virtual está novamente acessível para nossos usuários. A versão final do manifestoweb.pp, ao final deste capítulo, ficou:
exec{"apt-update":
command =>"/usr/bin/apt-get update"
} package{ ["mysql-client", "tomcat7"]:
ensure =>installed, require =>Exec["apt-update"], }
Página 110
4.6. Fazendo deploy da aplicaç ão Casa do Código file:
owner => root, group => tomcat7, mode => 0640, source =>, require =>["tomcat7"], notify["tomcat7"], } file:
owner => root, group => tomcat7, mode => 0644, source =>, require =>["tomcat7"], notify["tomcat7"], } file:
owner => root, group => root, mode => 0644, source =>, require =>["tomcat7"], notify["tomcat7"], } service:
ensure =>, enable =>, hasstatus =>true, hasrestart =>true, require => Package["tomcat7"], } $db_host ="192.168.33.10"
$db_schema="loja_schema"
$db_user ="loja"
Página 111
Casa do Código Capítulo 4. Infraestrutura como código $db_password file:
owner => root, group => tomcat7, mode => 0644, content =>("/vagrant/manifests/context.xml"), require =>["tomcat7"], notify["tomcat7"], } file:
owner => tomcat7, group => tomcat7, mode => 0644, source =>, require =>["tomcat7"], notify["tomcat7"], } Investir em automaç ão nos permitiu destruir e reconstruir servidores em questão de minutos. Você também deve ter percebido que passamos muito pouco tempo executando comandos manuais dentro dos servidores. Trans- ferimos a responsabilidade de execuç ão de comandos para o Puppet e decla- ramos o estado final desejado em arquivos de manifesto.
O código do Puppet está começando a crescer e não temos uma estrutura clara para organizar os arquivos de manifesto e ostemplates. Também estamos tratando o artefato.warcomo um arquivo estático, algo que sabemos não ser ideal. Nos próximos capítulos iremos revisitar essas decisões e criar um ecossistema mais robusto para entrega contínua da loja virtual.
Página 112
Página 113
Capítulo5 Puppetalémdobásico No final do capítulo4, o código Puppet para configurar a infraestrutura da loja virtual não está muito bem organizado. A única separaç ão que fizemos foi criar dois arquivos de manifesto, um para cada servidor:webedb. No entanto, dentro de cada arquivo, o código é simplesmente uma lista de re- cursos. Além disso, os arquivos de configuraç ão e detemplatesestão jogados sem nenhuma estrutura. Neste capítulo vamos aprender novos conceitos e funcionalidades do Puppet ao mesmo tempo que refatoramos o código para torná-lo mais idiomático e bem organizado.
5.1 Classes e tipos definidos O Puppet gerencia uma única instância de cada recurso definido em um ma- nifesto, tornando-os uma espécie desingleton. Da mesma forma, uma classe é uma coleção de recursos únicos em seu sistema. Se você conhece lingua-
Página 114
5.1. Classes e tipos definidos Casa do Código gens orientadas a objetos, não se confunda com a terminologia. Uma classe no Puppet não pode ser instanciada diversas vezes. Classes são apenas uma forma de dar nome a uma coleção de recursos que serão aplicados como uma unidade.
Um bom uso de classes no Puppet é para configuraç ão de serviços que você precisa instalar apenas uma vez no sistema. Por exemplo, no arquivo db.ppinstalamos e configuramos o servidor MySQL e criamos oschemae o usuário específicos da loja virtual. Na vida real, podemos ter váriosschemase usuários usando o mesmo banco de dados, porém não instalamos mais de um MySQL por sistema. O servidor MySQL é um bom candidato para definirmos em uma classe genérica, que chamaremos demysql-server. Refatorando nosso arquivodb.pppara declarar e usar a nova classe, teremos:
classmysql-server{ exec {"apt-update": … } package{"mysql-server": … } file {"/etc/mysql/conf.d/allow_external.cnf": … } service{"mysql": … } exec {"remove-anonymous-user": … } } includemysql-server exec{"loja-schema": …, require =>Class["mysql-server"], } exec{"loja-user": … } Perceba que movemos o recursoExec["remove-anonymous-user"] – que remove a conta de acesso anônima – para dentro da classe mysql-serverpois isso é algo que deve acontecer somente quando o ser- vidor MySQL é instalado pela primeira vez. Outra mudança que você pode perceber é que o recursoExec["loja-schema"] agora tem uma depen- dência comClass["mysql-server"] em vez de um recurso específico Service["mysql"]como anteriormente. Essa é uma forma de encapsular detalhes de implementaç ão dentro da classe, isolando esse conhecimento do resto do código, que pode declarar dependências em coisas mais abstratas e
JIM – Assistente
Jim IA: pode errar. Não digite dados pessoais. Suas mensagens são processadas por um serviço externo.
Deixe um comentário