Język DSL Puppeta cz.1

Załóżmy, że mamy do postawienia kilkaset wirtualnych serwerów z określonym oprogramowaniem i konfiguracją. Jeżeli chcielibyśmy wykonać to zadanie ręcznie byłoby to bardzo pracochłonne. W instalacji wirtualnych maszyn pomoże nam z pewnością Kickstart, a z konfiguracją tych maszyn może nam pomóc dowolny menadżer konfiguracji. Najbardziej znanym takim menadżerem jest z pewnością Puppet. Puppet odczytuje konfiguracje serwera zawartą w tzw. manifeście. Zazwyczaj jest to plik tekstowy z rozszerzeniem .pp.

 

Pierwszy manifest.

Manifest to plik zawierający konfigurację klienta napisaną w deklaratywnym języku Puppeta lub w języku Ruby DSL (domain-specific language). Główny plik z manifestem Puppeta to  /etc/puppetlabs/code/environments/production/manifests/site.pp. Manifesty Puppeta powstają wg schematu:

Wszystkie dostępne rodzaje zasobów Puppeta można wylistować po wpisaniu komendy:

Zasoby zadeklarowane na węźle o sprecyzowanej nazwie (np. ppagent1.example.com) zostaną utworzone na tym konkretnym węźle. Zasoby zadeklarowane na węźle domyślnym (default) zostaną utworzone na tych wszystkich agentach Puppeta, które nie zostały wprost zadeklarowane wcześniej (tutaj ppagent1.example.com). Np. do pliku site.pp wpisujemy

Uruchomienie manifestu w trybie master/agent:

lub po prostu:

W trybie stand-alone manifest wykonywany jest tylko na hoście na którym został uruchomiony. W tym wypadku manifest może być w utworzony w dowolnym katalogu. Uruchamiamy go komendą:

 

Pakiety.

Załóżmy, że chcemy uruchomić serwer www nginx z przykładową stroną. Najpierw musimy zainstalować epel-relase a później pakiet nginx. Zawartość pliku /etc/puppetlabs/code/environments/production/manifests/site.pp:

Wyrażenie “->” oznacza kolejność wykonywania działań. Jeżeli w repozytoriach są różne wersje nginx, możemy wskazać którą konkretną wersję chcemy zainstalować:

Jeżeli instalujemy nginxa to nie potrzebujemy apacha, a zatem puppet powinien go odinstalować jeżeli jest już w systemie:

Jeżeli zależy nam na tym aby mieć zainstalowaną najnowszą wersję danego pakietu:

Ale nie zawsze jest to najlepsze rozwiązanie ponieważ najnowsza wersja danego pakietu może mieć inną konfigurację i system może nie działać tak jak sobie tego życzymy. Taki sposób zarządzania aktualizacjami systemu może być dobrym rozwiązaniem gdy mamy swoje repozytorium dla serwerów i kontrolujemy jakie pakiety są w tym repozytorium. A zatem na chwilę obecną manifest wygląda następująco:

 

Usługi.

Po instalacji nginx’a należałoby go jeszcze uruchomić. W tym celu edytujemy /etc/puppetlabs/code/environments/production/manifests/site.pp .

Atrybut require określa zależności pomiędzy zasobami. W tym przypadku instalacja nginx’a możliwa jest po odinstalowaniu apacha, a uruchomienie nginxa po jego zainstalowaniu. Wyrażenie Package w zapisie require => Package napisane jest z dużej litery ponieważ odnosi się do nazwanej instancji zasobu z pakietem. Kod Puppeta wylistowany powyżej jest równoważny z:

Czyli pakiet nginx musi zostać zainstalowany przed (before) uruchomieniem go.

Na agencie wykonujemy zmodyfikowany manifest:

Przykład zależności plików jednych od drugich w pętli:

Dodanie opcji --graph podczas uruchamiania manifestu wyświetli diagram zależności zasobów.

Puppet potrafi kontrolować czy dana usługa ma być uruchamiana w czasie startu systemu. Np. aby wyłączyć automatyczne uruchamianie nginxa podczas staru systemu w przypadku gdy usługa jest zarządzana przez framework high-availability Heartbeat:

Automatyczne włączenie usługi przy starcie systemu wymaga ustawienia atrybutu enable => true.

Skrypt zarządzania daną usługą powinien obsługiwać opcję status, puppet będzie chciał ją użyć. Jeżeli skrypt nie ma takiej opcji to ją wyłączamy:

Puppet sprawdzi wtedy czy dana usługa po uruchomieniu jest na liście uruchomionych procesów systemowych (np. ps). Jeżeli ta usługa nie pojawia się na liście procesów systemowych to można zdefiniować własny wzorzec szukania procesu:

Jeżeli nie ma żadnej możliwości na odnalezienie uruchomionego procesu na liście procesów, można samemu wskazać puppetowi komendę, która zwróci określony status (0 usługa działa, inna wartość usługa nie działa):

 

Jeżeli jest potrzeba restartu usługi lub wczytania nowych ustawień z plików konfiguracyjnych, puppet domyślnie restartuje usługę wyłączając ją (stop) i włączając (start). Ponieważ wiele usług zapewnia opcje restart lub reload a wiele demonów przechowuje w pamięci użyteczne dane o stanie usługi, to lepiej wskazać puppetowi jak ma przeładować lub zrestartować usługę:

 

Użytkownicy.

Załóżmy, że na maszynie server1 chcemy założyć konto dla nowego użytkownika user1. Zmieniamy zatem zawartość pliku site.pp :

Atrybut home ustawia ścieżkę do katalogu domowego użytkownika, katalog ten zostanie utworzony tylko  wtedy, gdy zostanie ustawiony również atrybut managehome => true. Chociaż puppet potrafi ustawiać hasła dla kont użytkowników (atrybut password) rekomendowana jest autentykacja przez klucze SSH.

Usunięcie deklaracji wcześniej założonego konta użytkownika z manifestu nie spowoduje usunięcia tego konta. Gdy zajdzie potrzeba usunięcia konta użytkownika można to zrobić następująco.:

Katalog domowy użytkownika user1 nie zostanie jednak usunięty.

 

Kontrola dostępu.

Puppet może zarządzać kluczami publicznymi SSH i autoryzować je dla kont użytkowników dzięki zasobowi ssh_authorized_key. Jeżeli mamy już klucz publiczny to możemy go wykorzystać:

Jeżeli nie to należy go wygenerować:

Teraz modyfikujemy zawartość pliku site.pp :

Uruchomienie manifestu puppeta na agencie ppagent1.example.com:

Klucz publiczny znajdzie się teraz na liście kluczy autoryzowanych dla użytkownika user1:

My jako root z hosta ppmaster.example.com będziemy mogli się logować bez hasła na konto user1 na hosta ppagent1.example.com:

 

Jeżeli chcemy wygenerować klucz dla innego użytkownika niż aktualnie zalogowany:

Odczyt klucza publicznego:

Korzystając z tak wygenerowanego klucza będziemy mogli logować się bez hasła z konta user1@ppmaster na konto user1@ppagent1.

 

Jeżeli natomiast zajdzie potrzeba zablokowania użytkownikowi user1 logowania to można tymczasowo usunąć jego klucz SSH z Puppeta:

Jeżeli natomiast użytkownik user1 miał ustawioną kontrolę dostępu na podstawie hasła a nie klucza ssh (co nie jest rekomendowane) to możemy mu zablokować możliwość logowania do systemu ustawiając atrybut password => '*' :

 

Zadania.

Puppet daje możliwość wykonywania określonych komend bezpośrednio przy wykorzystaniu zasobu exec, np:

Wymagane jest podanie przez nas pełnej ścieżki do pliku ale możemy także dostarczyć listę takich ścieżek atrybutem path.

Możliwe jest także określenie domyślnej ścieżki dla wszystkich zasobów exec:

Po takiej deklaracji możliwe jest podawania komend bez pełnej ścieżki:

Zasób exec spowoduje uruchomienie jednak komendy za każdym razem gdy uruchomiony zostanie na agencie manifest Puppeta. Jeżeli natomiast chcemy daną komendę uruchomić tylko jeden raz to robimy to w sposób, który ilustruje przekład poniżej.

Atrybut cwd  zmienia bieżący katalog. Puppet sprawdza czy istnieje plik określony przez atrybut creates. Jeżeli nie istnieje to jest uruchamiany atrybut command. Jeżeli istnieje to Puppet nie robi nic.

Można to samo osiągnąć atrybutem unless lub onlyif.

Komendy można także wykonywać automatycznie jeżeli zmieni się zawartość jakiegoś pliku.

Komendy można także wykonywać sekwencyjnie. Odpowiednikiem zapisu:

jest zapis:

 

Cron.

Jeżeli istnieje potrzeba wykonywania pewnych czynności okresowo to realizujemy to przy pomocy crona. Puppet może również zarządzać cronem na naszych agentach.

Jeżeli pozostałe argumenty crona takie jak month, day, weekday nie zostały podane tzn. , że przyjmują one wartość domyślną *. Domyślnie zadania crona uruchamia root, ale możemy je uruchamiać także jako inny użytkownik dzięki atrybutowi user:

 

Sudo (OLD).

Jeżeli chcemy aby aby zwykli użytkownicy mieli jakieś uprawnienia superużytkownika root to wykonujemy poniższe kroki.

Tworzymy katalogi dla konfiguracji /etc/sudoers:

Zakładamy plik /puppet/modules/sudoers/manifests/init.pp o treści:

Zakładamy plik /puppet/modules/sudoers/files/sudoers z zawartością:

Sprawdzamy poprawność pliku:

Do definicji węzła server1 dodajemy wczytywanie nowej klasy sudoers:

Tak jak po każdej zmianie tak i teraz uruchamiamy ponownie papply:

 

 

Leave a Reply

Your email address will not be published.