Puppet

Tworzenie ekosystemu deweloperskiego dla JavaScript

by Karol Kozakowski @cosaquee

Cześć!

Karol Kozakowski

  • Developer/DevOps Specialist @COI
  • Z DevOps od pół roku
  • Zarządzanie ekosystemem do budowy i testowania aplikacji

  • Tworzenie i zarządzanie modułami Puppet
  • Zarządzanie systemami CI
  • Praca z narzędziami wsparcia DevOps

Jak będzie wyglądał warsztat?

  • ~8 tematów:
    • Wstęp teoretyczny
    • Samodzielna praca

Co przed nami?

  1. Czym jest środowisko deweloperskie, jakie są rodzaje i jak powinno wyglądać?
  2. Wprowadzenie do narzędzia Vagrant
  3. Przypomnienie z Puppet DSL
  4. Modułowość - klasy i definicje w Puppet
  5. Puppetforge i zewnętrzne moduły(librarian-puppet)
  6. Moduł puppetlabs/nodejs
  7. Puppet provider
  8. Stworzenie środowiska deweloperskiego JS przy użyciu Puppet

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ę?

Środowisko deweloperskie

Co to jest?

środowisko deweloperskie

Miejsce lub system w którym programista tworzy aplikacje
  • Zależności danego projektu w odpowiednich wersjach
  • Biblioteki i kod wymagany do zbudowania i przetestowania aplikacji
  • Powinno być zbliżone do środowiska produkcyjnego

Rodzaje środowisk

  • scentralizowane
  • ręczne
  • automatyczne

Jak tworzyć

  • Użycie narzędzi typu Configuration Management
  • Praktyka DevOps

Dyskusja

Jak wyglądają rozwiązania problemu środowisk produkcyjnych w innych firmach?

Jakie technologie są używane ?

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

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

  • landrush - Lokalnego micro DNS, który automatycznie przyznaje maszynom IP. 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 1

  • 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ąć

Dyskusja

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

Jedno z najbardziej dojrzałych narzędzi DevOps

Proces wprowadzania zmiany

Puppet DSL

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

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

Nawet ludzie nie znający Puppeta są w stanie odgadnąć co może oznaczać taki zapis

Zasób Puppet

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

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

Puppet posiada wiele wbudowanych zasobów

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 2

  • Uruchomienie VM przy użyciu Vagranta: puppetlabs/ubuntu-14.04-64-nocm
  • Zainstalowanie Puppet goo.gl/a2lGAR:
    wget https://apt.puppetlabs.com/puppetlabs-release-trusty.deb
    sudo dpkg -i puppetlabs-release-trusty.deb
    sudo apt-get update && sudo apt-get install -y puppet

Zadanie 3

  • Napisz prosty manifest instalujący pakiety: git, vim
  • Dodający użytkownika javascript
  • Oraz utworzyć katalog użytkownika i SSH /home/javascript, /home/javascript/.ssh
  • Sprawdz manifest przy użyciu: puppet parser validate plik.pp
  • Uruchom przy użyciu Vagrant

Struktura kodu Puppet

Modułowość

Kod puppet umieszczamy w:

  • modułach
  • klasach
  • definicjach

Struktura modułu

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

Moduły 101

  • Moduły znajdują się na PM
  • Moduły zawierają kod Puppet
  • Moduły posiadają określony układ
  • Moduły mogą być prosto instalowane

Wiecej: http://slides.com/cardil/...

Generowanie modułu

puppet module generate company/modulename

Generuje strukturę modułu

Klasy

  • Klasy to nazwane bloki kodu Puppet
  • Są definiowane w modułach do późniejszego użycia
  • Nie są automatycznie wywoływane, muszą być dołączone do katalogu
  • Generalnie opisują średnie i duże fragmenty funkcjonalności
  • Nazwa może mylić z innymi językami programowania

Klasy przykład

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

Użycie klasy

# only once in catalog
# class is a resource
class { 'apache':
  version => 'latest',
}
# or simply
include apache
include apache

Definicje

  • To bloki kodu puppet które mogą być wywołane wielokrotnie z różnymi parametrami
  • Mogą być użyte jako proste makra dla powtarzających się operacji

Definicje - przykład

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

Zadanie 4

  • Wykorzystując kod z zadania 2 utworzyć moduł puppet inazwisko/javascript i przenieść kod do klas i definicji
  • uruchomienie modulu przy pomocy Vagrant

Forge

  • Hosting modułów Puppet - odpowiednik repozytorium pakietów
  • Automatycznie zintegrowane z poleceniem puppet module
  • Wiele narzędzi wykorzystuje: librarian-puppet, r10k
  • Jedynie publiczne moduły, bez możliwości instalacji wewnątrz sieci (są alternatywy: unibet/puppet-forge-server)

Szukanie i pobieranie modułów

puppet module list # listuje moduły
puppet search apt # szuka modułu po słowie kluczowym
puppet module install puppetlabs/apt # instaluje moduł

Jakie moduły wybierać?

pisane przez Puppetlabs, testowane na wielu platformach

pisane przez innych autorów, zaakceptowane przez Puppetlabs jako jedne z najlepszych spełniających wymagania

Ilość ściągnięć, historia, kto developuje, zależności, instalacja pakietów systemu, wartości na sztywno

librarian-puppet

  • Upewnia się, że odpowiednie moduły są zainstalowane
  • Obsługuje plik Puppetfile
    forge 'https://forge.puppetlabs.com/'
    mod 'puppetlabs/apt'
    mod 'puppetlabs/firewall', '1.8.0'
  • Instalacja z Rubygems: gem install librarian-puppet
  • Uruchomienie: librarian-puppet update --verbose w katalogu pliku Puppetfile

Zadanie 5

  • Napisz manifest który:
    • zainstaluje librarian-puppet(instalacja ruby-dev, File, Package)
    • zaaktualizuje plik w katalogu /etc/puppet/Puppetfile
    • uruchomi polecenia librarian-puppet update --verbose
  • Uruchomić ten skrypt przy pomocy Vagrant

Środowisko deweloperskie

JavaScript

JavaScript

  • skryptowy język programowania
  • stworzony przez firmę Netscape
  • dominujący w przeglądarkach internetowych
  • coraz bardziej popularny w wykorzystaniu serwerowym dzięki Nodejs

Node.js

  • środowisko programistyczne JavaScript
  • przystosowane do uruchamiania aplikacji po stronie serwera
  • oraz wielu różnych narzędzi deweloperskich i programów
  • Menadżer pakietów dla JavaScript
  • Największa ilość bibliotek
  • Łatwość publikacji własnego kodu

Moduł

puppetlabs/nodejs

Dlaczego wybrałem

puppetlabs/nodejs

  • możliwość instalacji nodejs
  • udostępnia provider dla zasobu package
  • możliwość instalacji biblioteki lokalnie jak i globalnie
  • bezpośredni autorzy Puppeta, duża ilość instalacji, aktywnie wspierany, mozliwość parametryzacji

https://forge.puppetlabs.com/puppetlabs/nodejs

Zadanie 6

  • Instalacja modułu puppetlabs/nodejs(za pomocą librarian-puppet)
  • Napisanie manifestu zawierającego nodejs include nodejs
  • Uruchomienie na Vagrant i przetestowanie działania poprzez wpisanie w konsole node

Czym są

Puppet providers?

Provider

  • Zasoby w Puppet posiadają wiele providerów
  • Każdy provider jest konkretną implementacją dla konkretnego systemu operacyjnego lub podsystemu.
  • Na przykład, dla typu package istnieje wiele providerów między innymi: aix, appdmg, windows, apt, rpm, pip3
  • Puppet automatycznie wybiera odpowiedni provider

Używanie konkretnego providera

Istenieje możliwość wymuszenia konkretnego providera dla każdego typu

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

Dodatkowe providery

  • istnieje możliwość dodawania dodatkowych providerów
  • należy napisać odpowiedni kod w języku Ruby
  • niektóre moduły na PuppetForge udostępniają takie providery

Zadanie 7

  • Instalacja biblioteki lolcat z RubyGems przy pomocy zasobu package i providera gem
  • Sprawdzenie działania poprzez wpisane lolcat -h

Sposoby użycia modułu

puppetlabs/nodejs

Instalacja Node.js

include nodejs

Po wywołaniu będziemy mogli wywołać polecenie node

Instalacja biblioteki (globalna)

package { 'express':
  ensure   => 'present',
  provider => 'npm',
}

Instalacja paczki express dla każdego użytkownika w systemie.

Instalacja biblioteki (lokalnie)

nodejs::npm { 'express from the npm registry':
  ensure  => 'present',
  package => 'express',
  target  => '~/node_modules',
}

Instalacja biblioteke express do ~/node_modules dla aktualnego użytkownika w systemie.

Nie możemy wykorzystać zasobu package bo instaluje on w scieżkach systemowych

Zadanie 8

  • Zainstalować globalnie paczkę grunt-cli przy użyciu puppetlabs/nodejs
  • Zainstalować lokalnie paczkę mongodb przy użyciu puppetlabs/nodejs

Sprawdzenie

  • Za pomocą git sklonować repozytorium: https://github.com/twitter/typeahead.js
  • Odpalić instalację zależności poprzez npm install
  • odpalić budowanie się projektu poprzez polecenie grunt

Podsumowanie

warsztatu

Co poznaliśmy? Powtórka

  • środowisko deweloperskie: co to takiego, jak je tworzyć?
  • Wprowadzenie do Vagrant
  • Przypomnienie z Puppet DSL
  • Modułowość - klasy i definicje w Puppet
  • Puppetforge i zewnętrzne moduly (librarian-puppet)
  • Opis modułu puppetlabs/nodejs
  • Stworzenie środowiska deweloperskiego JS przy użyciu Puppet

Co dalej?

  • Testy rspec/beaker
  • Dziedziczenie klas i podział na moduły
  • Tworzenie niestandardowych funkcji oraz faktów
  • Tworzenie dodatkowych typów i providerów

Dziękuje