Em poucas palavras, o gerenciamento de configuração de servidor (também conhecido como IT Automation) é uma solução para transformar a sua administração de infraestrutura em uma base de código, descrevendo todos os processos necessários para fazer o deploy de um servidor em um conjunto de scripts de provisionamento que podem ser versionados e facilmente reutilizados. Isso pode melhorar muito a integridade de qualquer infraestrutura de servidor ao longo do tempo.
Em um guia anterior, falamos sobre os principais benefícios da implementação de uma estratégia de gerenciamento de configuração para a infraestrutura de servidor, como as ferramentas de gerenciamento de configuração funcionam e o que essas ferramentas têm em comum normalmente.
Esta parte da série o guiará pelo processo de automatização do provisionamento de servidores usando o Puppet, uma ferramenta popular de gerenciamento de configuração capaz de gerenciar infraestruturas complexas de maneira transparente, usando um servidor mestre ou master para orquestrar a configuração dos nodes. Vamos nos concentrar na terminologia da linguagem, sintaxe e recursos necessários para criar um exemplo simplificado para automatizar completamente o deployment de um servidor web Ubuntu 18.04 usando o Apache.
Esta é a lista de passos que precisamos automatizar para alcançar nosso objetivo:
apt
index.html
no document root personalizadoComeçaremos examinando a terminologia usada pelo Puppet, seguida de uma visão geral dos principais recursos da linguagem que podem ser usados para escrever manifests. No final deste guia, compartilharemos o exemplo completo para que você possa experimentar sozinho.
Nota: este guia pretende apresentar a linguagem do Puppet e como escrever manifests para automatizar o provisionamento de servidor. Para uma visão mais introdutória do Puppet, incluindo as etapas necessárias para instalar e começar com esta ferramenta, consulte a documentação oficial do Puppet.
Antes de podermos avançar para uma visão mais prática do Puppet, é importante nos familiarizarmos com importantes terminologias e conceitos introduzidos por esta ferramenta.
installed
O provisionamento no Puppet é escrito usando uma DSL (linguagem específica de domínio) personalizada baseada em Ruby.
Com o Puppet, as tarefas ou etapas são definidas declarando recursos. Os recursos podem representar pacotes, arquivos, serviços, usuários e comandos. Eles podem ter um estado, que acionará uma alteração no sistema caso o estado de um recurso declarado seja diferente do que está atualmente no sistema. Por exemplo, um recurso package definido como installed
no seu manifest acionará uma instalação do pacote no sistema se o pacote não tiver sido instalado anteriormente.
É assim que um recurso package se parece:
package { 'nginx':
ensure => 'installed'
}
Você pode executar qualquer comando arbitrário declarando um recurso exec
, como o seguinte:
exec { 'apt-get update':
command => '/usr/bin/apt-get update'
}
Observe que a parte apt-get update
na primeira linha não é a declaração de comando real, mas um identificador para este recurso exclusivo. Frequentemente, precisamos fazer referência a outros recursos de dentro de um recurso e usamos o identificador deles para isso. Nesse caso, o identificador é apt-get update
, mas poderia ser qualquer outra string.
Ao escrever manifests, é importante ter em mente que o Puppet não avalia os recursos na mesma ordem em que eles são definidos. Essa é uma fonte comum de confusão para quem está começando com o Puppet. Os recursos devem definir explicitamente a dependência entre si, caso contrário, não há garantia de qual recursos será avaliado e, consequentemente, executado primeiro.
Como um exemplo simples, digamos que você queira executar um comando, mas você precisa garantir que uma dependência seja instalada primeiro:
package { 'python-software-properties':
ensure => 'installed'
}
exec { 'add-repository':
command => '/usr/bin/add-apt-repository ppa:ondrej/php5 -y'
require => Package['python-software-properties']
}
A opção require
recebe como parâmetro uma referência a outro recurso. Neste caso, estamos nos referindo ao recurso Package identificado como python-software-properties
.
É importante notar que, enquanto usamos exec
, package
, e assim por diante para declarar recurso (com letras minúsculas), quando nos referimos a recurso definidos anteriormente, usamos Exec
, Package
e assim por diante (em maiúsculas).
Agora, digamos que você precise garantir que uma tarefa seja executada antes de outra. Para um caso como este, podemos usar a opção before
:
package { 'curl':
ensure => 'installed'
before => Exec['install script']
}
exec { 'install script':
command => '/usr/bin/curl http://example.com/some-script.sh'
Os manifests são basicamente uma coleção de declarações de recursos, usando a extensão .pp
. Abaixo você pode encontrar um exemplo de um playbook simples que executa duas tarefas: atualiza o cache do apt
e instala o vim
posteriormente:
exec { 'apt-get update':
command => '/usr/bin/apt-get update'
}
package { 'vim':
ensure => 'installed'
require => Exec['apt-get update']
}
Antes do final deste guia, veremos um exemplo mais real de um manifest, explicado em detalhes. A próxima seção fornecerá uma visão geral dos elementos e recursos mais importantes que podem ser usados para escrever manisfests do Puppet.
As variáveis podem ser definidas em qualquer ponto em um manifest. Os tipos mais comuns de variáveis são strings e matrizes ou arrays de strings, mas outros tipos também são suportados, como booleanos e hashes.
O exemplo abaixo define uma variável string que é usada posteriormente dentro de um recurso:
$package = "vim"
package { $package:
ensure => "installed"
}
Os loops são normalmente usados para repetir uma tarefa usando diferentes valores de entrada. Por exemplo, em vez de criar 10 tarefas para instalar 10 pacotes diferentes, você pode criar uma única tarefa e usar um loop para repetir a tarefa com todos os pacotes diferentes que deseja instalar.
A maneira mais simples de repetir uma tarefa com valores diferentes no Puppet é usando arrays, como no exemplo abaixo:
$packages = ['vim', 'git', 'curl']
package { $packages:
ensure => "installed"
}
A partir da versão 4, o Puppet suporta maneiras adicionais de iterar as tarefas. O exemplo abaixo faz a mesma coisa que o exemplo anterior, mas desta vez usando o iterador each
. Esta opção oferece mais flexibilidade para fazer um loop pelas definições de recursos:
$packages.each |String $package| {
package { $package:
ensure => "installed"
}
}
Condicionais podem ser usadas para decidir dinamicamente se um bloco de código deve ou não ser executado, com base em uma variável ou em uma saída de um comando, por exemplo.
O Puppet suporta a maioria das estruturas condicionais que você pode encontrar nas linguagens de programação tradicionais, como as instruções if/else
e case
. Além disso, alguns recursos como o exec
suportam atributos que funcionam como condicionais, mas aceitam apenas uma saída de comando como condição.
Digamos que você queira executar um comando com base em um fact. Nesse caso, como você deseja testar o valor de uma variável, é necessário usar uma das estruturas condicionais suportadas, como if/else
:
if $osfamily != 'Debian' {
warning('This manifest is not supported on this OS.')
}
else {
notify { 'Good to go!': }
}
Outra situação comum é quando você deseja condicionar a execução de um comando com base na saída de outro comando. Para casos como esse, você pode usar onlyif
ou unless
, como no exemplo abaixo. Este comando será executado apenas quando a saída de /bin/which php
for bem-sucedida, ou seja, o comando sair com o status 0:
exec { "Test":
command => "/bin/echo PHP is installed here > /tmp/test.txt",
onlyif => "/bin/which php"
}
Da mesma forma, unless
irá executar o comando o tempo todo, exceto quando o comando sob unless
sair com êxito:
exec { "Test":
command => "/bin/echo PHP is NOT installed here > /tmp/test.txt",
unless => "/bin/which php"
}
Os templates geralmente são usados para definir arquivos de configuração, permitindo o uso de variáveis e outros recursos destinados a tornar esses arquivos mais versáteis e reutilizáveis. O Puppet suporta dois formatos diferentes para templates: Embedded Puppet (EPP) e Embedded Ruby (ERB). O formato EPP, no entanto, funciona apenas com versões recentes do Puppet (a partir da versão 4.0).
Abaixo está um exemplo de um template ERB para configurar um virtual host no Apache, usando uma variável para configurar o document root para este host:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot <%= @doc_root %>
<Directory <%= @doc_root %>>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Para aplicar o template, precisamos criar um recurso file
que processe o conteúdo do template com o método template
. É assim que você aplicaria esse template para substituir o virtual host padrão do Apache:
file { "/etc/apache2/sites-available/000-default.conf":
ensure => "present",
content => template("apache/vhost.erb")
}
O Puppet faz algumas suposições ao lidar com arquivos locais, a fim de reforçar a organização e a modularidade. Nesse caso, o Puppet procuraria um arquivo de template vhost.erb
dentro de uma pasta apache/templates
, dentro do seu diretório de módulos.
Os recursos de serviço são usados para garantir que os serviços sejam inicializados e ativados. Eles também são usados para acionar a reinicialização do serviço.
Vamos levar em consideração o nosso exemplo anterior de uso de template, onde configuramos um virtual host no Apache. Se você deseja garantir que o Apache seja reiniciado após uma mudança no virtual host, primeiro crie um recurso service para o serviço Apache. É assim que esse recurso é definido no Puppet:
service { 'apache2':
ensure => running,
enable => true
}
Agora, ao definir o recurso, você precisa incluir uma opção notify
para acionar uma reinicialização:
file { "/etc/apache2/sites-available/000-default.conf":
ensure => "present",
content => template("vhost.erb"),
notify => Service['apache2']
}
Agora, vamos dar uma olhada em um manifest que automatizará a instalação de um servidor Web Apache em um sistema Ubuntu 14.04, conforme discutido na introdução deste guia.
O exemplo completo, incluindo o arquivo de template para configurar o Apache e um arquivo HTML para ser servido pelo servidor web, pode ser encontrado no Github. A pasta também contém um arquivo Vagrant que permite testar o manifest em uma configuração simplificada, usando uma máquina virtual gerenciada pelo Vagrant.
Abaixo você pode encontrar o manifest completo:
- $doc_root = "/var/www/example"
-
- exec { 'apt-get update':
- command => '/usr/bin/apt-get update'
- }
-
- package { 'apache2':
- ensure => "installed",
- require => Exec['apt-get update']
- }
-
- file { $doc_root:
- ensure => "directory",
- owner => "www-data",
- group => "www-data",
- mode => 644
- }
-
- file { "$doc_root/index.html":
- ensure => "present",
- source => "puppet:///modules/main/index.html",
- require => File[$doc_root]
- }
-
- file { "/etc/apache2/sites-available/000-default.conf":
- ensure => "present",
- content => template("main/vhost.erb"),
- notify => Service['apache2'],
- require => Package['apache2']
- }
-
- service { 'apache2':
- ensure => running,
- enable => true
- }
O manifest começa com uma definição de variável, $doc_root
. Essa variável é usada posteriormente em uma declaração de recurso.
Este recurso exec executa um comando apt-get update
.
Este recurso package instala o pacote apache2
, definindo que o recurso apt-get update
é um requisito, o que significa que ele só será executado após a avaliação do recurso necessário.
Utilizamos um recurso file aqui para criar um novo diretório que servirá como document root. O recurso file
pode ser usado para criar diretórios e arquivos, e também é usado para aplicar templates e copiar arquivos locais no servidor remoto. Esta tarefa pode ser executada em qualquer ponto do provisionamento, portanto, não precisamos definir nenhum require
aqui.
Usamos outro recurso file aqui, desta vez para copiar nosso arquivo index.html local para o document root dentro do servidor. Usamos o parâmetro source
para permitir que o Puppet saiba onde encontrar o arquivo original. Essa nomenclatura é baseada na maneira como o Puppet lida com arquivos locais; se você der uma olhada no repositório de exemplo do Github, você verá como a estrutura de diretórios deve ser criada para permitir que o Puppet encontre esse recurso. O diretório document root precisa ser criado antes da execução do recurso, e é por isso que incluímos uma opção require
que faz referência ao recurso anterior.
Um novo recurso file é usado para aplicar o template do Apache e notificar o serviço para uma reinicialização. Neste exemplo, nosso provisionamento é organizado em um módulo chamado main, e é por isso que a origem do template é main/vhost.erb. Usamos uma instrução require
para garantir que o recurso do template seja executado apenas após a instalação do pacote apache2
, caso contrário, a estrutura de diretórios usada pelo Apache ainda não estará presente.
Finalmente, o recurso service declara o serviço apache2
, que notificamos para reiniciar a partir do recurso que aplica o template de virtual host.
O Puppet é uma poderosa ferramenta de gerenciamento de configuração que usa uma DSL expressiva e personalizada para gerenciar recursos do servidor e automatizar tarefas. Sua linguagem oferece recursos avançados que podem dar flexibilidade extra às suas configurações de provisionamento; é importante lembrar que os recursos não são avaliados na mesma ordem em que são definidos e, por esse motivo, você precisa ter cuidado ao definir dependências entre os recursos para estabelecer a sequência de execução correta.
No próximo guia desta série, veremos o Chef, outra ferramenta poderosa de gerenciamento de configuração que aproveita a linguagem de programação Ruby para automatizar a administração e o provisionamento da infraestrutura.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!