Puppet

for Beginners

by Krzysztof Suszyński | @ksuszynski

Hej!

Krzysztof Suszyński

  • Ewangelizuje z Puppet i Java
  • Główny Programista w COI / właściciel Wave Software
  • Od 2014r. współpraca z
  • Z DevOps pierwszy raz w 2010 roku
  • Duże wdrożenia z DevOps / Puppet
  • Prezentacje na User Groups i szkolenia pracowników
  • Wiele OS modułów: JBoss, Glassfish, XtreemFS, Artifactory, Flyway, Herald

Jak będzie wyglądał warsztat?

  • ~5 tematów:
    • Wstęp teoretyczny
    • Samodzielna praca
    • Przerwa
  • Mikro projekt

Co przed nami?

  1. Sposoby pracy z Puppet
  2. Instalacja Puppet na systemie operacyjnym
  3. Podstawowe typy takie jak file, service, user czy package
  4. Składnia deklaratywnych manifestów
  5. Zasoby i zarządzanie kolejnością
  6. Wstęp do testowania i tryb bez operacyjny

Dyskusja

  • Jakie cele mam na tym warsztacie?
  • Czy potrafię wskazać na czym najbardziej mi zależy?
  • Czy mam już plan jak wykorzystać zdobytą tu wiedzę?

Zapis infrastruktury jako kod

Configuration enforcement

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!”

Sposoby pracy z narzędziami configuration management

Praca bezpośrednio na docelowej infrastrukturze

  • Nie polecam
  • Niebezpieczne i jedno dostępne
  • Szczątkowe możliwości testowania
  • Możliwość używania środowisk

Najpopularniejsze i polecane przez Puppetlabs :-(

Wykorzystanie narzędzi typu Vagrant

  • W miarę wygodne i proste
  • Bezpieczne
  • Możliwe dogłębne testowanie
  • Możliwe wykorzystanie systemów CI

Tak będziemy pracować na tym warsztacie

Wykorzystanie separacji modułów

  • Wymaga ekosystemu developerskiego Puppet
  • Bezpieczne, wielodostępne i skalowalne
  • Możliwe pełne testowanie i separacja na odpowiedzialności
  • Konieczne wykorzystanie systemów CI i CD
  • Wykorzystanie zaawansowanych testów rspec i beaker

Najlepszy sposób pracy lecz zaawansowany

Vagrant

Typowe narzędzie fazy rozwoju i wstępnego testowania rozwiązań. Pozwala na:

  • szybkie zarządzanie obrazami maszyny wirtualnej
  • zarządzanie połączeniami sieciowymi
  • miejscem współdzielonym
  • uruchamianiem na maszynie wirtualnej skryptów i narzędzi configuration management

Kluczowe funkcje Vagranta

  • dostarcza poleceń linii komend do sterowania maszyną lub maszynami wirtualnymi
  • pozwala na zapis konfiguracji w pliku Vagrantfile
  • posiada szereg wbudowanych providerów: VirtualBox, VMWare, Docker, Hyper-V
  • posiada szereg wbudowanych provisionerów: Shell, Chef, Puppet, Ansible, Docker, Salt, CFEngine
  • posiada system wtyczek i istnieje wiele publicznych wtyczek
  • posiada prostą instalację w postaci pliku DEB, RPM, MSI lub DMG
  • dostarcza automatycznej konfiguracji sieci oraz folderów współdzielonych

Instalacja

Vagrant

# 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

Bazowe obrazy do Vagranta

https://atlas.hashicorp.com/boxes/search

Nowe środowisko dla Vagranta

$ 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.
$ _

Przykładowy plik Vagrantfile

# -*- 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

Konfiguracja sieci, procesora i pamięci

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

Uruchomienie maszyn w środowisku

$ 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
$ _

Sesja SSH w środowisku

$ 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.
$ _

Zweryfikowanie stanu maszyny

Aby sprawdzić jaki jest aktualny stan maszyny w ramach konfiguracji, należy wywołać polecenie vagrant status.

Usunięcie maszyny

Aby skasować maszynę wykonać należy polecenie vagrant destroy.

Zaopatrywanie w konfigurację

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

Wynik zaopatrywania w konfigurację

$ 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
$ _

Wtyczki

do Vagranta

github.com/mitchellh/vagrant/wiki/Available-Vagrant-Plugins

vagrant plugin install plugin-name

  • landrush - lokalnego micro DNS. Działa zarówno w maszynach wirtualnych jak i na hoście
  • sahara - Możliwość wykonywania migawek stanu, przywracania stanu i potwierdzania zmian

Vagrant

Demo

Zadanie 3

  • Zainstalować Vagranta
  • Przygotować maszynę z obrazu: puppetlabs/ubuntu-14.04-64-nocm
  • Zainstalować podstawowe pakiety: git, htop, telnet, itp. i sprawdzić separację ze swoim systemem
  • Zatrzymać, usunąć, postawić na nowo, na koniec usunąć

Jedno z najbardziej dojrzałych narzędzi DevOps

Czytelność Puppet

package { 'postgresql':
  ensure => 'installed',
}

service { 'postgresql':
  ensure  => 'running',
  enable  => true,
  require => Package['postgresql'],
}

Co to znaczy? Na pierwszy rzut oka?

Zalety Puppet

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

Zalety Puppet - c.d.

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

Zalety Puppet - c.d. 2

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

Zalety Puppet - c.d. 3

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

Puppet

Jak działa?

Proces działania

Klasyfikacja

Proces wprowadzania zmiany

Sposoby instalacji Puppet

  • z pakietów dostępnych w systemie operacyjnym
  • z rubygems
  • z pakietów z repozytoriów puppetlabs
  • instalator wersji Enterprise

Uwaga! Przed instalacją Puppet należy ustawić pełną nazwę domenową (FQDN) i poleca się zainstalowanie i uruchomienie usługi synchronizacji czasu ntp!

Demo

Instalacja Puppet

Zadanie 4

  1. Używając Vagrant utworzyć VM i zainstalować puppet z repozytoriów Puppetlabs: goo.gl/Xbqnl8
  2. Zapisać kod w pliku manifest.pp:
    package { 'nginx':
      ensure => 'installed',
    }
  3. Uruchom w trybie No-OP puppet apply manifest.pp --noop
  4. Wywołaj przy użyciu puppet apply manifest.pp (użyj też trybu --debug)

Zadanie 5

Dyskusja

  • Czy praca z Vagrantem wydaje się prosta?
  • Jakie problemy mogą się pojawić? Na co uważać?
  • Jakie widzisz plusy i minusy?

Opis ekosystemu Puppet

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

Facter

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 - przykład

$ 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
$ _
          

Zadanie 6

  • Uruchom polecenie: facter ipaddress
  • Uruchom polecenie: facter fqdn
  • Uruchom polecenie: facter operatingsystem
  • Uruchom polecenie: facter -p i facter (porównać)
  • Co zwracają te polecenia? Jak można to wykorzystać?

Augeas

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.

Augeas

$ 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

Hiera

Hierarchiczna, prosta baza danych dzięki której możliwe są kontekstowe konfiguracje.

Hiera - graf



     /------------- 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             |
                         \----------------------------------/
          

puppet resource

Możliwość uruchamiania puppeta dla konkretnych pojedynczych zasobów i listowania ich

puppet resource - przykład

# 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',
}

Demo

puppet resource

Zadanie 7

  • Utwórz użytkownika: useradd -s /bin/bash -b /home twoje-imie
  • Uruchom polecenie: puppet resource user twoje-imie
  • Ustaw hasło: passwd twoje-imie
  • Sprawdź, uruchamiając polecenie: puppet resource user twoje-imie
  • Zmień shell przy użyciu: puppet resource user twoje-imie shell=/bin/sh
  • Wykonaj i sprawdź wynik: puppet resource user
  • Co zwracają te polecenia? Jak można to wykorzystać?

Podstawa składni DSL Puppet

Język Puppet

Język Puppet zapisywany jest w manifestach

Manifesty są grupowane w moduły

Manifesty mogą zawierać definicje, klasy lub wywołania zasobów

Zasób Puppet

Zasobem jest każdy pojedynczy deklaratywny element, który puppet może wymusić

service { 'apache2':
  ensure => 'running',
}

Puppet posiada wiele wbudowanych zasobów

Podstawowe zasoby

  • file
  • service
  • package
  • exec
  • user
  • group
  • augeas

file

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',
}

package

Potrafi zarządzać pakietami przy użyciu YUM, APT, GEM, PIP i wielu innych.

package { 'ruby':
  ensure   => 'installed',
}
package { 'lolcat':
  ensure   => 'installed',
  provider => 'gem',
}

service

Potrafi zarządzać usługami w systemie.

service { 'apache':
  ensure     => 'running',
  enable     => true,
  hasrestart => true,
  hasstatus  => true,
}

user

Zarządza użytkownikami w systemie

user { 'ksuszynski':
  ensure => 'present',
  shell  => '/bin/bash',
  groups => ['admin', 'user'],
}

exec

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'],
}

Kolejność

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

Polecany flow

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'],
}

Zadanie 8

  • Napisz prosty manifest instalujący i uruchamiający jedną z usług: apache, nginx, postgres, mysql
  • Sprawdz manifest przy użyciu: puppet parser validate plik.pp
  • Uruchom przy użyciu Vagrant
  • Wykorzystaj typy package, service, file i user
  • Pamiętaj o ustawieniu kolejności
  • Zatrzymaj usługę "ręcznie": service ... stop i uruchom Puppet ponownie
  • Wywołaj w trybie debug

Zmienne

W 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

Wyrażenia warunkowe

W języku DSL Puppet występuje zestaw wyrażeń warunkowych

if $::osfamily == 'Debian' {
  $service = 'apache2'
} else {
  $service = 'httpd'
}

Warunki case

case $::operatingsystem {
  'RedHat', 'CentOS': { $service = 'httpd' }
  /^(Debian|Ubuntu)$/:{ $service = 'apache2' }
  default:            { fail("Unsupported platform: ${::operatingsystem}") }
}

Selektory

$rootgroup = $::osfamily ? {
  'Solaris'          => 'wheel',
  /(Darwin|FreeBSD)/ => 'wheel',
  default            => 'root',
}

file { '/etc/passwd':
  ensure => 'file',
  owner  => 'root',
  group  => $rootgroup,
}

Funkcje

if str2bool($::is_virtual) {
  fail('unsupported')
} else {
  include ntp
}

W tym przykładzie funkcje to fail, include oraz str2bool.

Zadanie 9

  • Napisz manifest instalujący i uruchamiający usługę apache
  • Powinna ona zawierać warunkową obsługę dla rodzin systemów Debian i Red Hat
  • Sprawdź manifest przy użyciu: puppet parser validate plik.pp
  • Uruchom przy użyciu Vagrant
  • Pamiętaj o ustawieniu kolejności

Podsumowanie

warsztatu

  • Co poznaliśmy? Powtorka.
  • Co dalej?
    • modułowość
    • serwer <=> agent
    • testowanie

Dziękuję

Do zobaczenia