DevOps, Poradnik

Ansible w małych i dużych projektach

klawiatura

Korzystaliście kiedyś z Ansible? W tym artykule postaram się przybliżyć zagadnienia związane z jego używaniem, a także szerzej omówić jego wdrożenie oraz korzyści z korzystania z tego narzędzia.

Bez dobrze zaprojektowanej i zarządzanej infrastruktury, a także przemyślanego procesu wdrażania i aktualizacji, większość oprogramowania gotowego do obsługi dużej liczby klientów, przy jednoczesnym zachowaniu stabilności działania usług po prostu by nie powstała. Niezależnie od tego, czy w naszej infrastrukturze jest kilka, czy kilka tysięcy serwerów, na pewno warto skorzystać z narzędzia do zarządzania konfiguracją.

Jakie korzyści możemy odnieść z wykorzystania Ansible?

Ansible jest narzędziem do zarządzania stanem infrastruktury. Pozwala nam na wdrażanie systemów i aplikacji w spójny, powtarzalny sposób przy wykorzystaniu natywnych protokołów SSH oraz WinRM. Jest narzędziem open source, które używa zarówno języków deklaratywnych, jak i proceduralnych do zarządzania konfiguracją. Praca z Ansible pozwala zarówno na wykonywanie komend ad-hoc, jak i na przetwarzanie wcześniej zdefiniowanych w języku YAML plików konfiguracyjnych, tzw. scenariuszy (playbooków). Platformę można wykorzystać także do zarządzania wieloma urządzeniami sieciowymi popularnych producentów, co znacznie ułatwia zmianę konfiguracji w switchach, routerach czy innych urządzeniach sieciowych.

Ansible kontra inne narzędzia do zarządzania konfiguracją

Prawdopodobnie największą zaletą Ansible jest możliwość działania bez konieczności użycia agenta. Oznacza to, że nie potrzebujemy instalować żadnego dodatkowego oprogramowania na zarządzanych serwerach klientów poza Pythonem, który jest obecnie dostępny niemal w każdym systemie operacyjnym. Użycie natywnych protokołów SSH oraz WinRM zapewnia dodatkowe bezpieczeństwo. Wdrożenie nie wymaga więc wielkich zmian w politykach bezpieczeństwa czy otwierania dodatkowych portów.

Dzięki swojej prostocie, wszechstronności i skalowalności — Ansible pozostaje jednym z najbardziej dynamicznie rozwijających się projektów na Github, z zaangażowaną i aktywną społecznością (ponad 55 tysięcy gwiazdek według danych na listopad 2022) wyprzedzając konkurencyjne narzędzia typu Chef, Puppet, SaltStack. Ma wyjątkowe wsparcie od wszystkich popularnych dostawców chmury. Udostępnia tysiące modułów (małych programów tymczasowo umieszczonych na zarządzanych maszynach do czasu zakończenia scenariusza), ułatwiających szybkie i przejrzyste opracowywanie scenariuszy, a później uruchamianie ich na setkach, tysiącach systemów naraz.

Przykładowy fragment scenariusza do zarządzania LAMP (Linux, Apache, MySQL, PHP):

---
- name: LAMP stack configuration
  hosts: all
  become: true
  tasks:
    - name: Ensure latest version of all required packages is installed
      ansible.builtin.apt:
        pkg:
          - apache2
          - mariadb-server
          - php
          - php-mysql
        state: latest

Organizowanie kodu automatyzacji

Wraz z upływem czasu ilość kodu w naszym projekcie będzie się powiększać, więc jeżeli wszystkie zadania zdefiniujemy w jednym scenariuszu, możemy sobie wyobrazić, jak trudno będzie nim zarządzać, czytać kod, analizować potencjalne problemy. Na szczęście Ansible oferuje bardzo wiele możliwości dzielenia kodu na mniejsze fragmenty.

Najważniejszą z nich jest tworzenie ról. Role umożliwiają automatyczne ładowanie powiązanych zmiennych, plików, zadań, procedur obsługi i innych artefaktów Ansible w oparciu o znaną strukturę plików. Po pogrupowaniu treści w role możemy z łatwością ponownie ich używać i udostępniać je innym użytkownikom.

Do zarządzania administrowanymi serwerami służą pliki ewidencji (inventory). Plik ewidencji może być globalny (znajdujący się w katalogu, gdzie zainstalowano Ansible) oraz lokalny, np. na potrzeby jednego projektu. Ich użycie wymaga przekazania do komendy odpowiedniej flagi. Pliki ewidencji mogą być utworzone w formacie INI lub YAML, pozwalają nam na grupowanie zarządzanych serwerów oraz definiowanie zmiennych wykorzystywanych później w scenariuszach lub komendach wykonywanych ad-hoc.

Ansible obsługuje dwa rodzaje ewidencji: statyczną oraz dynamiczną. Statyczna pozostaje niezmieniona aż do chwili, gdy będzie zmodyfikowana przez użytkownika. W przypadku ewidencji dynamicznej Ansible ma możliwość pobierania danych z wszelkich plików wykonywalnych, dane wyjściowe muszą być jednak w formacie JSON. Na szczęście w czasach, gdy dodatkowe hosty szybko pojawiają się i znikają w odpowiedzi na stale rosnące wymagania biznesowe, wielu popularnych dostawców chmury takich jak Amazon AWS, Microsoft Azure, OpenStack dostarcza skrypty do zarządzania ewidencją dynamiczną.

Możemy również tworzyć własne skrypty, które będą pobierały dane do ewidencji, gdzie źródłem danych będzie niestandardowa, korporacyjna bazy danych CMDB lub katalogi LDAP. Aby wyświetlić informację o dostępnych pluginach, możemy użyć komendy ansible-doc -t inventory -l.

Przykładowe użycie pluginu aws_ec2 (Musimy upewnić się, że w naszej sekcji [inventory] w pliku ansible.cfg będzie zmienna enable_plugins = aws_ec2):

plugin: aws_ec2
regions:
 - us-east-1
 - us-west-1
strict: False
keyed_groups:
 - prefix: arch
 key: 'architecture'
 - prefix: tag
 key: tags
 - prefix: instance_type
 key: instance_type
 - key: 'security_groups|json_query("[].group_id")'
 prefix: 'security_groups'
 - key: tags.Application
 separator: ''
 - key: placement.region
 prefix: aws_region
 - key: tags['Role']
 prefix: foo
 parent_group: "project"

Zbieranie faktów Ansible, Jinja2

Przed przystąpieniem do wykonania zadań zawartych w scenariuszu, Ansible przy użyciu modułu setup wykonuje proces zbierania faktów, który może zostać wyłączony przez dodanie zmiennej „gather_facts: false”. Jest on bardzo istotny, ponieważ wiele modułów korzysta z zebranych w ten sposób informacji.

W zaawansowanych scenariuszach często zdarza się, że wykorzystujemy zebrane fakty, szczególnie w instrukcjach warunkowych. By sprawdzić przykładową listę zbieranych faktów, możemy użyć komendy ansible nazwa_hosta -m setup | less. Możemy zebrać między innymi takie dane jak: interfejsy IPv4/IPv6: ansible_all_ipv4_addresses/ansible_all_ipv6_addresses, dystrybucja systemu operacyjnego: ansible_distribution/ansible_distribution_version, wersji kernela: ansible_kernel, wielkości pamięci ram na danym hoście: ansible_memtotal_mb, ilości vcpu: ansible_processor_vcpus, wersji Pythona: ansible_python_version.

Zbieranie faktów oferuje nam ogromne, wręcz nieograniczone możliwości zarządzania konfiguracją. Wyobraźmy sobie, że w infrastrukturze składającej się z tysięcy fizycznych oraz wirtualnych hostów mamy kilka starych fizycznych maszyn posiadających 192vCPU, działających na kernelu 2.6.x pod kontrolą RedHata 6. Naszym zadaniem jest upewnienie się, że na każdej z nich zostały ustawione odpowiednie parametry kernela. Dzięki zbieraniu faktów Ansible oraz dodaniu odpowiednich warunków w kodzie swojego scenariusza — Ansible bez problemu zrealizuje nam to zadanie na maszynach, na których chcemy, by zostało zrealizowane bez konieczności definiowania żadnych nowych zmiennych.

Ansible został stworzony w Pythonie i dziedziczy po nim silnik szablonów Jinja 2. Dzięki zastosowaniu silnika generowania szablonów możemy dynamicznie tworzyć pliki konfiguracyjne na podstawie zadanego szablonu. To potężny framework oferujący szeroki wachlarz możliwości operowania danymi i ich konwertowania. Dzięki odpowiednim filtrom Jinja2 możemy np. konwertować ciąg tekstowy na zawierający tylko małe litery, wyszukiwać dane według wzorca i zastąpić je innymi.

Scenariusze i role. Ansible Galaxy. Ansible-lint

Role zostały zaprojektowane, aby umożliwić efektywne i wielokrotne używanie kodu Ansible. Powinny one być pisane w taki sposób, by nadawały się do ponownego wykorzystania w innych systemach, a także zachowywały zasadę idempotentności — oznacza to, że wielokrotne wykonanie tego samego zadania nie zmieni stanu danego systemu. Np. podczas inicjacji bazy danych będzie ona wypełniana danymi tylko za pierwszym razem (chyba że zechcemy inaczej). Następne wykonanie scenariusza na danym systemie sprawdzi, czy baza jest zainicjowana. Jeśli jest, to przejdzie do następnego zadania bez wykonania zmian w systemie.

Role możemy porównać do bibliotek w konwencjonalnych językach programowania wysokiego poziomu. W katalogu zawierającym scenariusz Ansible będzie domyślnie szukać podkatalogu roles, w którym będą utworzone kolejne podkatalogi dla każdej z ról. Możemy również stworzyć plik requirements.yml nad katalogiem roles, w którym wskażemy instalację roli z innego repozytorium gita.  Gdy wielkość scenariuszy wzrasta, warto rozważyć podzielenie ich na więcej plików i katalogów, co znacznie ułatwi ich zarządzanie oraz czytanie kodu. 

Ansible Galaxy to bezpłatna witryna do wyszukiwania, pobierania, oceniania i przeglądania wszelkiego rodzaju ról Ansible. Zawiera wiele gotowych ról, które możemy wykorzystać w swoich projektach, np. oficjalna rola nginx. Klient ansible-galaxy jest już zawarty w Ansible. 

Ansible-lint jest narzędziem utrzymywanym przez społeczność sprawdzającym scenariusze, role pod kątem praktyk i zachowań, które można potencjalnie poprawić. Jego głównym celem jest promowanie najlepszych praktyk, wzorców i zachowań przy jednoczesnym unikaniu typowych pułapek, które mogą łatwo prowadzić do błędów lub utrudniać utrzymanie kodu.

Zadanie synchroniczne i asynchroniczne

Zadania w Ansible są z reguły wykonywane sekwencyjnie. Oznacza to, że wykonywane zadania musi zostać zakończone, zanim rozpoczniemy wykonywanie następnego. W większości przypadków jest to korzystne z perspektywy spójnego i logicznego wykonywania ciągu zadań, ale szczególnie w bardziej rozbudowanych projektach możemy napotkać sytuacje, w których nie chcemy stosować takiego podejścia, np. gdy wykonywanie pewnego zadania trwa znacznie dłużej niż skonfigurowany czas przekroczenia oczekiwania w połączeniu SSH. Możemy wtedy wykorzystać parametry służące do obsługi zadań asynchronicznych: async oraz poll.

Parametr async instruuje Ansible, by dane zadania było wykonywane asynchronicznie. Przykładowo async: 600 wskaże Ansible by uznał zadanie za zakończone niepowodzeniem, jeśli czas jego wykonywania przekroczy 10 minut (600s). Drugi parametr poll instruuje Ansible, w jakich odstępach czasu ma sprawdzać stan wykonywania zadania asynchronicznego. Może przyjąć również wartość 0, wtedy zadanie asynchroniczne jest wykonywanie niezależnie w tle, a jego wynik nie będzie sprawdzony. Jeżeli jednak chcemy sprawdzić później jego wynik – musimy zdefiniować kolejne zadanie w scenariuszu, które go wyświetli.

Ansible Vault

Bardzo często napotykamy na konieczność przechowywania wrażliwych danych uwierzytelniających lub innych danych wrażliwych w zmiennych, które będą nam potrzebne do wykonania scenariusza. Aby żadna niepowołana osoba nie uzyskała do nich dostępu, z pomocą przychodzi nam Ansible Vault. Jest to dostarczane razem z Ansible narzędzie pozwalające na szyfrowanie zmiennych lub plików, a następnie użycie ich w scenariuszach. Domyślnie wykorzystuje algorytm AES-256. Nie musimy posiadać oddzielnego pliku magazynu danych wrażliwych, po zaszyfrowaniu możemy je dołączać od razu w scenariuszach.

Ansible Tower/AWX

Ansible oferuje nam bardzo potężne możliwości automatyzacji, jednak gdy nasz projekt wraz z upływem czasu będzie się rozrastał, zarządzanie Ansible z poziomu powłoki może stać się naprawdę problematyczne. Wyobraźmy sobie, że musimy nadać kilku deweloperom uprawnienia do uruchamiania tylko kilku konkretnych zadań, wywołać jedno zadanie z poziomu innego, zasilić Ansible Vault dużą ilością poufnych informacji uwierzytelniających do wielu platform lub zaplanować cykliczne wykonywanie kilkunastu scenariuszy.

W takich wypadkach użycie API dedykowanego oprogramowania Ansible Tower lub AWX wydaje się znacznie lepszym rozwiązaniem. Ansible Tower to produkt firmy RedHat typu downstream, AWX to projekt upstream  oraz open source, jest on również dostępny w postaci kontenera Dockera.

Podsumowanie

Ansible to świetne narzędzie do wykonywania wielu zadań związanych z utrzymaniem oraz rozwojem infrastruktury IT, które walczy o bycie absolutnie topowym wyborem narzędzi IaC. Jeśli będziemy starali się używać go zgodnie z dobrymi praktykami, opierając się przy tym o oficjalną dokumentację projektu, możemy zapomnieć o legendarnym „to działało na moim komputerze” i w pełni skupić się na rozwijaniu produktu, oszczędzając sobie przy tym wielu zbędnych godzin na diagnozowanie problemów z infrastrukturą.

Bibliografia:

  1. Daniel Oh, James Freeman, Fabio Alessandro Locati, Ansible 2 w praktyce. Automatyzacja infrastruktury, zarządzanie konfiguracją i wdrażanie aplikacji, Helion S.A. Gliwice 2021
  2. Hochstein Lorin, Moser Rene, Ansible w praktyce. Automatyzacja konfiguracji i proste instalowanie systemów, Helion S.A. Gliwice 2018Oficjalna dokumentacja projektu Ansible. Dostępna w internecie: https://docs.ansible.com/

DevOps Engineer w Ulam Labs, absolwent Politechniki Wrocławskiej. Od najmłodszych lat związany z komputerami i elektroniką. Obecnie w projekcie Cybersecurity, rozwija kompletną platformę do skanowania infrastruktury sieciowej, aplikacji webowych oraz API. Po pracy preferuje sport i aktywny wypoczynek, jego pasją jest zdrowy styl życia.

Podobne artykuły

[wpdevart_facebook_comment curent_url="https://justjoin.it/blog/ansible-w-malych-i-duzych-projektach" order_type="social" width="100%" count_of_comments="8" ]