On Github ingwarsw / jenkins-by-devops
by Karol Lassak | @IngwarSwenson
Karol Lassak
Dla każdego z podpunktu wymienić kilka narzędzi bądź rozwiązań
Proszę użyć internetu i własnych doświadczeń :-)
Krótkie szybkie iteracje
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 -*- # vi: set ft=ruby : # Vagrantfile API/syntax version. Don't touch unless you know what VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # Every Vagrant virtual environment requires a box to build off o config.vm.box = "puppetlabs/ubuntu-14.04-64-nocm" # Enable provisioning with Puppet stand alone. Puppet manifests # are contained in a directory path relative to this Vagrantfile. # You will need to create the manifests directory and a manifest # the file default.pp in the manifests_path directory. # # 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
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!
package { 'nginx': ensure => 'installed', }Zniszczyć maszyne i na nowej zainstalować puppet z repozytoriów puppetlabs Redo #2 (użyj też trybu --noop oraz --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 $ _
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', }
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
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'], }
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
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 łączy się do serwera i pobiera z niego konfigurację
Dostęp tylko po SSL z zaufanym certyfikatem
Kompilacja na serwerze, wykonanie na agencie
Puppet posiada szereg możliwości testowania
Nie będziemu tu mówić o 2 ostatnich
Unikalna funkcjonalność puppet
Pozwala uruchamianie manifestów bez wprowadzania zmian
Flaga: --noop
W Puppet smoke testy to po prostu uruchamianie manifestów, specjalnie przygotowanych w katalogu tests w trybie bezoperacyjnym --noop
puppet apply tests/apache.pp --noop
Kod puppet umieszczamy w:
mymodule # This outermost directory’s name matches the │ # name of the module. ├── manifests # Contains all of the manifests in the module. │ └── init.pp # Contains a class definition. This class’s │ # name must match the module’s name. ├── metadata.json # Contains META information about module ├── spec # Contains spec tests for any plugins in the │ # lib directory. ├── templates # Contains templates, which the module’s │ # manifests can use. ├── files # Contains files to be sourced ├── tests # Contains examples showing how to declare │ │ # the module's classes and defined types. │ └── init.pp └── lib # Contains plugins, like custom facts and │ # custom resource types. └── puppet ├── provider └── type
Wiecej: http://slides.com/cardil/...
class apache ($version = 'latest') { package {'httpd': ensure => $version, # Using the class parameter from above before => File['/etc/httpd.conf'], } file {'/etc/httpd.conf': ensure => file, owner => 'httpd', content => template('apache/httpd.conf.erb'), # Template from a module } service {'httpd': ensure => running, enable => true, subscribe => File['/etc/httpd.conf'], } }
# only once in catalog # class is a resource class { 'apache': version => 'latest', } # or simply include apache include apache
# /etc/puppet/modules/apache/manifests/vhost.pp define apache::vhost ($port, $docroot, $servername = $title, $vhost_name = '*') { include apache # contains Package['httpd'] and Service['httpd'] include apache::params # contains common config settings $vhost_dir = $apache::params::vhost_dir file { "${vhost_dir}/${servername}.conf": content => template('apache/vhost-default.conf.erb'), # This template can access all of the parameters and variables from above. owner => 'www', group => 'www', mode => '644', require => Package['httpd'], notify => Service['httpd'], } }