Como criar livros de receitas simples do chef para gerenciar a infraestrutura no Ubuntu
Introdução
O Chef é um sistema de gerenciamento de configuração projetado para permitir que você automatize e controle um grande número de computadores de maneira automatizada, confiável e escalável.
Em tutoriais anteriores, vimos alguns Chef 11). Neste guia, usaremos esses guias como um ponto de partida para começar a falar sobre como automatizar seu ambiente.
Neste artigo, discutiremos os fundamentos da criação de um livro de receitas do Chef. Os livros de receitas são as unidades de configuração que nos permitem configurar e executar tarefas específicas no Chef em nossos nós remotos. Construímos livros de receitas e, em seguida, informamos ao Chef quais nós queremos executar as etapas descritas no livro de receitas.
Neste guia, assumiremos que você está começando com as três máquinas com as quais terminamos a última lição. Você deve ter um servidor, uma estação de trabalho e pelo menos um nó para o qual enviar as alterações de configuração.
Conceitos básicos do livro de receitas
Os livros de receitas servem como a unidade fundamental de detalhes de configuração e política que o Chef usa para colocar um nó em um estado específico. Isso significa apenas que o Chef usa livros de receitas para executar o trabalho e garantir que as coisas estejam como deveriam estar no nó.
Os livros de receitas geralmente são usados para lidar com um serviço, aplicativo ou funcionalidade específica. Por exemplo, um livro de receitas pode ser criado para usar o NTP para definir e sincronizar o horário do nó com um servidor específico. Ele pode instalar e configurar um aplicativo de banco de dados. Livros de receitas são basicamente pacotes para escolhas de infraestrutura.
Os livros de receitas são criados na estação de trabalho e, em seguida, carregados em um servidor Chef. A partir daí, receitas e políticas descritas no livro de receitas podem ser atribuídas a nós como parte da lista de execução do nó. Uma lista de execução é uma lista sequencial de receitas e funções executadas em um nó pelo chef-cliente em para colocar o nó em conformidade com a política que você definiu para ele.
Dessa forma, os detalhes de configuração que você escreve em seu livro de receitas são aplicados aos nós que você deseja aderir ao cenário descrito no livro de receitas.
Os livros de receitas são organizados em uma estrutura de diretório totalmente independente. Existem muitos diretórios e arquivos diferentes que são usados para finalidades diferentes. Vamos ver alguns dos mais importantes agora.
receitas
Uma receita é o principal burro de carga do livro de receitas. Um livro de receitas pode conter mais de uma receita ou depender de receitas externas. As receitas são usadas para declarar o estado de diferentes recursos.
Os recursos do Chef descrevem uma parte do sistema e seu estado desejado. Por exemplo, um recurso pode dizer o pacote x deve ser instalado. Outro recurso pode dizer o serviço x deve estar em execução.
Uma receita é uma lista de recursos relacionados que informam ao Chef como o sistema deve ser se ele implementar a receita. Quando o Chef executa a receita, ele verifica cada recurso quanto à conformidade com o estado declarado. Se o sistema corresponder, ele passa para o próximo recurso, caso contrário, ele tenta mover o recurso para o estado especificado.
Os recursos podem ser de muitos tipos diferentes. Você pode aprender sobre os diferentes tipos de recursos aqui. Alguns comuns são:
- pacote: usado para gerenciar pacotes em um nó
- serviço: usado para gerenciar serviços em um nó
- usuário: Gerencie usuários no nó
- grupo: Gerenciar grupos
- modelo: gerencie arquivos com modelos ruby incorporados
- cookbook_file: transfere arquivos do subdiretório de arquivos no livro de receitas para um local no nó
- arquivo: Gerencie o conteúdo de um arquivo no nó
- diretório: Gerenciar diretórios no nó
- execute: Executa um comando no nó
- cron: Edite um arquivo cron existente no nó
Atributos
Os atributos no Chef são basicamente configurações. Pense neles como simples pares chave-valor para qualquer coisa que você queira usar em seu livro de receitas.
Existem vários tipos diferentes de atributos que podem ser aplicados, cada um com um nível diferente de precedência sobre as configurações finais sob as quais um nó opera. No nível do livro de receitas, geralmente definimos os atributos padrão do serviço ou sistema que estamos configurando. Estes podem ser substituídos posteriormente por valores mais específicos para um nó específico.
Ao criar um livro de receitas, podemos definir atributos para nosso serviço no subdiretório de atributos de nosso livro de receitas. Podemos então fazer referência a esses valores em outras partes do nosso livro de receitas.
arquivos
O subdiretório de arquivos dentro do livro de receitas contém todos os arquivos estáticos que colocaremos nos nós que usam o livro de receitas.
Por exemplo, quaisquer arquivos de configuração simples que provavelmente não modificaremos podem ser colocados, em sua totalidade, no subdiretório de arquivos. Uma receita pode então declarar um recurso que move os arquivos desse diretório para seu local final no nó.
Modelos
Os modelos são semelhantes aos arquivos, mas não são estáticos. Os arquivos de modelo terminam com a extensão .erb
, o que significa que eles contêm Ruby embutido.
Eles são usados principalmente para substituir valores de atributo no arquivo para criar a versão final do arquivo que será colocada no nó.
Por exemplo, se tivermos um atributo que define a porta padrão para um serviço, o arquivo de modelo pode chamar para inserir o atributo no ponto do arquivo onde a porta é declarada. Usando esta técnica, você pode facilmente criar arquivos de configuração, mantendo as variáveis reais que deseja alterar em outro lugar.
Metadados.rb
O arquivo metadata.rb é usado, não surpreendentemente, para gerenciar os metadados sobre um pacote. Isso inclui coisas como o nome do pacote, uma descrição, etc.
Ele também inclui coisas como informações de dependência, onde você pode especificar quais livros de receitas este livro de receitas precisa para operar. Isso permitirá que o servidor Chef crie a lista de execução para os nós corretamente e garanta que todas as partes sejam transferidas corretamente.
Crie um livro de receitas simples
Para demonstrar um pouco do fluxo de trabalho envolvido no trabalho com livros de receitas, criaremos nosso próprio livro de receitas. Este será um livro de receitas muito simples que instala e configura o servidor web Nginx em nosso nó.
Para começar, precisamos ir para nosso diretório ~/chef-repo
em nossa estação de trabalho:
cd ~/chef-repo
Uma vez lá, podemos criar um livro de receitas usando faca. Como mencionamos em guias anteriores, a faca é uma ferramenta usada para configurar a maioria das interações com o sistema do Chef. Podemos usá-lo para realizar trabalhos em nossa estação de trabalho e também para conectar-se ao servidor Chef ou a nós individuais.
A sintaxe geral para criar um livro de receitas é:
Como nosso livro de receitas lidará com a instalação e configuração do Nginx, nomearemos nosso livro de receitas apropriadamente:
knife cookbook create nginx
** Creating cookbook nginx
** Creating README for cookbook: nginx
** Creating CHANGELOG for cookbook: nginx
** Creating metadata for cookbook: nginx
O que a faca faz aqui é construir uma estrutura simples dentro de nosso diretório de livros de receitas para nosso novo livro de receitas. Podemos ver a estrutura do livro de receitas navegando no diretório cookbooks e no diretório com o nome do livro de receitas.
cd cookbooks/nginx
ls
attributes CHANGELOG.md definitions files libraries metadata.rb providers README.md recipes resources templates
Como você pode ver, isso criou uma estrutura de pastas e arquivos que podemos usar para construir nosso livro de receitas. Vamos começar com a maior parte da configuração, a receita.
Crie uma receita simples
Se formos para o subdiretório recipes
, podemos ver que já existe um arquivo chamado default.rb
dentro:
cd recipes
ls
default.rb
Esta é a receita que será executada se você fizer referência à receita \nginx. É aqui que adicionaremos nosso código.
Abra o arquivo com seu editor de texto:
nano default.rb
#
# Cookbook Name:: nginx
# Recipe:: default
#
# Copyright 2014, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
A única coisa que está neste arquivo atualmente é um cabeçalho de comentário.
Podemos começar planejando as coisas que precisam acontecer para que nosso servidor da web Nginx comece a funcionar da maneira que queremos. Fazemos isso configurando recursos. Os recursos não descrevem como fazer algo, eles simplesmente descrevem como uma parte do sistema deve parecer quando estiver completa.
Antes de tudo, obviamente precisamos garantir que o software esteja instalado. Podemos fazer isso criando um recurso \pacote primeiro.
package 'nginx' do
action :install
end
Este pequeno trecho de código define um recurso de pacote para o Nginx. A primeira linha começa com o tipo de recurso (pacote) e o nome do recurso (‘nginx’). O resto é um grupo de ações e parâmetros que declaram o que queremos que aconteça com o recurso.
Neste recurso, vemos action :install
. Esta linha informa ao Chef que o recurso que estamos descrevendo deve ser instalado. O nó que executa esta receita verificará se o Nginx está instalado. Se for, ele irá verificar isso na lista de coisas a fazer. Caso contrário, ele instalará o programa usando os métodos disponíveis no sistema do cliente e, em seguida, o desmarcará.
Depois de instalar o serviço, provavelmente queremos ajustar seu estado atual no nó. Por padrão, o Ubuntu não inicia o Nginx após a instalação, então vamos querer mudar isso:
service 'nginx' do
action [ :enable, :start ]
end
Aqui, vemos um recurso do tipo \service. Isso declara que para o componente de serviço Nginx (a parte que nos permite gerenciar o servidor com init ou upstart), queremos iniciar o serviço agora e também habilitar para iniciar automaticamente quando a máquina for reiniciada.
O recurso final que declararemos é o arquivo real que serviremos. Como este é apenas um arquivo simples que não modificaremos, podemos simplesmente declarar o local onde queremos o arquivo e dizer onde no livro de receitas obter o arquivo:
cookbook_file "/usr/share/nginx/www/index.html" do
source "index.html"
mode "0644"
end
Usamos o tipo de recurso \cookbook_file para informar ao Chef que este arquivo está disponível no próprio livro de receitas e pode ser transferido como está para o local. Em nosso exemplo, estamos transferindo um arquivo para a raiz do documento do Nginx.
No nosso caso, especificamos o nome do arquivo que estamos tentando criar na primeira linha. Na linha \source, informamos o nome do arquivo a ser procurado no livro de receitas. O Chef procura esse arquivo no subdiretório \files/default do livro de receitas.
A linha \mode define as permissões no arquivo que estamos criando. Nesse caso, estamos concedendo ao usuário root permissões de leitura e gravação e todos os demais permissões de leitura.
Salve e feche este arquivo quando terminar.
Criando o arquivo de índice
Como você viu acima, definimos um recurso \cookbook_file que deve mover um arquivo chamado \index.html para a raiz do documento no nó. Precisamos criar este arquivo.
Devemos colocar este arquivo no subdiretório \files/default do nosso livro de receitas. Acesse agora digitando:
cd ~/chef-repo/cookbooks/nginx/files/default
Dentro deste diretório, criaremos o arquivo que referenciamos:
nano index.html
Este arquivo será apenas um documento HTML realmente simples destinado a demonstrar que nossos recursos operaram da maneira que queríamos.
Cole isso no arquivo:
<html>
<head>
<title>Hello there</title>
</head>
<body>
<h1>This is a test</h1>
<p>Please work!</p>
</body>
</html>
Salve e feche o arquivo quando terminar.
Criar um Livro de Receitas Auxiliar
Antes de prosseguirmos, vamos resolver preventivamente um pequeno problema. Quando nosso nó tenta executar o livro de receitas que criamos como está agora, é provável que ele falhe.
Isso ocorre porque ele tentará instalar o Nginx dos repositórios do Ubuntu, e o banco de dados de pacotes em nosso nó provavelmente está desatualizado. Normalmente, executamos \sudo apt-get update antes de executar os comandos do pacote.
Para resolver esse problema, podemos criar um livro de receitas simples cujo único objetivo é garantir que o banco de dados do pacote seja atualizado.
Podemos fazer isso usando a mesma sintaxe de faca que usamos antes. Vamos chamar este livro de receitas de \apt:
knife cookbook create apt
Isso criará o mesmo tipo de estrutura de diretório que tínhamos quando começamos com nosso livro de receitas Nginx.
Vamos direto ao ponto e editar a receita padrão para o nosso novo livro de receitas.
nano ~/chef-repo/cookbooks/apt/recipes/default.rb
Neste arquivo, vamos declarar um recurso \execute\, que é simplesmente uma forma de definir um comando que queremos executar no nó.
Nosso recurso se parece com isso:
execute "apt-get update" do
command "apt-get update"
end
A primeira linha dá um nome para o nosso recurso. No nosso caso, estamos chamando o recurso assim para simplificar. Se o atributo \comando for definido (como fizemos), então este é o comando real que é executado.
Uma vez que estes são exatamente os mesmos, não importa nem um pouco.
Salve e feche o arquivo.
Agora que temos nosso novo livro de receitas, há várias maneiras de garantir a execução antes do nosso livro de receitas do Nginx. Poderíamos adicioná-lo à lista de execução do nó antes do livro de receitas do Nginx, mas também podemos vinculá-lo ao próprio livro de receitas do Nginx.
Esta é provavelmente a melhor opção porque não teremos que lembrar de adicionar o livro de receitas \apt antes do livro de receitas \nginx em cada nó que queremos configurar para o Nginx.
Precisamos ajustar algumas coisas no livro de receitas do Nginx para que isso aconteça. Primeiro, vamos abrir o arquivo de receita do Nginx novamente:
nano ~/chef-repo/cookbooks/nginx/recipes/default.rb
No topo deste livro de receitas, antes dos outros recursos que definimos, podemos ler na receita padrão \apt digitando:
pacote 'nginx' fazer
serviço 'nginx' fazer
cookbook_file \/usr/share/nginx/www/index.html do
Salve e feche o arquivo.
O outro arquivo que precisamos editar é o arquivo metadata.rb
. Este arquivo é verificado quando o servidor do Chef envia a lista de execução para o nó, para ver quais outras receitas devem ser adicionadas à lista de execução.
Abra o arquivo agora:
nano ~/chef-repo/cookbooks/nginx/metadata.rb
Na parte inferior do arquivo, você pode adicionar esta linha:
depende de \apt”
Com isso concluído, nosso livro de receitas do Nginx agora conta com nosso livro de receitas apt para cuidar da atualização do banco de dados do pacote.
Adicione o livro de receitas ao seu nó
Agora que nossos livros de receitas básicos estão completos, podemos carregá-los em nosso servidor chef.
Podemos fazer isso individualmente digitando:
knife cookbook upload apt
knife cookbook upload nginx
Ou podemos carregar tudo digitando:
knife cookbook upload -a
De qualquer forma, nossas receitas serão carregadas no servidor do Chef.
Agora, podemos modificar a lista de execução de nossos nós. Podemos fazer isso facilmente digitando:
Se você precisar encontrar o nome de seus nós disponíveis, digite:
knife node list
client1
Para nossos propósitos, quando digitamos isso, obtemos um arquivo parecido com este:
knife node edit client1
{
"name": "client1",
"chef_environment": "_default",
"normal": {
"tags": [
]
},
"run_list": [
]
}
Você pode precisar definir sua variável de ambiente EDITOR antes que isso funcione. Você pode fazer isso digitando:
Como você pode ver, este é um documento JSON simples que descreve alguns aspectos do nosso node. Podemos ver um array \run_list, que está vazio no momento.
Podemos adicionar nosso livro de receitas Nginx a esse array usando o formato:
Quando terminarmos, nosso arquivo deve ficar assim:
{
"name": "client1",
"chef_environment": "_default",
"normal": {
"tags": [
]
},
"run_list": [
"recipe[nginx]"
]
}
Salve e feche o arquivo para implementar as novas configurações.
Agora, podemos SSH em nosso nó e executar o software cliente Chef. Isso fará com que o cliente faça check-in no servidor Chef. Depois de fazer isso, ele verá a nova lista de execução que foi atribuída a ele.
SSH em seu nó e, em seguida, execute isto:
sudo chef-client
Starting Chef Client, version 11.8.2
resolving cookbooks for run list: ["nginx"]
Synchronizing Cookbooks:
- apt
- nginx
Compiling Cookbooks...
Converging 4 resources
Recipe: apt::default
* execute[apt-get update] action run
- execute apt-get update
Recipe: nginx::default
* package[nginx] action install (up to date)
* service[nginx] action enable
- enable service service[nginx]
* service[nginx] action start (up to date)
* cookbook_file[/usr/share/nginx/www/index.html] action create (up to date)
Chef Client finished, 2 resources updated
Como você pode ver, nosso livro de receitas apt também foi enviado e executado, embora não estivesse na lista de execução que criamos. Isso ocorre porque o Chef resolveu de forma inteligente as dependências e modificou a lista de execução real antes de executá-la no nó.
Nota: Existem vários métodos para garantir que um livro de receitas ou receita seja executado antes de outro. Adicionar uma dependência é apenas uma escolha e outros métodos podem ser preferidos.
Podemos verificar se isso funciona acessando o endereço IP ou nome de domínio do nosso nó:
Você deve ver algo parecido com isto:
Parabéns, você configurou seu primeiro nó usando os livros de receitas do Chef!
Conclusão
Embora este tenha sido um exemplo muito simples que provavelmente não economizou muito tempo ao configurar seu servidor manualmente, esperamos que você possa começar a ver as possibilidades desse método de construção de infraestrutura.
Ele não apenas permite a rápida implantação e configuração de diferentes tipos de servidores, mas também garante que você conheça a configuração exata de todas as suas máquinas. Isso permite que você valide e teste sua infraestrutura e também fornece a estrutura necessária para reimplantar rapidamente sua infraestrutura por capricho.