Infrastructure as Code (IaC) to paradygmat zarządzania infrastrukturą IT, w którym konfiguracja serwerów, sieci i usług jest definiowana w plikach deklaratywnych lub proceduralnych, przechowywanych w systemie kontroli wersji.
Ansible jest jednym z najpopularniejszych narzędzi do automatyzacji konfiguracji, zarządzanym przez Red Hat. Jego główną zaletą jest bezagentowa architektura - do zarządzania węzłami wystarczy dostęp SSH i interpreter Pythona na zdalnej maszynie.
W przeciwieństwie do skryptów bash, Ansible zapewnia idempotentność: wielokrotne uruchomienie playbooka daje ten sam efekt, a przy stanie zgodnym nie wprowadza żadnych zmian.
Warsztat praktyczny obejmuje napisanie playbooka instalującego serwer Nginx z wykorzystaniem modułów apt, copy, service oraz handlera do restartu usługi.
Celem warsztatu jest przygotowanie administratora do wdrożenia automatyzacji konfiguracji w środowisku produkcyjnym. Uczestnik po zakończeniu zajęć powinien samodzielnie tworzyć playbooki Ansible i zarządzać nimi w systemie kontroli wersji.
Szczególny nacisk położony jest na zrozumienie idempotentności - kluczowej koncepcji odróżniającej Ansible od zwykłych skryptów. Uczestnik nauczy się, jak pisać playbooki, które można bezpiecznie uruchamiać wielokrotnie.
Wiedza zdobyta podczas warsztatu ma charakter uniwersalny - Ansible jest używany zarówno w małych środowiskach developerskich, jak i w dużych centrach danych zarządzających tysiącami serwerów.
Umiejętność debugowania playbooków i rozwiązywania problemów z łącznością SSH to kompetencje niezbędne w codziennej pracy z Ansible.
Prezentacja została podzielona na sześć bloków tematycznych zgodnie z zasadą 20 minut teorii i 30 minut praktyki.
Część pierwsza wprowadza w paradygmat IaC, wyjaśniając, dlaczego tradycyjne zarządzanie ręczne jest niebezpieczne i jakie korzyści daje automatyzacja.
W części drugiej omówimy różne narzędzia automatyzacji, a następnie skupimy się na architekturze Ansible - bezagentowej, pushowej, wykorzystującej SSH i moduły Pythona.
Część trzecia i czwarta to przygotowanie do laboratorium: omówienie struktury projektu Ansible, składni YAML, zmiennych, faktów, templatów, warunków, pętli i handlerów.
Najważniejszą częścią jest laboratorium, w którym uczestnicy samodzielnie napiszą playbook instalujący Nginx i zweryfikują jego działanie.
W tradycyjnym modelu zarządzania każdy administrator loguje się na serwer przez SSH i wykonuje komendy ręcznie. Nawet przy użyciu notatek i dokumentacji, proces ten jest podatny na błędy i niepowtarzalny.
Problem snowflake servers (serwery-płatki śniegu) polega na tym, że każdy serwer w infrastrukturze staje się unikalny z powodu nagromadzenia ręcznych zmian, różnych wersji pakietów i indywidualnych konfiguracji.
Odtworzenie serwera po awarii w modelu ręcznym wymaga od administratora przypomnienia sobie wszystkich zmian, które zostały naniesione od momentu instalacji. W praktyce oznacza to wiele godzin pracy i ryzyko pominięcia krytycznych konfiguracji.
Błędy ludzkie są nieuniknione przy ręcznym zarządzaniu. Pomylenie serwerów produkcyjnych z testowymi, literówki w konfiguracji firewalla czy niepoprawne uprawnienia do plików to tylko niektóre z typowych problemów.
Problem snowflake servers narasta z czasem. Każda ręczna zmiana, każda aktualizacja, każda poprawka wprowadza różnicę między serwerami. Po kilku miesiącach serwery, które startowały identycznie, mogą się znacząco różnić.
W praktyce oznacza to, że dodanie nowego serwera do klastra wymaga ręcznego odtworzenia wszystkich zmian, które zostały naniesione na istniejące serwery. Jest to proces czasochłonny i podatny na błędy.
Z perspektywy bezpieczeństwa, snowflake servers są koszmarem. Administrator nie wie, które serwery mają zainstalowane wszystkie łatki bezpieczeństwa, a które mają przestarzałe wersje pakietów.
IaC rozwiązuje ten problem poprzez przechowywanie definicji konfiguracji w plikach, które są wspólne dla wszystkich serwerów. Każdy nowy serwer jest konfigurowany automatycznie na podstawie tych samych definicji.
Ewolucja zarządzania konfiguracją przeszła przez cztery wyraźne fazy. Faza 1 to czysto ręczna konfiguracja, która jest całkowicie niepowtarzalna i uzależniona od wiedzy administratora.
Faza 2 to skrypty bash. Są one lepsze niż ręczna konfiguracja, ale mają poważne wady: nie są idempotentne, trudno je testować i nie dają informacji zwrotnej o zgodności stanu.
Faza 3 to podejście deklaratywne, reprezentowane przez narzędzia takie jak Ansible. Administrator nie pisze "jak" coś zrobić, ale "co" ma być zrobione.
Faza 4 to pełne wdrożenie IaC z wykorzystaniem kontroli wersji, automatycznego stosowania konfiguracji przez CI/CD oraz testowania zmian w środowisku staging przed wdrożeniem na produkcję.
Idempotentność to właściwość operacji, która polega na tym, że wielokrotne jej wykonanie daje ten sam rezultat co wykonanie jednokrotne. W kontekście IaC oznacza to, że playbook można uruchomić wielokrotnie bez ryzyka wprowadzenia niepożądanych zmian.
Rozważmy typowy skrypt bash: apt install nginx. Przy pierwszym uruchomieniu pakiet zostanie zainstalowany. Przy drugim uruchomieniu apt sprawdzi, że pakiet jest już zainstalowany, ale skrypt i tak wykona operację i zgłosi sukces. Ansible natomiast sprawdzi, czy nginx jest zainstalowany, i jeśli tak, pominie zadanie.
Moduł copy w Ansible jest dobrym przykładem idempotentności. Sprawdza on sumę kontrolną (MD5/SHA1) pliku źródłowego i docelowego. Jeśli plik docelowy ma tę samą sumę kontrolną, Ansible nie kopiuje pliku ponownie.
Dzięki idempotentności administrator może bezpiecznie uruchamiać playbooki w pętli cron lub w ramach CI/CD, wiedząc, że nie spowoduje to nieoczekiwanych zmian w systemie.
Model pożądanego stanu (desired state) jest fundamentalny dla zrozumienia IaC. Administrator opisuje w pliku YAML, jaki ma być końcowy stan systemu, a narzędzie samo decyduje, jakie operacje wykonać, aby ten stan osiągnąć.
Na przykład zamiast pisać skrypt: "apt update, apt install nginx -y, systemctl start nginx, systemctl enable nginx", w Ansible piszemy: "stan: nginx zainstalowany, uruchomiony i włączony przy starcie".
Porównanie do SQL jest pouczające: podejście imperatywne to SELECT * FROM users WHERE name = 'ala', a podejście deklaratywne to CREATE TABLE users (name VARCHAR, email VARCHAR) - definiujemy strukturę, a nie sposób jej uzyskania.
W praktyce podejście deklaratywne znacznie upraszcza zarządzanie konfiguracją, ponieważ administrator nie musi myśleć o kolejności operacji ani o przypadku brzegowym, gdy konfiguracja jest już zgodna.
Przechowywanie konfiguracji w systemie kontroli wersji to jedna z najważniejszych zalet IaC. Git pozwala na śledzenie każdej zmiany, co w praktyce oznacza pełną historię konfiguracji każdego serwera w infrastrukturze.
W tradycyjnym modelu, gdy coś przestaje działać, administrator nie wie, co się zmieniło. W modelu IaC wystarczy sprawdzić git log, aby zobaczyć, jakie zmiany zostały wprowadzone i przez kogo.
Code review to kolejna kluczowa zaleta. Zmiany w konfiguracji są zatwierdzane przez pull requesty, gdzie inni administratorzy mogą je przejrzeć i skomentować.
Gałęzie w Git umożliwiają testowanie zmian w środowisku staging zanim trafią na produkcję. Pozytywny wynik testów automatycznych w stagingu jest warunkiem wdrożenia na produkcję.
Powtarzalność to największa zaleta IaC. Niezależnie od tego, który administrator uruchamia playbook, rezultat jest identyczny. Nie ma już sytuacji, w której różni administratorzy konfigurują serwery w różny sposób.
Szybkość wdrożenia nowych serwerów jest dramatycznie większa. W tradycyjnym modelu konfiguracja nowego serwera mogła zająć cały dzień. Z IaC i Ansible to kwestia kilku minut na uruchomienie playbooka.
Audytowalność jest kluczowa z perspektywy zgodności z regulacjami (PCI DSS, HIPAA, SOX). W modelu IaC każda zmiana konfiguracji ma wpis w historii Gita z informacją o autorze, dacie i zakresie zmian.
Odtwarzalność po awarii to jedna z najważniejszych zalet w środowisku produkcyjnym. Gdy serwer ulegnie awarii, administrator uruchamia nową maszynę, wykonuje ansible-playbook i po kilku minutach serwer jest w pełni skonfigurowany.
Scenariusz odtworzenia serwera po awarii doskonale ilustruje różnicę między tradycyjnym zarządzaniem a IaC. W pierwszym przypadku administrator musi polegać na swojej pamięci i notatkach, które często są niekompletne.
W praktyce odtworzenie serwera w tradycyjnym modelu oznacza: instalację systemu operacyjnego, instalację niezbędnych pakietów, przywrócenie konfiguracji z kopii zapasowej (jeśli istnieje), ręczne dostrojenie parametrów i weryfikację.
W modelu IaC proces jest znacznie prostszy: nowa maszyna otrzymuje adres IP, administrator aktualizuje inventory, uruchamia ansible-playbook i po kilku minutach serwer jest gotowy do pracy.
Dodatkowo, ponieważ playbook jest przechowywany w Git, administrator może wybrać konkretną wersję konfiguracji (commit, tag), która była na serwerze przed awarią.
Wprowadzenie do IaC stanowi fundament dalszej części prezentacji. Zrozumienie koncepcji idempotentności, pożądanego stanu i deklaratywnego podejścia jest niezbędne do efektywnej pracy z Ansible.
W kolejnych slajdach omówimy konkretne narzędzia automatyzacji, ze szczególnym uwzględnieniem Ansible. Przedstawimy architekturę, strukturę projektu i praktyczne przykłady użycia.
Warto pamiętać, że IaC to nie tylko narzędzia, ale przede wszystkim zmiana sposobu myślenia o zarządzaniu infrastrukturą.
Przejście na IaC wymaga inwestycji czasu w naukę narzędzi i zmianę procesów, ale zwraca się wielokrotnie w postaci szybszego wdrażania, mniejszej liczby błędów i lepszej kontroli nad infrastrukturą.
Ansible został przejęty przez Red Hat w 2015 roku i od tego czasu dynamicznie się rozwija. Jego główną zaletą jest bezagentowa architektura - nie wymaga instalowania żadnego oprogramowania na zarządzanych węzłach, wystarczy SSH i Python.
Puppet, stworzony przez Puppet Labs w 2005 roku, był pierwszym popularnym narzędziem do zarządzania konfiguracją. Używa własnego języka deklaratywnego (Puppet Language) i działa w modelu pull.
Chef, napisany w Ruby, jest popularny w środowiskach developerskich. Używa Ruby DSL, co daje dużą elastyczność, ale wymaga znajomości tego języka.
SaltStack (obecnie VMware Salt) oferuje zarówno model push, jak i pull. Używa magistrali komunikacyjnej ZeroMQ, co zapewnia bardzo wysoką wydajność przy zarządzaniu tysiącami węzłów.
Różnica między provisioning a configuration management jest często mylona przez początkujących administratorów. Provisioning dotyczy tworzenia i zarządzania samą infrastrukturą: maszynami wirtualnymi, sieciami, dyskami, load balancerami.
Terraform jest obecnie standardem w provisioning'u. Używa deklaratywnego języka HCL (HashiCorp Configuration Language) i może zarządzać infrastrukturą w wielu chmurach jednocześnie.
Configuration management zajmuje się tym, co dzieje się wewnątrz maszyn po ich utworzeniu: instalacja pakietów, konfiguracja usług, tworzenie użytkowników, zarządzanie plikami konfiguracyjnymi.
W praktyce oba narzędzia często współpracują: Terraform tworzy maszyny wirtualne w chmurze, a następnie przekazuje ich adresy IP do Ansible, który konfiguruje je zgodnie z wymaganiami.
Architektura bezagentowa jest główną zaletą Ansible w porównaniu do Puppet czy Chef. Brak agenta oznacza brak potrzeby zarządzania certyfikatami, brak problemów z aktualizacją agenta i brak dodatkowego obciążenia na zarządzanych węzłach.
Gdy administrator uruchamia playbook, Ansible nawiązuje połączenie SSH z każdym węzłem, kopiuje moduły (skrypty Pythona) do węzła, wykonuje je zdalnie i zbiera wyniki. Po zakończeniu wszystkie pliki tymczasowe są usuwane.
Moduły Ansible są pisane w Pythonie i wykonywane na zdalnym węźle. Każdy moduł to osobny skrypt, który wykonuje konkretne zadanie: instaluje pakiet, kopiuje plik, restartuje usługę.
Model push oznacza, że to kontroler inicjuje komunikację. Administrator uruchamia ansible-playbook, który łączy się z węzłami i wypycha konfigurację.
Uwierzytelnianie przez klucz SSH jest standardem w Ansible. Klucz publiczny jest dodawany do pliku ~/.ssh/authorized_keys na zarządzanych węzłach, a klucz prywatny znajduje się na kontrolerze.
W środowiskach produkcyjnych klucz SSH powinien być zabezpieczony frazą (passphrase) i zarządzany przez ssh-agent. Można też używać SSH certificates (ssh-keygen -s CA) dla większych środowisk.
ControlMaster i ControlPersist to funkcje OpenSSH używane przez Ansible do utrzymywania otwartego połączenia SSH między zadaniami w playbooku. Bez nich każde zadanie wymagałoby nowego połączenia SSH, co znacząco spowalnia wykonanie.
Pipelining to optymalizacja, która wysyła moduły przez stdin SSH zamiast przez osobne połączenie SFTP. Wymaga wyłączenia opcji requiretty w sudoers na węzłach zarządzanych.
Ansible wymaga Pythona na kontrolerze (kontroler to maszyna, z której uruchamiamy playbooki). Najnowsze wersje Ansible wymagają Pythona 3.12 lub nowszego.
Instalacja z pip (pip install ansible) jest zalecana, ponieważ zapewnia najnowszą wersję. Można użyć środowiska wirtualnego (venv), aby uniknąć konfliktów z pakietami systemowymi.
W systemach RHEL/CentOS/Fedora, Ansible jest dostępny z repozytoriów EPEL lub jako pakiet ansible-core z modułami społeczności.
Należy pamiętać, że Ansible wymaga Pythona tylko na kontrolerze. Na zarządzanych węzłach wystarczy Python (bez Ansible) i dostęp SSH.
Zarządzane węzły nie wymagają instalacji Ansible ani żadnego agenta. Jedynym wymaganiem jest Python w wersji 3.9+ oraz dostęp SSH z kontrolera.
Moduły Ansible są kopiowane na węzeł przez SFTP lub SSH (z pipelining) i wykonywane przez lokalny interpreter Pythona. Po wykonaniu modułu wyniki są zwracane w formacie JSON, a pliki tymczasowe są usuwane.
Dla środowisk, gdzie Python nie jest domyślnie zainstalowany (np. minimalistyczne kontenery Docker), Ansible oferuje moduł raw, który wykonuje komendy bezpośrednio przez SSH bez potrzeby Pythona.
W przypadku systemów Windows, Ansible używa WinRM (Windows Remote Management) zamiast SSH. Wymaga to konfiguracji WinRM na węźle Windows i użycia ansible_connection=winrm w inventory.
Moduły Ansible to podstawowe jednostki pracy w playbooku. Każdy moduł wykonuje konkretne zadanie i zwraca wynik w formacie JSON z informacją o zmianie (changed, ok, failed).
Moduł ping jest najprostszym modułem - testuje, czy Ansible może połączyć się z węzłem przez SSH i wykonać moduł Pythona. Zwraca pong przy sukcesie.
Moduły do zarządzania pakietami (apt, yum, dnf) są idempotentne - sprawdzają, czy pakiet jest już zainstalowany, i instalują go tylko wtedy, gdy jest nieobecny.
Moduł copy kopiuje plik z kontrolera na węzeł i sprawdza sumę kontrolną, aby uniknąć niepotrzebnych kopii. Moduł template działa podobnie, ale używa szablonów Jinja2 z dynamicznymi wartościami.
Komendy ad-hoc są przydatne do szybkich, jednorazowych zadań, gdy nie chcemy tworzyć pełnego playbooka. Składnia to: ansible
Flaga -b (--become) oznacza eskalację uprawnień (domyślnie sudo). Jest niezbędna do zadań wymagających uprawnień administratora, takich jak instalacja pakietów czy restartowanie usług.
Wzorzec hostów (all, web, db) określa, do których hostów z inventory ma być zastosowane polecenie.
Komendy ad-hoc są idealne do: sprawdzenia, które hosty są dostępne (ansible all -m ping), szybkiej aktualizacji pakietów lub sprawdzenia wersji systemu.
Struktura projektu Ansible nie jest sztywno narzucona, ale istnieją przyjęte konwencje. Dla małych projektów wystarczy jeden lub dwa pliki, dla większych zaleca się organizację według standardów.
Plik ansible.cfg definiuje globalne ustawienia Ansible: domyślne inventory, użytkownika SSH, ścieżkę do klucza, opcje połączenia SSH (pipelining, ControlMaster), timeouty i poziomy logowania.
Katalog group_vars zawiera pliki YAML nazwane według grup z inventory. Zmienne zdefiniowane w tych plikach są dostępne dla wszystkich hostów w danej grupie.
Role to zaawansowana struktura organizacji kodu w Ansible. Każda rola może zawierać zadania, handlery, zmienne, pliki, szablony i metadane.
Inventory jest sercem projektu Ansible - definiuje, które maszyny są zarządzane i jak się z nimi łączyć. Domyślnie Ansible szuka pliku /etc/ansible/hosts, ale lepiej używać własnego pliku inventory w projekcie.
W formacie INI każda sekcja w nawiasach kwadratowych to grupa. Hosty mogą być wymienione z adresem IP lub nazwą DNS, a zmienne specyficzne dla hosta są dodawane po spacji.
Przykład: [web] web1 ansible_host=192.168.1.10 ansible_user=admin lub [web] 192.168.1.10.
Można również używać zakresów: [web] web[1:5].example.com rozwinie się do web1.example.com do web5.example.com.
Plik hosts.ini pokazuje typową strukturę inventory w małym środowisku. Hosty są podzielone na grupy według pełnionej roli: web (serwery aplikacji), db (bazy danych), loadbalancer.
Aliasy hostów (web01, web02) są wygodniejsze w użyciu niż adresy IP, szczególnie gdy adresy IP mogą się zmieniać. W playbookach odwołujemy się do aliasów, a nie do adresów IP.
Sekcja [all:vars] definiuje zmienne wspólne dla wszystkich hostów. W tym przypadku są to ścieżka do klucza SSH i interpreter Pythona.
Weryfikacja inventory za pomocą ansible-inventory --list pokazuje rozszerzone inventory z wszystkimi zmiennymi i grupami.
Plik ansible.cfg może znajdować się w kilku lokalizacjach. Kolejność pierwszeństwa: ANSIBLE_CONFIG (zmienna środowiskowa), ./ansible.cfg (bieżący katalog), ~/.ansible.cfg, /etc/ansible/ansible.cfg.
Opcja host_key_checking = False wyłącza sprawdzanie klucza SSH hosta w known_hosts. Jest to wygodne w środowiskach testowych, ale w produkcji powinno być włączone dla bezpieczeństwa.
Pipelining to jedna z najważniejszych optymalizacji. Bez niej Ansible wysyła moduły przez SFTP (osobne połączenie SSH), a z pipelining moduły są wysyłane przez stdin SSH.
Opcja gathering = smart w połączeniu z fact_caching_timeout pozwala uniknąć niepotrzebnego zbierania faktów przy każdym uruchomieniu playbooka.
Playbook to plik YAML zawierający jeden lub więcej play. Każdy play definiuje: które hosty są celem (hosts), czy wymagana jest eskalacja uprawnień (become) oraz listę zadań do wykonania (tasks).
Zadania w playbooku są wykonywane sekwencyjnie. Jeśli któreś zadanie zakończy się błędem (failed), dalsze zadania w play nie są wykonywane. Można zmienić to zachowanie przez ignore_errors lub failed_when.
Flaga become: yes oznacza, że Ansible użyje sudo do wykonania zadań jako root. Można też określić konkretnego użytkownika: become_user: postgres.
Po uruchomieniu ansible-playbook, Ansible łączy się z hostami z grupy web, zbiera fakty (opcjonalnie), a następnie wykonuje każde zadanie, porównując stan pożądany z aktualnym.
YAML to format danych, który jest znacznie bardziej czytelny niż JSON czy XML. Ansible używa YAML jako formatu do definiowania playbooków, inventory (w formacie YAML) i zmiennych.
Wcięcia w YAML muszą być wykonane spacjami, nigdy tabulatorami. Różne edytory tekstu mogą domyślnie używać tabulatorów, co prowadzi do błędów składni.
Lista w YAML to sekwencja elementów poprzedzonych myślnikiem (- ). Słownik to pary klucz-wartość oddzielone dwukropkiem (:). Ważne: po dwukropku zawsze musi być spacja.
Najczęstszym błędem w plikach YAML jest niepoprawne wcięcie - albo użycie tabulatora zamiast spacji, albo nieprawidłowa liczba spacji.
Zmienne w Ansible pozwalają na parametryzację playbooków. Zamiast na sztywno wpisywać nazwę pakietu czy ścieżkę, używamy zmiennych, które są podstawiane podczas wykonywania playbooka.
Fakty (facts) są zbierane przez moduł setup na początku każdego playbooka. Zawierają szczegółowe informacje o systemie: nazwę hosta, adresy IP, system operacyjny, wersję jądra, procesor, pamięć, dyski.
Priorytety zmiennych są ważne do zrozumienia, która wartość będzie użyta, gdy zmienna jest zdefiniowana w wielu miejscach.
Możliwość zbierania faktów pozwala na pisanie playbooków, które dostosowują się do systemu: na Debianie używamy apt, na RHEL yum, na FreeBSD pkg.
Jinja2 to potężny silnik szablonów, który pozwala na tworzenie dynamicznych plików konfiguracyjnych. Działa to tak: tworzymy plik szablonu z rozszerzeniem .j2, w którym umieszczamy zmienne w podwójnych nawiasach klamrowych.
Moduł template w Ansible działa podobnie do copy, ale przed skopiowaniem przetwarza szablon Jinja2. Można w nim używać zmiennych, faktów, pętli i warunków.
Przykład szablonu nginx.conf.j2: server { listen {{ http_port }}; server_name {{ server_name }}; root {{ web_root }}; }.
Jinja2 wspiera również filtry: {{ zmienna | default('wartosc_domyslna') }}, {{ zmienna | upper }}, {{ lista | join(',') }}.
Warunki when są kluczowe do pisania uniwersalnych playbooków, które działają na różnych systemach operacyjnych lub w różnych konfiguracjach.
Najczęstszym zastosowaniem jest dostosowanie komend do systemu operacyjnego. Na Debianie/Ubuntu pakiet Apache nazywa się apache2, a na RHEL/CentOS - httpd.
Warunki mogą być również używane do sprawdzania wartości zmiennych: when: port is defined and port > 1024.
W Ansible dostępne są również testy Jinja2: defined, undefined, none, boolean, number, string, even, odd.
Pętle w Ansible pozwalają na wykonanie tego samego zadania wielokrotnie z różnymi parametrami. Zamiast pisać osobne zadanie dla każdego pakietu, użytkownika czy pliku, definiujemy listę i używamy pętli.
Składnia loop przyjmuje listę wartości. Dla każdego elementu listy Ansible wykonuje zadanie, podstawiając bieżący element do zmiennej item.
W przypadku instalacji pakietów, pętla loop jest znacznie czytelniejsza niż lista pakietów w jednym zadaniu.
Dla bardziej złożonych przypadków, Ansible oferuje lookup plugins, które mogą być używane jako źródło danych do pętli.
Tagi to mechanizm etykietowania zadań w playbooku, który pozwala na wybiórcze uruchamianie tylko niektórych zadań. Jest to niezwykle przydatne w dużych playbookach.
Na przykład, jeśli mamy playbook, który instaluje pakiety, konfiguruje usługi i uruchamia je, możemy użyć tagów packages, config i service.
Tagi mogą być przypisane do całego play (play-level tags) lub do pojedynczego zadania. Można też użyć tagów dziedziczonych z roli.
Specjalny tag always powoduje, że zadanie jest zawsze wykonywane, chyba że jawnie pominiemy tag always przez --skip-tags always.
Handlery to jedno z najważniejszych narzędzi do zarządzania usługami w Ansible. Są to zadania, które są uruchamiane tylko wtedy, gdy zostały wywołane przez inne zadanie poprzez dyrektywę notify.
Kluczową zaletą handlerów jest to, że są uruchamiane na końcu playbooka, a nie natychmiast po zadaniu, które je wywołało. Dzięki temu, jeśli kilka zadań zmodyfikuje konfigurację, usługa zostanie zrestartowana tylko raz.
W przykładzie, zadanie używające modułu template do skopiowania pliku konfiguracyjnego wywołuje handler restartu tylko wtedy, gdy plik ulegnie zmianie.
Handlery są szczególnie przydatne przy zarządzaniu usługami, które wymagają restartu po zmianie konfiguracji (Nginx, Apache, PostgreSQL, SSH).
Moduł copy to jeden z najczęściej używanych modułów w Ansible. Służy do kopiowania plików z kontrolera na zarządzane węzły. Działa idempotentnie - porównuje sumę kontrolną pliku źródłowego i docelowego przed kopiowaniem.
Ścieżka src jest domyślnie względna wobec katalogu projektu. Najlepiej trzymać pliki w osobnym katalogu files/ wewnątrz projektu.
Parametr mode definiuje uprawnienia w formacie ósemkowym. Ważne: mode w Ansible musi być stringiem ('0644', a nie liczbą 0644).
Moduł copy wspiera również kopiowanie całych katalogów (recurse: yes) oraz używanie zawartości bezpośrednio z playbooka przez parametr content.
Moduł service (lub systemd dla systemów z systemd) zarządza usługami systemowymi. Jest w pełni idempotentny: uruchamia usługę tylko wtedy, gdy jest zatrzymana.
Różnica między state: restarted a state: reloaded jest ważna. Restart zatrzymuje i uruchamia usługę (przerwa w działaniu), podczas gdy reload wysyła sygnał SIGHUP do procesu.
W przypadku Nginx, reload jest preferowany nad restartem, ponieważ nie powoduje przerw w obsłudze klientów.
Dla systemów bez systemd (starsze dystrybucje), moduł service automatycznie wybiera odpowiedni system init.
Moduł user to kompletne narzędzie do zarządzania kontami użytkowników w systemie Linux. Może tworzyć, modyfikować i usuwać użytkowników, a także zarządzać ich grupami, powłoką i katalogiem domowym.
Tworząc użytkownika, można określić grupę podstawową (group), grupy dodatkowe (groups z append: yes) oraz UID.
Parametr state: absent z remove: yes usuwa użytkownika wraz z katalogiem domowym i skrzynką pocztową. Należy używać ostrożnie w środowisku produkcyjnym.
Moduł user może również zarządzać hasłami (password z zahashowanym hasłem), datą wygaśnięcia konta (expires) oraz SSH keys.
Moduł file jest podstawowym narzędziem do zarządzania atrybutami plików i katalogów w Ansible. Nie służy do kopiowania treści (do tego jest copy i template), ale do zarządzania własnością, uprawnieniami i typem pliku.
Najczęstszym zastosowaniem jest tworzenie katalogów przed skopiowaniem do nich plików. state: directory tworzy katalog, jeśli nie istnieje.
state: touch tworzy pusty plik lub aktualizuje znacznik czasu (atime/mtime) istniejącego pliku.
state: link tworzy dowiązanie symboliczne. Parametr src wskazuje na cel dowiązania, a path na ścieżkę dowiązania.
Role to zaawansowany mechanizm organizacji kodu w Ansible. Pozwalają na grupowanie powiązanych zadań, handlerów, zmiennych, plików i szablonów w jedną, reużywalną jednostkę.
Struktura katalogów roli jest ściśle określona: tasks/main.yml (główne zadania), handlers/main.yml (handlery), vars/main.yml (zmienne wysokiego priorytetu), defaults/main.yml (zmienne niskiego priorytetu), meta/main.yml (zależności i metadane).
Role są szczególnie przydatne w większych projektach, gdzie wiele playbooków korzysta z tych samych konfiguracji.
Ansible Galaxy (galaxy.ansible.com) to repozytorium publicznych ról, które można pobrać i użyć we własnych projektach.
Dobre praktyki są kluczowe dla utrzymania jakości kodu Ansible w dłuższej perspektywie. Przechowywanie projektu w Git to podstawa.
Walidacja składni (--syntax-check) powinna być wykonywana przed każdym uruchomieniem playbooka. W środowisku CI/CD jest to automatycznie sprawdzane.
Tryb --check (dry-run) symuluje wykonanie playbooka bez wprowadzania rzeczywistych zmian. Jest to niezbędne narzędzie do weryfikacji.
Ansible Vault pozwala na szyfrowanie wrażliwych danych: haseł, kluczy API, certyfikatów. Zaszyfrowane pliki można bezpiecznie przechowywać w Git.
Do laboratorium potrzebujemy dwóch maszyn wirtualnych z systemem Ubuntu. Można użyć VirtualBox, VMware, maszyn w chmurze (AWS EC2, Azure VM) lub kontenerów LXC/Docker.
Kontroler to maszyna, z której będziemy uruchamiać Ansible. Nie wymaga dużej mocy obliczeniowej (1 CPU, 1 GB RAM wystarczy).
Po wygenerowaniu klucza SSH (ed25519 jest bezpieczniejszy i szybszy od RSA), kopiujemy klucz publiczny na węzeł zarządzany.
Przed rozpoczęciem laboratorium warto sprawdzić, czy połączenie SSH działa bez hasła.
Pierwszym krokiem laboratorium jest utworzenie pliku inventory i przetestowanie połączenia z węzłem zarządzanym. Moduł ping to najprostszy moduł Ansible.
W odpowiedzi widzimy: adres IP węzła, status SUCCESS (lub FAILURE/UNREACHABLE), informację o interpreterze Pythona oraz odpowiedź pong.
Jeśli otrzymamy UNREACHABLE, należy sprawdzić: czy adres IP jest poprawny, czy klucz SSH jest dodany do authorized_keys, czy Python jest zainstalowany na węźle oraz czy firewall nie blokuje portu 22.
Status changed: false oznacza, że żadna zmiana nie została wykonana - moduł ping jest tylko testem połączenia.
Nasz pierwszy playbook jest prosty - instaluje Nginx na węźle z grupy web. Zawiera definicję play (hosts: web), eskalację uprawnień (become: yes) oraz zmienne (vars).
Po uruchomieniu ansible-playbook, Ansible połączy się z węzłem, zbierze fakty, sprawdzi czy Nginx jest zainstalowany, a jeśli nie - zainstaluje go.
Wynik powinien pokazać: PLAY (instalacja Nginx), TASK (Gathering Facts), TASK (Instalacja Nginx) oraz PLAY RECAP z podsumowaniem.
W play recap zobaczymy: ok=2, changed=1 (pierwsze uruchomienie) lub changed=0 (drugie uruchomienie - dowód idempotentności).
Rozszerzamy playbook o zadanie kopiowania pliku index.html z kontrolera na węzeł. Plik index.html powinien być umieszczony w katalogu files/ w projekcie.
Moduł copy kopiuje plik i ustawia własność na www-data (użytkownik Nginx) oraz uprawnienia 0644. Jeśli plik docelowy ma już te same atrybuty i sumę kontrolną, zadanie zgłosi ok.
Dzięki notify, handler restart nginx zostanie wywołany tylko wtedy, gdy plik index.html faktycznie się zmienił.
Zadanie uruchomienia Nginx (service: state: started, enabled: yes) jest idempotentne - jeśli Nginx już działa i jest włączony, zadanie zgłosi ok.
Tryb dry-run (--check) to jedna z najważniejszych funkcji Ansible. Symuluje on wykonanie playbooka bez wprowadzania rzeczywistych zmian.
Z --diff Ansible pokazuje dokładne różnice w plikach (jak git diff). Jest to szczególnie przydatne przy sprawdzaniu, czy szablony generują poprawne pliki konfiguracyjne.
Po pierwszym uruchomieniu playbooka, changed=3 oznacza, że trzy zadania wprowadziły zmiany.
Po drugim uruchomieniu, changed=0 - to jest właśnie dowód idempotentności. Playbook został wykonany, ale ponieważ stan systemu był już zgodny z pożądanym, żadne zadanie nie musiało wprowadzać zmian.
Weryfikacja jest kluczowym etapem każdego zadania automatyzacji. Nie wystarczy uruchomić playbooka - trzeba sprawdzić, czy faktycznie działa zgodnie z oczekiwaniami.
Pierwsza komenda ad-hoc sprawdza status usługi Nginx przez systemctl. Powinna pokazać active (running).
curl z kontrolera (maszyny, na której uruchamiamy Ansible) testuje, czy serwer odpowiada na żądania HTTP. Wynik 200 OK potwierdza działanie.
curl z węzła zarządzanego, wykonany przez moduł command, sprawdza lokalnie, czy Nginx odpowiada na localhost.
Błędy składni YAML są najczęstszym problemem początkujących użytkowników Ansible. YAML jest bardzo wrażliwy na wcięcia i formatowanie.
Użycie tabulatora zamiast spacji jest najczęstszym błędem. Większość edytorów kodu można skonfigurować do automatycznego zamieniania tabulatorów na spacje.
Komenda ansible-playbook --syntax-check jest pierwszą linią obrony przed błędami składni. Powinna być wykonywana przed każdym uruchomieniem playbooka.
Dodatkowo można użyć python3 z modułem yaml do walidacji pliku. Prawidłowy plik YAML powinien zostać wczytany bez błędów.
Problemy z połączeniem SSH są drugim najczęstszym problemem w Ansible. Objawiają się komunikatem UNREACHABLE! i zatrzymaniem wykonania playbooka.
Pierwszym krokiem diagnostyki jest ręczne połączenie SSH z kontrolera do węzła: ssh -vvv user@host. Opcja -vvv pokazuje szczegółowe informacje o procesie uwierzytelniania.
Jeśli ręczne SSH działa, ale Ansible nie, problemem może być: inny użytkownik w Ansible, inny port SSH, lub brak klucza w ssh-agencie.
W środowisku produkcyjnym zaleca się używanie SSH keys z ssh-agent i włączenie host_key_checking z dodaniem kluczy hostów przez ssh-keyscan.
Błędy uprawnień są szczególnie częste przy pierwszej konfiguracji Ansible. Użytkownik SSH musi mieć uprawnienia sudo do wykonywania zadań wymagających uprawnień root.
Zaleca się skonfigurowanie sudo z opcją NOPASSWD dla użytkownika Ansible, aby uniknąć blokowania się na pytanie o hasło podczas automatyzacji.
W systemach z SELinux (RHEL/CentOS/Fedora) lub AppArmor (Ubuntu/Debian), dodatkowe polityki bezpieczeństwa mogą blokować dostęp do plików nawet przy poprawnych uprawnieniach.
W przypadku braku Pythona na węźle, Ansible nie będzie mógł wykonać większości modułów. Należy zainstalować Python lub użyć modułu raw dla podstawowych komend.
Debugowanie playbooków jest niezbędną umiejętnością każdego administratora Ansible. Najprostszą metodą jest zwiększenie poziomu verbose (-v, -vv, -vvv).
Poziom -v pokazuje podstawowe informacje o wykonaniu zadań. -vv dodaje informacje o połączeniach SSH. -vvv pokazuje pełne dane debugowania, w tym komendy SSH wykonywane na węźle.
Moduł debug to wbudowane narzędzie do wyświetlania wartości zmiennych podczas wykonywania playbooka. Jest nieocenione przy diagnozowaniu problemów z podstawianiem zmiennych.
Tryb --check --diff pokazuje, jakie zmiany zostaną wprowadzone, bez faktycznego ich wykonywania. --diff dodatkowo pokazuje różnice w plikach.
Typowe problemy w Ansible mają przewidywalne objawy i rozwiązania. Warto zapamiętać najczęstsze scenariusze, aby szybko diagnozować problemy.
Błąd składni YAML jest najłatwiejszy do zdiagnozowania - ansible-playbook --syntax-check wskaże linię z błędem.
Problemy z SSH są najtrudniejsze do zdiagnozowania, ponieważ komunikaty błędów są często mylące. Zawsze warto sprawdzić ręczne połączenie SSH z verbose.
Problemy z uprawnieniami są szczególnie częste przy pierwszej konfiguracji. Należy pamiętać, że Ansible potrzebuje sudo do zadań wymagających uprawnień root.
Cheat sheet zawiera najważniejsze polecenia Ansible, które każdy administrator powinien znać. Warto wydrukować go i mieć pod ręką podczas pracy.
ansible all -m ping to pierwsze polecenie, które należy uruchomić po skonfigurowaniu nowego inventory. Potwierdza ono, że Ansible może komunikować się ze wszystkimi hostami.
ansible-playbook z --check i --diff to bezpieczny sposób na sprawdzenie, jakie zmiany wprowadzi playbook przed faktycznym uruchomieniem.
ansible-doc -l wyświetla listę wszystkich dostępnych modułów z krótkim opisem. Dla szczegółowej dokumentacji konkretnego modułu: ansible-doc nazwa_modulu.