by Krzysztof Suszyński | @ksuszynski
Krzysztof Suszyński
Zapis infrastruktury jako kod przetwarzany i wykonywalny jest KLUCZOWY dla DevOps
Daje możliwość pracy w niedużych iteracjach.
“To co było zapisane w postaci kodu zadziałało, problem był w tych elementach, których jeszcze nie automatyzowaliśmy. Zróbmy to!”
Najpopularniejsze i polecane przez Puppetlabs :-(
Tak będziemy pracować na tym warsztacie
Najlepszy sposób pracy lecz zaawansowany
Typowe narzędzie fazy rozwoju i wstępnego testowania rozwiązań. Pozwala na:
# All commands as root
echo 'deb http://download.virtualbox.org/virtualbox/debian trusty contrib' >
/etc/apt/sources.list.d/virtualbox.list
wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | apt-key add -
apt-get update
apt-get install virtualbox-5.0
curl -kL https://dl.bintray.com/mitchellh/vagrant/vagrant_1.7.2_x86_64.deb -o vagrant_1.7.2_x86_64.deb
dpkg -i vagrant_1.7.2_x86_64.deb
$ vagrant init puppetlabs/ubuntu-14.04-64-nocm
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.
$ _
# -*- mode: ruby -*-
Vagrant.configure(2) do |config|
# Every Vagrant virtual environment requires a box to build off o
config.vm.box = "puppetlabs/ubuntu-14.04-64-nocm"
# [...]
# config.vm.provision "puppet" do |puppet|
# puppet.manifests_path = "manifests"
# puppet.manifest_file = "site.pp"
# end
end
Vagrant.configure(2) do |config|
config.vm.network :private_network, ip: "192.168.50.4"
config.vm.provider :virtualbox do |v|
v.memory = 1024
v.cpus = 2
end
end
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'puppetlabs/ubuntu-14.04-64-nocm'.
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'puppetlabs/ubuntu-14.04-64-nocm' is
==> default: Setting the name of the VM: tmp_default_1426727671461
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration..
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 => 2222 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minu
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
default: /vagrant => /tmp
$ _
$ vagrant ssh
Welcome to Ubuntu 14.04 LTS (GNU/Linux 3.13.0-24-generic x86_64)
* Documentation: https://help.ubuntu.com/
vagrant@localhost:~$ uptime
18:17:47 up 3 min, 1 user, load average: 0.00, 0.00, 0.00
vagrant@localhost:~$ logout
Connection to 127.0.0.1 closed.
$ _
Aby sprawdzić jaki jest aktualny stan maszyny w ramach konfiguracji, należy wywołać polecenie vagrant status
.
Aby skasować maszynę wykonać należy polecenie vagrant destroy
.
Vagrant.configure("2") do |config|
config.vm.box = "puppetlabs/ubuntu-14.04-64-puppet"
# Provision with Bash
config.vm.provision :shell, inline: "echo Hi $(cat /etc/issue)"
# Provision with Puppet apply
config.vm.provision :puppet do |puppet|
puppet.manifests_path = "manifests"
# contains: "package { 'elinks': ensure => 'installed', }"
puppet.manifest_file = "default.pp"
end
end
$ vagrant provision
==> default: Running provisioner: shell...
default: Running: inline script
==> default: Hi Ubuntu 14.04.2 LTS \n \l
==> default: Running provisioner: puppet...
==> default: Running Puppet with default.pp...
==> default: Notice: Compiled catalog for localhost.suszynski.org
in environment production in 0.08 seconds
==> default: Notice: /Stage[main]/Main/Package[elinks]/ensure:
ensure changed 'purged' to 'present'
==> default: Notice: Finished catalog run in 4.88 seconds
$ _
github.com/mitchellh/vagrant/wiki/Available-Vagrant-Plugins
vagrant plugin install plugin-name
puppetlabs/ubuntu-14.04-64-nocm
Jedno z najbardziej dojrzałych narzędzi DevOps
package { 'postgresql':
ensure => 'installed',
}
service { 'postgresql':
ensure => 'running',
enable => true,
require => Package['postgresql'],
}
Co to znaczy? Na pierwszy rzut oka?
Dostarcza możliwości zapisania oczekiwanego stanu infrastruktury IT
Wymuszenia wykonania zmian dostosowującego ją do tegoż stanu
Wszystkie elementy składowe to open-source
Prosty język manifestów naturalnie przyjazny administratorom
Silnik Puppeta składa się z zestawu komend konsoli systemu, które również można efektywnie wykorzystywać w oderwaniu od Puppeta
Język DSL w postaci deklaratywnej tzn. 4 generacji podobnie jak SQL
Brak podejścia "all or nothing", można go wprowadzać na dowolnym etapie zaawansowania projektu
Największa społeczność użytkowników
Możliwość prostego rozszerzenia silnika Puppeta w postaci zarówno manifestów Puppet jak i kodu niskopoziomowego Ruby
Wytwarza naturalny podział pracy: programiści piszą kod w Ruby a administratorzy używają prostszych manifestów
Największa ilość gotowych do użycia modułów i rozszerzeń
Moduły pisane i utrzymywane przez firmę Puppetlabs
Dogłębne testowanie jednostkowe, "dymne", integracyjne i akceptacyjne
Możliwość symulowania zmiany w systemie
Dokładne, szczegółowe raportowanie
Bezpieczna i skalowalna architektura agent --> serwer
Wsparcie i integracje z innymi narzędziami np. Vagrant, VMWare, OpenStack
Wsparcie enterprise firmy Puppetlabs i Red Hat, oraz dodatkowe bardzo przydatne narzędzia takie jak Enterprise Console, Razer czy Cloud Provisioning
Wsparcie dla największej liczby systemów operacyjnych: Linux (RHEL i podobne, Debian i podobne), Suse, AIX, Solaris, Windows, Mac OSX
Największe wsparcie dla edytorów kodu, systemów weryfikacji i budowania oraz integracji ciągłej
Uwaga! Przed instalacją Puppet należy ustawić pełną nazwę domenową (FQDN) i poleca się zainstalowanie i uruchomienie usługi synchronizacji czasu ntp!
manifest.pp
: package { 'nginx':
ensure => 'installed',
}
puppet apply manifest.pp --noop
puppet apply manifest.pp
(użyj też trybu --debug
)Puppet składa się z kilku luźno powiązanych ze sobą narzędzi i systemów.
Dzięki temu daje możliwość używania ich niezależnie
Narzędzie działające między innymi w konsoli systemowej. Jego zadaniem jest wyliczanie faktów na temat maszyny na której został uruchomiony.
$ facter
architecture => amd64
ipaddress => 172.17.42.1
kernel => Linux
kernelmajversion => 3.11
kernelrelease => 3.11.0-26-generic
kernelversion => 3.11.0
lsbdistcodename => saucy
lsbdistdescription => Ubuntu 13.10
lsbdistid => Ubuntu
lsbdistrelease => 13.10
lsbmajdistrelease => 13.10
operatingsystem => Ubuntu
operatingsystemmajrelease => 13.10
operatingsystemrelease => 13.10
osfamily => Debian
puppetversion => 3.2.4
rubyplatform => x86_64-linux
rubyversion => 1.9.3
timezone => CET
uniqueid => 007f0100
uptime => 1 day
uptime_days => 1
uptime_hours => 45
uptime_seconds => 165504
virtual => physical
$ _
facter ipaddress
facter fqdn
facter operatingsystem
facter -p
i facter
(porównać)Narzędzie elastycznego zmieniania konfiguracji plików. Potrafi inteligentnie zmieniać treść bardzo wielu różnych formatów plików, selektywnie, zmieniając jedyne pożądaną wartość i nie zmieniając nic w przypadku pełnej zgodności.
$ augtool
augtool> get /files/etc/postgresql/9.1/main/postgresql.conf/max_connections
/files/etc/postgresql/9.1/main/postgresql.conf/max_connections = 100
augtool> set /files/etc/postgresql/9.1/main/postgresql.conf/max_connections 130
augtool> get /files/etc/postgresql/9.1/main/postgresql.conf/max_connections
/files/etc/postgresql/9.1/main/postgresql.conf/max_connections = 130
augtool> save
Hierarchiczna, prosta baza danych dzięki której możliwe są kontekstowe konfiguracje.
/------------- DC1 -------------\ /------------- DC2 -------------\
| ntpserver: ntp1.dc1.example.com | | ntpserver: ntp1.dc2.example.com |
| sysadmin: dc1noc@example.com | | |
| classes: users::dc1 | | classes: users::dc2 |
\-------------------------------/ \-------------------------------/
\ /
\ /
/------------- COMMON -------------\
| ntpserver: 1.pool.ntp.org |
| sysadmin: sysadmin@%{domain} |
| classes: users::common |
\----------------------------------/
Możliwość uruchamiania puppeta dla konkretnych pojedynczych zasobów i listowania ich
# puppet resource user ksuszynski
user { 'ksuszynski':
ensure => 'present',
comment => 'Krzysztof Suszynski,,,',
gid => '1000',
groups => ['adm', 'sudo', 'docker'],
home => '/home/ksuszynski',
shell => '/bin/bash',
uid => '1000',
}
useradd -s /bin/bash -b /home twoje-imie
puppet resource user twoje-imie
passwd twoje-imie
puppet resource user twoje-imie
puppet resource user twoje-imie shell=/bin/sh
puppet resource user
Język Puppet zapisywany jest w manifestach
Manifesty są grupowane w moduły
Manifesty mogą zawierać definicje, klasy lub wywołania zasobów
Zasobem jest każdy pojedynczy deklaratywny element, który puppet może wymusić
service { 'apache2':
ensure => 'running',
}
Puppet posiada wiele wbudowanych zasobów
Potrafi zarządzać plikami, katalogami i linkami symbolicznymi. Dodatkowo kopiować pliki i katalogi.
file { '/etc':
ensure => 'directory',
mode => '0755',
}
file { '/etc/acme-motd':
ensure => 'file',
content => 'Hello from Acme Datacenter managed by Puppet!',
mode => '0644',
}
file { '/etc/motd':
ensure => 'link',
target => '/etc/acme-motd',
}
Potrafi zarządzać pakietami przy użyciu YUM, APT, GEM, PIP i wielu innych.
package { 'ruby':
ensure => 'installed',
}
package { 'lolcat':
ensure => 'installed',
provider => 'gem',
}
Potrafi zarządzać usługami w systemie.
service { 'apache':
ensure => 'running',
enable => true,
hasrestart => true,
hasstatus => true,
}
Zarządza użytkownikami w systemie
user { 'ksuszynski':
ensure => 'present',
shell => '/bin/bash',
groups => ['admin', 'user'],
}
Pozwala na uruchamianie poleceń w systemie
exec { '/usr/bin/yes yes | bundle exec rake gitlab:setup':
unless => '/usr/bin/test -f /opt/gitlab/.db_done',
timeout => 600,
environment => ['RAILS_ENV=production'],
}
Zasoby tworzą graf w którym określamy kolejność wykonania
service { 'apache2':
ensure => 'running',
require => Package['apache2'],
}
package { 'apache2':
ensure => 'installed',
}
require, before, subscribe, notify
install -> configure ~> service
package { 'openssh-server':
ensure => 'installed',
}
file { '/etc/ssh/sshd_config.conf':
ensure => 'file',
content => template('myssh/sshd_config.conf.erb'),
require => Package['openssh-server'],
}
service { 'ssh':
ensure => 'installed',
subscribe => File['/etc/ssh/sshd_config.conf'],
}
puppet parser validate plik.pp
service ... stop
i uruchom Puppet ponownieW języku DSL Puppet występuje możliwość tworzenia i wykorzystywania zmiennych
Wbrew nazwie, raz ustalonej zmiennej nie można zmienić
$service = 'apache2'
service { $service:
ensure => 'running',
require => Package[$service],
}
package { $service:
ensure => 'installed',
}
Fakty są dostępne w przestrzeni globalnej np.: $::fqdn
W języku DSL Puppet występuje zestaw wyrażeń warunkowych
if $::osfamily == 'Debian' {
$service = 'apache2'
} else {
$service = 'httpd'
}
case $::operatingsystem {
'RedHat', 'CentOS': { $service = 'httpd' }
/^(Debian|Ubuntu)$/:{ $service = 'apache2' }
default: { fail("Unsupported platform: ${::operatingsystem}") }
}
$rootgroup = $::osfamily ? {
'Solaris' => 'wheel',
/(Darwin|FreeBSD)/ => 'wheel',
default => 'root',
}
file { '/etc/passwd':
ensure => 'file',
owner => 'root',
group => $rootgroup,
}
if str2bool($::is_virtual) {
fail('unsupported')
} else {
include ntp
}
W tym przykładzie funkcje to fail
, include
oraz str2bool
.
puppet parser validate plik.pp