OpenVox: Gestão de Configuração em Linux

Numa PME com cinco ou mais servidores Linux, o padrão é quase sempre o mesmo: cada máquina foi montada à mão, com pacotes instalados por SSH e configurações ajustadas ficheiro a ficheiro. Passado um ano, dois servidores que deviam ser iguais já não o são. Um pacote actualizado aqui, uma linha acrescentada ali, e ninguém sabe ao certo o que corre em produção. É a deriva de configuração, e explica metade dos mistérios que surgem quando algo falha.

O OpenVox ataca o problema por outra via: em vez de descreveres os passos para instalar um serviço, descreves o estado desejado. O pacote ntpsec deve estar instalado, o ficheiro /etc/ntpsec/ntp.conf deve ter um certo conteúdo, o serviço deve estar a correr e activado no arranque. Um agente em cada servidor consulta um servidor central a cada 30 minutos, recebe a lista de diferenças e corrige o que for preciso, sem intervenção humana. Se alguém editar um ficheiro à mão e o partir, o ciclo seguinte repõe o estado correcto.

Duas notas antes de começar. No universo Puppet há o Puppet Enterprise, a edição paga da Perforce com consola web e orquestração, e houve um Puppet Open Source clássico, descontinuado no fim de 2024. A comunidade Vox Pupuli mantém o fork OpenVox, que é drop-in do Puppet 8: os comandos e os caminhos de configuração são os mesmos (puppet, puppetserver, /etc/puppetlabs/). É o OpenVox que serve de base a este tutorial, porque é a via livre activa em 2026. Duas ressalvas da documentação antes de migrar: faz backup da árvore /etc/puppetlabs/ e testa a migração — os pacotes OpenVox desinstalam e substituem os do Puppet, e os dois não podem estar instalados em simultâneo no mesmo sistema. Se o teu parque já tem Puppet da Perforce, tudo o que se segue aplica-se da mesma forma.

Neste artigo:

  1. Como o OpenVox funciona
  2. Instalar o servidor
  3. Primeiro agente
  4. O primeiro manifest
  5. Módulos e o Puppet Forge
  6. Facts e Hiera
  7. Ambiente prod/dev
  8. Diagnóstico
  9. Erros Comuns
  10. Checklist
  11. Artigos Relacionados
  12. Fontes Oficiais

1. Como o OpenVox funciona

A lógica é declarativa: escreves o estado final pretendido, nunca os comandos para lá chegar. O motor compara o estado actual do sistema com o desejado e aplica apenas as diferenças. Executar o mesmo manifest duas vezes seguidas não repete nada, o que torna as execuções seguras e repetíveis.

A arquitectura tem duas peças. O servidor (pacote openvox-server, equivalente ao puppetserver) guarda os manifests, os módulos e os dados, e responde aos agentes na porta 8140, por HTTPS. Em cada máquina gerida corre o agente (pacote openvox-agent), um serviço que por omissão aplica um ciclo a cada 30 minutos (parâmetro runinterval). Em cada ciclo, o agente recolhe os facts do sistema — distribuição, família de sistema operativo, endereço IP, memória — e envia-os ao servidor. Este compila o catálogo da máquina: a lista de recursos (packages, ficheiros, serviços) com os valores que cada um deve ter. O agente aplica o catálogo localmente, corrige só o que difere e devolve um relatório.

Os manifests escrevem-se no Puppet DSL, em ficheiros .pp organizados em classes e módulos. Os dados que variam de nó para nó ficam no Hiera. Toda a comunicação usa certificados emitidos pela CA que o próprio servidor traz consigo: no primeiro contacto, o agente gera um pedido de certificado que assinas no servidor, uma única vez por máquina.

Diagrama oficial da arquitectura Puppet, modelo que o OpenVox mantém: o primary server contém a codebase com Puppet Code e Hiera Data e compila catálogos no Puppet Server; o PuppetDB guarda os dados; dois Puppet Agent com Facter recebem os catálogos
Arquitectura Puppet/OpenVox (documentação oficial do Puppet, que o OpenVox segue): o primary server guarda código e dados Hiera e compila catálogos; o PuppetDB persiste facts e relatórios; os agentes recolhem facts com o Facter e aplicam os catálogos localmente.

2. Instalar o servidor

A Vox Pupuli publica pacotes para Debian e Ubuntu no apt.voxpupuli.org. No servidor (Ubuntu 24.04 no exemplo):

sudo wget https://apt.voxpupuli.org/openvox8-release-ubuntu24.04.deb
sudo dpkg -i openvox8-release-ubuntu24.04.deb
sudo apt-get update
sudo apt-get install -y openvox-server

Em Debian 12 o pacote do repositório é openvox8-release-debian12.deb. Confirma sempre o ficheiro do teu codename na página do apt.voxpupuli.org antes de descarregar.

O servidor é uma aplicação Java. O ficheiro /etc/default/puppetserver tem a linha JAVA_ARGS com os limites de memória da JVM (-Xms e -Xmx). A documentação oficial estima cerca de 512 MB de RAM por instância JRuby em actividade, mais uns 512 MB para o resto do processo. Numa VM pequena podes fixar JAVA_ARGS=”-Xms1g -Xmx1g” e reduzir o max-active-instances em /etc/puppetlabs/puppetserver/puppetserver.conf para 1. São estimativas: o consumo real depende do número de agentes, da dimensão dos módulos e catálogos, dos dados Hiera e das execuções simultâneas. Em produção, dimensiona medindo, não pelo valor de partida.

Antes do primeiro arranque, cria a autoridade certificadora (CA). O comando prepara a CA por omissão, com certificado raiz e intermédio:

sudo puppetserver ca setup
sudo systemctl start puppetserver
sudo systemctl enable puppetserver
sudo puppetserver ca list --all

Saída representativa de um servidor recém-instalado:

Signed Certificates:
Unsigned Certificates:

A lista vazia é normal: ainda nenhum agente pediu certificado.

3. Primeiro agente

No cliente Linux, instala o agente a partir do mesmo repositório:

sudo wget https://apt.voxpupuli.org/openvox8-release-ubuntu24.04.deb
sudo dpkg -i openvox8-release-ubuntu24.04.deb
sudo apt-get update
sudo apt-get install -y openvox-agent

Por omissão, o agente procura um servidor com o nome puppet no DNS. Se o teu servidor se chamar de outra forma, indica-o em /etc/puppetlabs/puppet/puppet.conf:

[agent]
server = puppet.pme.local

A primeira execução é manual e gera o pedido de certificado:

sudo puppet agent -t

Como o certificado ainda não foi assinado, a execução termina com um erro — saída representativa:

Info: Creating a new SSL key for cliente01
Info: Creating a new SSL certificate request for cliente01
Info: Certificate Request fingerprint (SHA256): 4A:9B:C1:77:F2:E0:11:3D:D8:5A:60:2C:BE:14:9F:71:35:08:D2:6E:1C:44:AA:F3:B9:52:07:8D:63:E1:2B:C5
Exiting; no certificate found and waitforcert is disabled

No servidor, lista os pedidos e assina o do agente — a impressão digital SHA256 deve coincidir com a que o agente mostrou:

sudo puppetserver ca list --all
sudo puppetserver ca sign --certname cliente01

De volta ao cliente, o mesmo comando corre agora o primeiro ciclo completo:

sudo puppet agent -t

Saída representativa de uma primeira execução bem-sucedida, ainda sem manifests a aplicar:

Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for cliente01
Info: Applying configuration version '1758792000'
Notice: Applied catalog in 0.28 seconds

A partir daqui, o serviço do agente repete o ciclo a cada 30 minutos. Quando quiseres aplicar uma alteração de imediato, corre puppet agent -t à mão.

4. O primeiro manifest

Os manifests vivem em /etc/puppetlabs/code/environments/production/. O ponto de entrada é o site.pp, na subdirectoria manifests/:

sudo mkdir -p /etc/puppetlabs/code/environments/production/modules/base/manifests
sudo nano /etc/puppetlabs/code/environments/production/manifests/site.pp
node default {
  include base
}

O bloco node default aplica-se a qualquer máquina sem regra própria, pelo que os agentes novos ficam logo cobertos. O módulo base declara três recursos: um pacote, um ficheiro e um serviço. Em modules/base/manifests/init.pp:

class base {
  package { 'ntpsec':
    ensure => installed,
  }
  file { '/etc/ntpsec/ntp.conf':
    mode    => '0644',
    content => "server 0.pt.pool.ntp.org iburst\nserver 1.pt.pool.ntp.org iburst\n",
    require => Package['ntpsec'],
    notify  => Service['ntpsec'],
  }
  service { 'ntpsec':
    ensure  => running,
    enable  => true,
    require => File['/etc/ntpsec/ntp.conf'],
  }
}

Repara nos require e no notify: por omissão, a ordem entre recursos distintos não é garantida, e o metaparâmetro require declara que um recurso só se aplica depois de outro estar resolvido — o equivalente inverso é before. O notify no ficheiro faz o serviço ser reiniciado sempre que o conteúdo muda numa execução posterior; sem ele, um ficheiro alterado não reiniciava o serviço que já estava a correr. O exemplo usa o ntpsec porque é isso que o Ubuntu 24.04 traz: o pacote ntp é de transição e instala o ntpsec, com configuração em /etc/ntpsec/ntp.conf e serviço ntpsec — os caminhos clássicos /etc/ntp.conf e serviço ntp já não se aplicam a esta versão.

Na próxima execução do agente, o catálogo aplica as três alterações — saída representativa:

Notice: /Stage[main]/Base/Package[ntpsec]/ensure: created
Notice: /Stage[main]/Base/File[/etc/ntpsec/ntp.conf]/content: content changed '{md5}a13b8f2c...' to '{md5}91cf7d04...'
Notice: /Stage[main]/Base/Service[ntpsec]/ensure: ensure changed 'stopped' to 'running'
Notice: /Stage[main]/Base/Service[ntpsec]: Triggered 'refresh' from 1 event
Notice: Applied catalog in 2.51 seconds

Na passagem seguinte, sem nada a fazer, a saída resume-se a uma linha Applied catalog. É esta idempotência que torna o OpenVox seguro para repetir.

5. Módulos e o Puppet Forge

Escrever tudo à mão escala mal. O Puppet Forge é o repositório público de módulos da comunidade, com milhares de módulos para serviços comuns: ntp, apache, postgresql, docker, fail2ban. Os módulos do Forge funcionam no OpenVox sem alterações. Para instalar o módulo oficial do NTP:

cd /etc/puppetlabs/code/environments/production
sudo puppet module install puppetlabs-ntp

Saída representativa:

Notice: Preparing to install into /etc/puppetlabs/code/environments/production/modules ...
Notice: Downloading from https://forgeapi.puppet.com ...
Notice: Installing -- do not interrupt ...
/etc/puppetlabs/code/environments/production/modules
└── puppetlabs-ntp (v11.2.0)

O módulo traz uma classe pronta a usar, que já trata das diferenças entre Debian, Ubuntu e Red Hat:

class { 'ntp':
  servers => [ '0.pt.pool.ntp.org', '1.pt.pool.ntp.org' ],
}

Um módulo tem uma estrutura fixa: manifests/init.pp com a classe principal, files/ para ficheiros estáticos e templates/ para modelos. Em ambientes maiores, os módulos e as versões ficam declarados num Puppetfile e geridos por r10k, mas para começar o puppet module install chega. Antes de instalares um módulo, confere a compatibilidade com a tua versão do Puppet na página do módulo.

6. Facts e Hiera

Os facts são variáveis de leitura que o facter recolhe em cada ciclo. Acedes-lhes pelo hash $facts:

notice($facts['os']['family'])
notice($facts['networking']['ip'])

Com os facts escreves manifests que se adaptam ao sistema, por exemplo para escolher o pacote conforme a família da distribuição:

$pkg = $facts['os']['family'] ? {
  'RedHat' => 'chrony',
  default  => 'ntpsec',
}
package { $pkg:
  ensure => installed,
}

Os dados que variam por nó ou por ambiente ficam no Hiera, fora dos manifests. Um exemplo mínimo. Em /etc/puppetlabs/code/environments/production/hiera.yaml:

version: 5
defaults:
  datadir: data
  data_hash: yaml_data
hierarchy:
  - name: "Comum"
    path: "common.yaml"

Em data/common.yaml:

base::ntp_servers:
  - '0.pt.pool.ntp.org'
  - '1.pt.pool.ntp.org'

A classe passa a declarar o parâmetro, e o Hiera preenche-o automaticamente pelo nome base::ntp_servers:

class base (
  Array[String] $ntp_servers,
) {
  # usa $ntp_servers no conteúdo do ficheiro de configuração
}

Quando precisas de um valor fora de classes parametrizadas, a função lookup() vai buscá-lo ao Hiera: lookup(‘base::ntp_servers’). A regra prática: lógica nos manifests, dados no Hiera.

7. Ambiente prod/dev

O OpenVox organiza tudo em environments, subdirectorias independentes dentro de /etc/puppetlabs/code/environments/. A por omissão chama-se production. Cria ao lado uma development, com os mesmos manifests e módulos, e testa aí antes de publicar:

sudo puppet agent -t --environment development

Podes fixar o ambiente do agente em puppet.conf, na secção [agent], com environment = development. Cada ambiente tem os seus manifests, módulos e dados Hiera, pelo que um erro em development nunca chega às outras máquinas. Quando os testes passam, publica o conteúdo em production (idealmente via git, e não copiando ficheiros à mão).

Diagrama oficial dos environments do OpenVox: a pasta codedir/environments contém as subdirectorias production e test, cada uma com modules, manifests e environment.conf
Environments do OpenVox (documentação oficial): cada subdirectoria de codedir/environments é independente — modules, manifests e environment.conf próprios; production é a de origem.

8. Diagnóstico

Antes de aplicar mudanças, simula-as. A opção –noop percorre o catálogo e mostra o que mudaria, sem tocar no sistema:

sudo puppet agent -t --noop

Saída representativa de uma simulação:

Notice: /Stage[main]/Base/File[/etc/ntpsec/ntp.conf]/content: current_value '{md5}a13b8f2c...', should be '{md5}91cf7d04...' (noop)
Notice: Applied catalog in 0.09 seconds

Erros de sintaxe detectam-se sem servidor: puppet parser validate init.pp não devolve nada quando o ficheiro está correcto.

Quando algo falha, os logs do servidor ficam em /var/log/puppetlabs/puppetserver/puppetserver.log e os do agente saem no journal do systemd (journalctl -u puppet). Correr o agente à mão com puppet agent -t é a forma mais rápida de ver o erro completo no ecrã. Os espinhos mais comuns são: certificado do agente por assinar, DNS que não resolve o nome do servidor, relógio dessincronizado (os certificados SSL exigem horas certas) e ficheiros editados à mão que o OpenVox repõe no ciclo seguinte, que é exactamente o comportamento pretendido.

Erros Comuns

Erro Causa provável Resolução
Exiting; no certificate found Certificado do agente ainda por assinar sudo puppetserver ca sign --certname <nome> no servidor
Could not retrieve catalog from remote server Erro de sintaxe num manifest ou módulo puppet parser validate nos ficheiros e consulta ao log do servidor
Failed to open TCP connection ... :8140 Firewall ou DNS mal resolvido Abrir a porta 8140 e confirmar o parâmetro server em puppet.conf
Duplicate declaration: Class[X] is already declared Classe declarada duas vezes Usar include em vez de class { } repetido
Ficheiro editado à mão volta ao anterior Comportamento normal do agente Alterar o manifest (ou testar primeiro com –noop)
certificate verify failed após reinstalar o servidor Certificados antigos nos agentes Confirmar que a CA foi preservada, limpar só os certificados afectados com puppetserver ca clean — destrutivo, revoga o que remove — e assinar de novo

Checklist

  • [ ] O DNS interno resolve o nome do servidor OpenVox a partir de cada agente
  • [ ] A porta 8140 está aberta entre agentes e servidor
  • [ ] A memória da JVM está ajustada em /etc/default/puppetserver
  • [ ] A CA foi criada com puppetserver ca setup antes do primeiro arranque
  • [ ] Todos os certificados dos agentes estão assinados (puppetserver ca list –all)
  • [ ] Os manifests e módulos estão guardados em git
  • [ ] Os testes correm primeiro em development (puppet agent -t –environment development)
  • [ ] Antes de aplicar em produção, há sempre uma simulação com –noop
  • [ ] Os dados que variam por nó estão no Hiera, não escritos à mão nos manifests

Artigos Relacionados

Fontes Oficiais

  • Instalar OpenVox (guia oficial da Vox Pupuli): https://voxpupuli.org/openvox/install/
  • Repositório APT da Vox Pupuli (pacotes openvox8-release): https://apt.voxpupuli.org/
  • Documentação do Puppet 8 (língua, configuração, agente): https://www.puppet.com/docs/puppet/8/puppet_index.html
  • Comandos da CA (puppetserver ca): https://help.puppet.com/core/current/Content/PuppetCore/puppet_server_ca_cli.htm
  • Agente como serviço (runinterval, 30 minutos): https://help.puppet.com/core/current/Content/PuppetCore/nix_agent_as_service.htm
  • Guia de afinação do Puppet Server (memória JVM): https://help.puppet.com/core/current/Content/PuppetCore/server/tuning_guide.htm
  • Puppet Forge — módulo puppetlabs-ntp: https://forge.puppet.com/modules/puppetlabs/ntp