pandoc Puppet_walkthrough.md -o puppet.pdf "-fmarkdown-implicit_figures -o" --from=markdown -V geometry:margin=.4in --toc --highlight-style=espress
pandoc --from markdown Puppet_walkthrough.md -o puppet.pdf
puppet
in Ruby geschrieben ist)
Näheres dazu unter puppetlabs_spec_helper.
Unit Tests
sind Tests, welche einzelne Funktionen / minimale Codeblöcke testenrspec-puppet
validiert, ob bestimmte Puppet Resourcen so im Katalog sind, wie man sie erwartet
Minimales Beispiel
# import a helper
require 'spec_helper'
# class we want to test
describe 'borg' do
# mock an FQDN
let :node do
'rspec.puppet.com'
end
let :facts do
{
"operatingsystem": "CentOS",
"operatingsystemmajversion": 7
}
end
# mock class params if required
# bad practice, a module should work with default data
let :params do
{
backupserver: 'localhost'
}
end
context 'with all defaults' do
it { is_expected.to compile.with_all_deps }
end
end
Prüfen der einzelnen Resources:
require 'spec_helper'
describe 'borg' do
let :node do
'rspec.puppet.com'
end
on_supported_os.each do |os, facts|
context "on #{os} " do
let :facts do
facts
end
let :params do
{
backupserver: 'localhost'
}
end
context 'with all defaults' do
it { is_expected.to compile.with_all_deps }
it { is_expected.to contain_file('/etc/backup-sh-conf.sh') }
it { is_expected.to contain_file('/etc/borg') }
it { is_expected.to contain_file('/etc/profile.d/borg.sh') }
it { is_expected.to contain_file('/usr/local/bin/borg-backup') }
it { is_expected.to contain_file('/usr/local/bin/borg_exporter') }
it { is_expected.to contain_file('/etc/borg-restore.cfg') }
it { is_expected.to contain_class('borg::install') }
it { is_expected.to contain_class('borg::config') }
it { is_expected.to contain_class('borg::service') }
it { is_expected.to contain_ssh__client__config__user('root') }
it { is_expected.to contain_borg__ssh_keygen('root_borg') }
it { is_expected.to contain_exec('ssh_keygen-root_borg') }
end
case facts[:os]['name']
when 'Archlinux'
context 'on Archlinux' do
it { is_expected.to contain_package('borg') }
it { is_expected.to contain_package('perl-app-borgrestore') }
end
when 'Ubuntu'
context 'on Ubuntu' do
it { is_expected.to contain_package('borgbackup') }
it { is_expected.to contain_package('borgbackup-doc') }
it { is_expected.to contain_package('gcc') }
it { is_expected.to contain_package('make') }
it { is_expected.to contain_package('cpanminus') }
it { is_expected.to contain_package('libdbd-sqlite3-perl') }
if facts[:os]['release']['major'] == '16.04'
it { is_expected.to contain_apt__ppa('ppa:costamagnagianfranco/borgbackup') }
end
end
when 'RedHat', 'CentOS'
context 'on osfamily Redhat' do
it { is_expected.to contain_package('perl-local-lib') }
it { is_expected.to contain_package('perl-Test-Simple') }
it { is_expected.to contain_package('perl-App-cpanminus') }
it { is_expected.to contain_package('gcc') }
it { is_expected.to contain_exec('install_borg_restore') }
it { is_expected.to contain_file('/opt/BorgRestore') }
it { is_expected.to contain_file('/usr/local/bin/borg-restore.pl') }
end
when 'Gentoo'
context 'on osfamily Gentoo' do
it { is_expected.to contain_package('App-cpanminus') }
end
when 'Fedora'
context 'on osfamily Fedora' do
it { is_expected.to contain_package('perl-Path-Tiny') }
it { is_expected.to contain_package('perl-Test-MockObject') }
it { is_expected.to contain_package('perl-Test') }
it { is_expected.to contain_package('perl-autodie') }
end
end
end
end
end
Quelle ist das puppet-borg modul
$facts
HashCentOS
vs centos
) in allen Modulen seinrspec-puppet-facts macht genau das!
require 'spec_helper'
describe 'borg' do
let :node do
'rspec.puppet.com'
end
on_supported_os.each do |os, facts|
context "on #{os} " do
let :facts do
facts
end
let :params do
{
backupserver: 'localhost'
}
end
context 'with all defaults' do
it { is_expected.to compile.with_all_deps }
end
end
end
end
Es ist wichtig das alle Betriebssysteme, auf denen ein Modul genutzt wird, auch in der metadata.json stehen!
Für alle genutzten Betriebssysteme sollten in dem Projekt factsets sein!
require 'spec_helper_acceptance'
describe 'zabbix::server class' do
context 'default parameters' do
# Using puppet_apply as a helper
it 'works idempotently with no errors' do
# this will actually deploy apache + postgres + zabbix-server + zabbix-web
pp = <<-EOS
class { 'postgresql::server': } ->
class { 'zabbix::database': } ->
class { 'zabbix::server': }
EOS
shell('yum clean metadata') if fact('os.family') == 'RedHat'
# Run it twice and test for idempotency
apply_manifest(pp, catch_failures: true)
apply_manifest(pp, catch_changes: true)
end
# do some basic checks
describe package('zabbix-server-pgsql') do
it { is_expected.to be_installed }
end
describe service('zabbix-server') do
it { is_expected.to be_running }
it { is_expected.to be_enabled }
end
end
end
Quelle der Tests ist das voxpupuli/zabbix Modul.
Langfristig wird OnyxPoint die Entwicklung von beaker übernehmen
Puppet Inc. arbeitet an Litmus, einer Ruby Bibliothek um VMs/Container zu starten
Liste der aktuell empfohlenen plugins:
Gemfile:
gem 'puppet-lint-leading_zero-check', :require => false
gem 'puppet-lint-trailing_comma-check', :require => false
gem 'puppet-lint-version_comparison-check', :require => false
gem 'puppet-lint-classes_and_types_beginning_with_digits-check', :require => false
gem 'puppet-lint-unquoted_string-check', :require => false
gem 'puppet-lint-variable_contains_upcase', :require => false
gem 'puppet-lint-absolute_classname-check', '>= 2.0.0', :require => false
gem 'puppet-lint-topscope-variable-check', :require => false
gem 'puppet-lint-legacy_facts-check', :require => false
gem 'puppet-lint-anchor-check', :require => false
man kann in der Puppet DSL gezielt einzelne Linter deaktivieren, sofern sie ein False/Positive liefern:
# lint:ignore:case_without_default
Für Fehlermeldungen in einem sinnvollen Format kann man folgendes in seinem Rakefile
eintragen:
PuppetLint.configuration.log_format = '%{path}:%{line}:%{check}:%{KIND}:%{message}'
Für neue Komponentenmodule sollte man auch puppet-lint-param-docs nutzen. Dies erzwingt Dokumentation für jeden Parameter.
Ausgabe mit Fehler:
$ bundle exec rake lint
manifests/init.pp:106:arrow_on_right_operand_line:WARNING:arrow should be on the right operand's line
Ausgabe mit Autokorrektur:
$ bundle exec rake lint:auto_correct
manifests/init.pp:106:arrow_on_right_operand_line:FIXED:arrow should be on the right operand's line
puppet parser
puppet
Beispielhafte Ausgabe vom Rake Task wenn es keine Fehler gibt:
$ bundle exec rake syntax
---> syntax:manifests
---> syntax:templates
---> syntax:hiera:yaml
Ausgabe mit Syntaxfehlern:
$ bundle exec rake syntax
---> syntax:manifests
rake aborted!
Could not parse for environment production: Syntax error at end of file at demo.pp:2
Tasks: TOP => syntax => syntax:manifests
(See full trace by running task with --trace)
Ausgabe mit Fehlern:
$ bundle exec rake rubocop
Running RuboCop...
Inspecting 4 files
..C.
Offenses:
spec/spec_helper.rb:8:1: C: Layout/EmptyLines: Extra blank line detected. (https://github.com/bbatsov/ruby-style-guide#two-or-more-empty-lines)
4 files inspected, 1 offense detected
RuboCop failed!
Mit Autokorrektur:
bundle exec rake rubocop:auto_correct
Running RuboCop...
Inspecting 4 files
Parser::Source::Rewriter is deprecated.
Please update your code to use Parser::Source::TreeRewriter instead
..C.
Offenses:
spec/spec_helper.rb:8:1: C: [Corrected] Layout/EmptyLines: Extra blank line detected. (https://github.com/bbatsov/ruby-style-guide#two-or-more-empty-lines)
4 files inspected, 1 offense detected, 1 offense corrected
puppetlabs_spec_helper
einbindenGemfile:
source ENV['GEM_SOURCE'] || "https://rubygems.org"
gem 'puppetlabs_spec_helper'
Rakefile:
require 'puppetlabs_spec_helper/rake_tasks'
Alle Rake Tasks ausgeben:
bundle exec rake -T
rake beaker # Run beaker acceptance tests
rake beaker:sets # List available beaker nodesets
rake beaker:ssh[set,node] # Try to use vagrant to login to the Beaker node
rake build # Build puppet module package
rake build:pdk # Build Puppet module with PDK
rake build:pmt # Build Puppet module package with PMT (Puppet < 6.0.0 only)
rake check:dot_underscore # Fails if any ._ files are present in directory
rake check:git_ignore # Fails if directories contain the files specified in .gitignore
rake check:symlinks # Fails if symlinks are present in directory
rake check:test_file # Fails if .pp files present in tests folder
rake clean # Clean a built module package
rake compute_dev_version # Print development version of module
rake help # Display the list of available rake tasks
rake lint # Run puppet-lint
rake lint_fix # Run puppet-lint
rake parallel_spec # Run spec tests in parallel and clean the fixtures directory if successful
rake parallel_spec_standalone # Parallel spec tests
rake release_checks # Runs all necessary checks on a module in preparation for a release
rake rubocop # rubocop is not available in this installation
rake spec # Run spec tests and clean the fixtures directory if successful
rake spec:simplecov # Run spec tests with ruby simplecov code coverage
rake spec_clean # Clean up the fixtures directory
rake spec_clean_symlinks # Clean up any fixture symlinks
rake spec_list_json # List spec tests in a JSON document
rake spec_prep # Create the fixtures directory
rake spec_standalone # Run RSpec code examples
rake syntax # Syntax check Puppet manifests and templates
rake syntax:hiera # Syntax check Hiera config files
rake syntax:manifests # Syntax check Puppet manifests
rake syntax:templates # Syntax check Puppet templates
rake validate # Check syntax of Ruby files and call :syntax and :metadata_lint
Anforderungen:
Dies lässt sich mit dem Roles and Profiles Pattern lösen
lookup()
Aufrufe oder Automatic Class Parameter Lookup Pattern(Copyright Craig Dunn)
include modul
funktioniert und installiert mir eine Komponente mit sinnvollen und sicheren Standardwertenpuppet-strings
dokumentiertEs kommt vor, dass man ein öffentliches Modul patchen muss. Man muss versuchen diese Patches Upstream gemerged zu bekommen. Andernfalls difft der Fork immer mehr von Upstream ab und man landet in der Abhängigkeitshölle. Bei Modulen von Vox Pupuli / Puppet wird tendenziell schneller reagiert als bei Modulen mit einzelnen Maintainern. Puppet hat viele Mitarbeiter mit Commit Rechten für Ihre Module, Vox Pupuli hat > 140 (unregelmäßige) Maintainer. Außerdem gibt es hier Esakalationsmöglichkeiten.
puppet module list --environment production --tree
/var/log/puppetlabs/puppetserver/puppetserver.log
nach Warnungen / Fehlern schauenSSH Multiplexing aktivieren um git clone
s zu beschleunigen:
class profiles::ssh2git {
# /root/.ssh/config entry to access git.internal
ssh::client::config::user { 'gitaccess':
ensure => present,
user => 'root',
user_home_dir => '/root',
options => {
'Host git.internal' => {
'User' => 'git',
'IdentityFile' => '~/.ssh/id_ed25519...',
'ControlMaster' => 'auto',
'ControlPath' => '~/.ssh/ssh-%r@%h:%p',
'ControlPersist' => '10m'
},
},
}
sshkey { 'git.internal':
ensure => 'present',
target => '/root/.ssh/known_hosts',
type => 'ecdsa-sha2-nistp256',
key => 'DATA',
}
}
r10k mit mehreren Workern starten:
# puppet/r10k from Vox Pupuli
class { 'r10k':
version => '3.4.0',
pool_size => 10,
}
Es gibt viele Möglichkeiten Puppet Module zu speichern.
Folgende Projekte unterstützen Puppet Modul Releases(.tar.gz Archive):
Alternativ kann man mit git tags / commit ids im Puppetfile arbeiten.
Mit Puppet eine große Menge an Scripten als File Resources verteilen ist ein Antipattern. Diese sollte man als Artefakte Paketieren. Puppet richtet dann das Repository auf den Zielsystemen ein. Dies gillt für alle Artefakte, welche Puppet deployen soll.
Bei vielen Projekten bietet sich ein gitflow-workflow an:
Dies funktioniert sehr gut für intern entwickelte Anwendungen die auf anderen internen Tools aufsetzen und wiederum von anderen Teams genutzt werden. Für jede Umgebung benötigt man eigene Repositories und Maschinen/Server/Docker Images. Puppet kann solche Umgebungen deployen. Puppet Code selbst mit so einem Workflow zu verwalten funktioniert in der Regel nicht / bringt viel zu viel Overhead mit sich.
Für Puppet hat sich in den meisten Organisationen ein Git Feature Branch Workflow als beste Lösung etabliert.
production
. Dieser wird als Environment auf normalen Nodes genutztDedizierter Vortrag über Puppetserver Skalierung
Hiera Tuningoptionen für puppetlabs/puppetdb:
---
puppetdb::server::java_args:
'-Xmx': '8192m'
'-Xms': '2048m'
puppetdb::server::node_ttl: '14d',
puppetdb::server::node_purge_ttl: '14d',
puppetdb::server::report_ttl: '999d'
# default is 50
puppetdb::server::max_threads: 100
# default is processorcount / 2
puppetdb::server::command_threads: %{facts.processors.count}
# default is 4, have your database in mind
puppetdb::server::concurrent_writes: 8
puppetdb::server::automatic_dlo_cleanup: true
Optionen für puppetlabs/postgresql:
Anzahl der Verbindungen erhöhen:
postgresql::server::config_entry{'max_connections':
value => 400,
}
Laufenden PostgreSQL Server analysieren und eine optimierte Konfiguration generieren:
pgtune -i /var/lib/pgsql/10/data/postgresql.conf -o postgresql.conf
Für PostgreSQL empfiehlt sich deren eigenes Yum Repository. Die Upstream Pakete erlauben es beliebige Versionen parallel zu installieren. Außerdem bekommt das Yum Repository am schnellsten Sicherheitsupdates.
Hiera Optionen für theforeman/foreman:
---
# default is 5
foreman::db_pool: 20
foreman::keepalive: true
foreman::max_keepalive_requests: 1000
foreman::keepalive_timeout: 180
Foreman läuft via Passenger. Dieser wird mit puppetlabs/apache aufgesetzt. Multithreading hochdrehen:
---
apache::mod::passenger::passenger_max_pool_size: %{facts.processors.count}
apache::mod::passenger::passenger_min_instances: %{facts.processors.count}
Foreman kann memcached als Cache nutzen:
Via Puppet installieren:
# https://forge.puppet.com/saz/memcached
include memcached
include foreman::plugin::memcache
Via Hiera einstellen:
---
# 50GB of cache
memcached::max_memory: 51200
foreman::plugin::memcache::hosts:
- 127.0.0.1
Puppetlabs bietet im Modul puppetlabs/puppet_metrics_dashboard einen Monitoring Stack für Puppetserver. Dieser bietet JVM Metriken via JMX und Puppetserver Metriken via Graphite.
file
Reports sind unnötig und fressen oft IO/s und Inodes (grep ^reports /etc/puppetlabs/puppet/puppet.conf
)Hiera Optionen für theforeman/puppet:
$cpu_count_twice = $facts['processors']['count'] * 2
$cpu_count = $facts['processors']['count'] * 1
class{'puppet':
server_jvm_min_heap_size => "${cpu_count}G",
server_jvm_max_heap_size => "${cpu_count_twice}G",
server_max_requests_per_instance => 100000,
server_max_queued_requests => $cpu_count,
server_environment_class_cache_enabled => true,
server_jvm_extra_args => ['-XX:ReservedCodeCacheSize=2G'],
}
Dieses Dokument steht unter der CC BY-NC-SA 4.0 Lizenz. Für kommerzielle Anfragen oder Feedback kontaktieren sie bitte tim@bastelfreak.de
Das ganze dokument befindet sich nun in einem git repo: https://github.com/bastelfreak/puppetdocs#puppet-walkthrough
Das ist super. Kann man das bitte in ein Repository packen, so dass man PR's stellen kann? Danke schön.