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 Chef, uma poderosa ferramenta de gerenciamento de configuração que aproveita a linguagem de programação Ruby para automatizar a administração e o provisionamento da infraestrutura. 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 Chef, seguida de uma visão geral dos principais recursos da linguagem que podem ser usados para escrever recipes ou receitas. No final deste guia, compartilharemos o exemplo completo para que você possa experimentar sozinho.
Nota: este guia pretende apresentar a linguagem do Chef e como escrever receitas para automatizar o provisionamento de servidor. Para uma visão mais introdutória do Chef, incluindo as etapas necessárias para instalar e começar com esta ferramenta, consulte a documentação oficial do Chef.
Antes de podermos avançar para uma visão mais prática do Chef, é importante nos familiarizarmos com importantes terminologias e conceitos introduzidos por esta ferramenta.
As receitas do Chef são escritas usando Ruby. Uma receita é basicamente uma coleção de definições de recursos que criarão um conjunto passo a passo de instruções a serem executadas pelos nodes. Essas definições de recursos podem ser combinadas com o código Ruby para maior flexibilidade e modularidade.
Abaixo você pode encontrar um exemplo simples de uma receita que irá executar o apt-get update
e instalar o vim
posteriormente:
execute "apt-get update" do
command "apt-get update"
end
apt_package "vim" do
action :install
end
As variáveis locais podem ser definidas nas receitas como variáveis locais regulares do Ruby. O exemplo abaixo mostra como criar uma variável local que é usada posteriormente dentro de uma definição de recurso:
package = "vim"
apt_package package do
action :install
end
Essas variáveis, no entanto, têm um escopo limitado, sendo válidas apenas dentro do arquivo em que foram definidas. Se você deseja criar uma variável e disponibilizá-la globalmente, para poder usá-la em qualquer um dos seus cookbooks ou receitas, você precisa definir um atributo personalizado.
Os atributos representam detalhes sobre um node. O Chef possui atributos automáticos, que são os atributos coletados por uma ferramenta chamada Ohai e contêm informações sobre o sistema (como plataforma, nome do host e endereço IP padrão), mas também permitem definir seus próprios atributos personalizados.
Os atributos têm níveis de precedência diferentes, definidos pelo tipo de atributo que você cria. Os atributos default
são a escolha mais comum, pois ainda podem ser sobrescritos por outros tipos de atributos quando desejado.
O exemplo a seguir mostra como o exemplo anterior seria com um atributo de node default
em vez de uma variável local:
node.default['main']['package'] = "vim"
apt_package node['main']['package'] do
action :install
end
Há dois detalhes a serem observados neste exemplo:
A prática recomendada ao definir variáveis de node é organizá-las como hashes usando o cookbook atual em uso como chave. Nesse caso, usamos main
, porque temos um cookbook com o mesmo nome. Isso evita confusão se você estiver trabalhando com vários cookbooks que podem ter atributos com nomes semelhantes.
Observe que usamos node.default
ao definir o atributo, mas ao acessar seu valor posteriormente, usamos node
diretamente. O uso do node.default
define que estamos criando um atributo do tipo default. Esse atributo pode ter seu valor sobrescrito por outro tipo com precedência mais alta, como atributos normal ou override.
A precedência dos atributos pode ser um pouco confusa no início, mas você se acostumará com isso depois de alguma prática. Para ilustrar o comportamento, considere o seguinte exemplo:
node.normal['main']['package'] = "vim"
node.override['main']['package'] = "git"
node.default['main']['package'] = "curl"
apt_package node['main']['package'] do
action :install
end
Você sabe qual pacote será instalado neste caso? Se você achou que é o git
, adivinhou corretamente. Independentemente da ordem em que os atributos foram definidos, a maior precedência do tipo override
fará com que o node['main']['package']
seja avaliado como git
.
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.
O Chef suporta todas as estruturas de loop Ruby para criar loops dentro de receitas. Para uso simples, each
é uma escolha comum:
['vim', 'git', 'curl'].each do |package|
apt_package package do
action :install
end
end
Em vez de usar um array inline, você também pode criar uma variável ou atributo para definir os parâmetros que deseja usar dentro do loop. Isso manterá as coisas mais organizadas e fáceis de ler. Abaixo, o mesmo exemplo agora usando uma variável local para definir os pacotes que devem ser instalados:
packages = ['vim', 'git', 'curl']
packages.each do |package|
apt_package package do
action :install
end
end
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 Chef suporta todos as condicionais do Ruby para criar instruções condicionais nas receitas. Além disso, todos os tipos de recursos suportam duas propriedades especiais que avaliarão uma expressão antes de decidir se a tarefa deve ser executada ou não: if_only
e not_if
.
O exemplo abaixo verificará a existência do php
antes de tentar instalar a extensão php-pear
. Ele usará o comando which
para verificar se existe um executável php
atualmente instalado neste sistema. Se o comando which php
retornar falso, esta tarefa não será executada:
apt_package "php-pear" do
action :install
only_if "which php"
end
Se quisermos fazer o oposto, executando um comando o tempo todo exceto quando uma condição é avaliada como verdadeira, usamos not_if
. Este exemplo instalará o php5
, a menos que o sistema seja o CentOS:
apt_package "php5" do
action :install
not_if { node['platform'] == 'centos' }
end
Para realizar avaliações mais complexas, ou se você desejar executar várias tarefas sob uma condição específica, você pode usar qualquer uma das condicionais padrão do Ruby. O exemplo a seguir só executará apt-get update
quando o sistema for Debian ou Ubuntu:
if node['platform'] == 'debian' || node['platform'] == 'ubuntu'
execute "apt-get update" do
command "apt-get update"
end
end
O atributo node['platform']
é um atributo automático do Chef. O último exemplo foi apenas para demonstrar uma construção condicional mais complexa, no entanto, pode ser substituída por um teste simples usando o atributo automático node['platform_family']
, que retornaria “debian” para os sistemas Debian e Ubuntu.
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 Chef usa templates Embedded Ruby (ERB), que é o mesmo formato usado pelo Puppet. Eles suportam condicionais, loops e outros recursos do Ruby.
Abaixo está um exemplo de um modelo de ERB para configurar um virtual host no Apache, usando uma variável para definir o document root para esse 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 template
. É assim que você aplicaria esse template para substituir o virtual host padrão do Apache:
template "/etc/apache2/sites-available/000-default.conf" do
source "vhost.erb"
variables({ :doc_root => node['main']['doc_root'] })
action :create
end
O Chef faz algumas suposições ao lidar com arquivos locais, a fim de reforçar a organização e a modularidade. Nesse caso, o Chef procuraria um arquivo de template vhost.erb
dentro de uma pasta templates que deveria estar no mesmo cookbook em que esta receita está localizada.
Ao contrário das outras ferramentas de gerenciamento de configuração que vimos até agora, o Chef tem um escopo mais estrito para variáveis. Isso significa que você precisará fornecer explicitamente todas as variáveis que planeja usar dentro de um template, ao definir o recurso template
. Neste exemplo, usamos o método variables
para passar adiante o atributo doc_root
que precisamos no modelo de virtual host.
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.
No Chef, os recursos de serviço precisam ser declarados antes de você tentar notificá-los, caso contrário, você receberá um erro.
Vamos levar em consideração o nosso exemplo anterior de uso de templates, 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 Chef:
service "apache2" do
action [ :enable, :start ]
end
Agora, ao definir o recurso template, você precisa incluir uma opção notify
para acionar uma reinicialização:
template "/etc/apache2/sites-available/000-default.conf" do
source "vhost.erb"
variables({ :doc_root => node['main']['doc_root'] })
action :create
notifies :restart, resources(:service => "apache2")
end
Agora, vamos dar uma olhada em uma receita 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 a receita em uma configuração simplificada, usando uma máquina virtual gerenciada pelo Vagrant.
Abaixo você pode encontrar a receita completa:
- node.default['main']['doc_root'] = "/vagrant/web"
-
- execute "apt-get update" do
- command "apt-get update"
- end
-
- apt_package "apache2" do
- action :install
- end
-
- service "apache2" do
- action [ :enable, :start ]
- end
-
- directory node['main']['doc_root'] do
- owner 'www-data'
- group 'www-data'
- mode '0644'
- action :create
- end
-
- cookbook_file "#{node['main']['doc_root']}/index.html" do
- source 'index.html'
- owner 'www-data'
- group 'www-data'
- action :create
- end
-
- template "/etc/apache2/sites-available/000-default.conf" do
- source "vhost.erb"
- variables({ :doc_root => node['main']['doc_root'] })
- action :create
- notifies :restart, resources(:service => "apache2")
- end
-
A receita começa com uma definição de atributo, node['main']['doc_root']
. Poderíamos ter usado uma variável local simples aqui, no entanto, na maioria dos cenários de casos de uso, as receitas precisam definir variáveis globais que serão usadas nas receitas incluídas ou em outros arquivos. Para essas situações, é necessário criar um atributo em vez de uma variável local, pois a última possui um escopo limitado.
Esse recurso execute executa um apt-get update
.
Este recurso apt_package instala o pacote apache2
.
Este recurso service ativa e inicia o serviço apache2
. Posteriormente, precisaremos notificar esse recurso para reiniciar o serviço. É importante que a definição de serviço venha antes de qualquer recurso que tente notificar um serviço, caso contrário, você receberá um erro.
Este recurso directory usa o valor definido pelo atributo personalizado node['main']['doc_root']
para criar um diretório que servirá como nosso document root
Um recurso cookbook_file é usado para copiar um arquivo local em um servidor remoto. Este recurso copiará nosso arquivo index.html
e o colocará dentro do document root que criamos em uma tarefa anterior.
Por fim, esse recurso template aplica nosso template de virtual host do Apache e notifica o serviço apache2
para uma reinicialização.
O Chef é uma poderosa ferramenta de gerenciamento de configuração que utiliza a linguagem Ruby para automatizar o provisionamento e o deployment de servidores. Ele lhe oferece liberdade para usar os recursos de linguagem padrão para obter o máximo de flexibilidade, além de oferecer DSLs personalizadas para alguns recursos.
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!