Wstęp do Ansible

Ansible – zarządzanie wieloma hostami jednocześnie. Do działania wykorzystuje protokół SSH.

Ansible Management Node – miejsce, z którego uruchamiasz automatyzacje Ansible
Inventory – lista hostów zarządzanych przez Ansible (format txt lub bardziej zaawansowany YAML)
Playbook – scenariusz zawierający taski do wykonania na zdalnych serwerach
Task – pojedyncze zadanie wykonywane na serwerze
Jumphost – specjalna maszyna przez którą łączymy się do zdalnego serwera niedostępnego bezpośrednio ze świata

# Instalacja [RHEL]
Najpierw należy zainstalować repozytorium EPEL
subscription-manager repos –enable codeready-builder-for-rhel-9-$(arch)-rpms
dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm

A następnie jedyny pakiet do obsługi to: ansible

# Inventory
Domyślnie zlokalizowane w pliku /etc/ansible/hosts
Dostępne zmienne:
ansible_host – adres IP/DNS hosta
ansible_port – adres portu SSH
ansible_user – użytkownik, na jakiego ansible będzie się łączył, domyślnie root
ansible_become – informacja dla ansible, że użytkownik jest użytkownikiem sudo a nie rootem, więc każde polecenie musi zaczynać z sudo
ansible_ssh_extra_args – parametry doklejane do komendy ssh (np. w przypadku jumphosta)

Przykładowe inwentory:
[grupa_hostow]
web01 ansible_host=192.168.1.200 ansible_user=ubuntu ansible_become=true
web02 ansible_host=192.168.1.201 ansible_user=ubuntu ansible_become=true
[inna_grupa]
web03 ansible_host=192.168.1.202 ansible_port=10000

# Ustawienie, aby ansible domyślnie akceptował nowe klucze hostów
Sprawdźmy w pliku /etc/ansible/ansible.cfg jakie polecenie należy wykonać w celu wygenerowania konfigu (o ile plik jest pusty). Domyślnie jest to:
ansible-config init –disabled -t all > ansible.cfg
Należy zwrócić uwagę, aby być wewnątrz katalogu /etc/ansible.
Po wygenerowaniu konfiga wchodzimy ponownie do pliku, przechodzimy do sekcji ssh_connections i edytujemy zmienną ssh_common_args:
ssh_common_args= -o StrictHostKeyChecking=accept-new

# Logowanie do maszyn poprzez klucze SSH
Należy wygenerować klucz na nodzie:
ssh-keygen -t ed25519 -C ansible

A następnie skopiować go na hosty:
ssh-copy-id user@IP_hosta

# Wykonanie pojedynczego taska: moduły ad-hoc
Składnia wzorcowa:
ansible GDZIE -m JAKI_MODUŁ -a „ARGUMENTY DLA TEGO MODUŁU” (-f 1)
GDZIE:
all – wszystkie hosty w inventory
web01 – nazwa hosta zdefiniowana w inventory

-f – domyślnie ansible uruchamia się na 5 hostach jednocześnie, aby zmienić tę wartość należy wykorzystać ten przełącznik

Jeżeli nie podamy nazwy modułu wykorzysta domyślne moduł „command”

Moduły command, a shell:
command – wykona tylko prostą, jedną komendę
shell – ansible, uruchamia powłokę bash i dopiero wewnątrz niej daną komendę; wykorzystywany w przypadku złożonych komend (z wykorzystaniem pipe, && itp)

Sprawdźmy komunikację z powyżej utworzonym inventory wykorzystując ansiblowy moduł ping:
ansible all -m ping
ansible web01 -m ping

Aby wyłączyć wszystkie maszyny należy wykorzystać moduł shell i jako argument podać komendę wyłączającą:
ansible all -m shell -a „shutdown -h now”

Skopiowanie lokalnego pliku na hosta docelowego:
ansible all -m copy -a 'src=/root/plik dest=/home/ubuntu/plikdocelowy’

Sprawdzenie:
ansible all -a „ls -lA /home/ubuntu”

Instalacja pakietów:
ansible all -m package -a 'name=nazwa_pakietu state=present’
present – zainstaluj
absent – usuń

# Przykładowy plik napisany w języku YAML

– element1:
  opis: dwa
  opis2:
    – jeden
    – dwa
  opis3:
    a: b
    c: d

Każdy plik YAML powinien się zaczynać i kończyć
Wcięcia mogą wynosić dowolną ilość spacji, ale należy zachować uszeregowanie.

Lista pracowników:

# pracownicy
– jkowalski:
  imie: Jan
  nazwisko: Kowalski
  skills:
    – ansible
    – apache
    – nginx
  opis: |
    to jest napis
    i tak zostanie przekazany
  opis2: >
    to jest napis
    który i tak będzie przekazany
    w jednej linii

Do sprawdzenia poprawności plików YAML może posłużyć np. narzędzie yamllint (yamllint nazwa_pliku.yaml). Jeżeli nie zwraca wyniku, tzn poprawną składnię i brak błędów.

# Ansible facts, ansible magic variables
Facts – informacje, które ansible zbiera o naszej maszynie. Podczas uruchamiania playbooka wykorzystuje moduł setup. Aby sprawdzić co pobiera możemy użyć komendy:
ansible maszyna -m setup | less
Wszystkie te informacje możemy wykorzystać podczas budowania playbooka.

Ansible magic variables – informacje na temat samego Ansible
ansible maszyna -m debug -a 'var=mienna’
Przykłady zmiennych:
groups – grupy do jakich należy
inventory_hostname – nazwę jaką ma przyjętą w inventory
hostvars – informacje o innych maszynach (dzięki temu w playbooku możemy odwoływać się do innych maszyn)
„var=hostvars[’nazwa_maszyny’]” – informacje o konkretnej maszynie

Aby wykorzystać zmienne w playbooku wpisujemy je w {{ nazwa_zmiennej }}.

# Tworzenie playbooków
1. Dodanie maszyny lokalnej do inventories:
local ansible_connection=local (ansible nie będzie się łączył przez SSH tylko będzie wykonywał na niej polecenia lokalnie)
2. Utworzenie katalogu dla playbooka (w dowolnym miejscu) i wewnątrz niego podkatalog na klucze ssh (które w pierwszym tasku będziemy generować).
3. Utworzenie pliku startowego dla playbooka (przyjęte, że site.yaml)
4. Utworzenie zadania generującego klucze SSH
– name: generate SSH key
  hosts: local
  tasks:
    – name: generate SSH key for jkowalski
      openssh_keypair: (moduł do generowania kluczy)
        path: „/root/playbook/ssh_keys/jkowalski” (ścieżka wewnątrz utworzonego przed chwilą katalogu)
        type: ed25519
        state: present
        comment: „jkowalski key generated by ansible”

5. Uruchomienie playbooka:
ansible-playbook site.yaml
6. Rozszerzenie playbooka o zmienne. W tym celu utwórzmy katalogi host_vars (ze zmiennymi dla pojedynczych hostów) i group_vars (ze zmiennymi dla grup hostów)
7. Chcemy utworzyć użytkowników na wszystkich hostach w związku z tym w katalogu group_vars utwórzmy plik all o następującej zawartości:
ssh_user: jkowalski
8. Zmodyfikujmy playbook, aby korzystał ze zmiennych:
– name: generate SSH key
  hosts: local
  tasks:
    – name: generate SSH key for {{ ssh_user }}
      openssh_keypair: (moduł do generowania kluczy)
        path: „/root/playbook/ssh_keys/{{ ssh_user }}”
        type: ed25519
        state: present
        comment: „{{ ssh_user }} key generated by ansible”
9. Sprawmy, aby utworzyły jednocześnie kilku użytkowników. W tym celu wykorzystamy pętle. Przeróbmy najpierw plik ze zmiennymi all, aby zawierał listę użytkowników:
ssh_user:
  – jkowalski
  – jnowak
  – anowak
A następnie w playbooku na końcu dopiszmy (na równi z nazwą taska):
loop: ” {{ ssh_user }}”
To utworzyło nam iteracyjną zmienną wewnętrzną, do której się odwołujemy pod nazwą item. Umożliwi to przejście przez wszystkie elementy z tablicy ssh_users. W związku z tym wszystkie powyższe wystąpienia modyfikujemy i finalnie playbook wygląda następująco:
– name: generate SSH key
  hosts: local
  tasks:
    – name: „generate SSH key for ssh_users”
    openssh_keypair: (moduł do generowania kluczy)
      path: „/root/playbook/ssh_keys/{{ item }}”
      type: ed25519
      state: present
      comment: „{{ item }} key generated by ansible”
  loop: „{{ ssh_user }}”

10. Pogrupujmy hosty w inventory. Grupy zapisujemy w formacie: [nazwa_grupy]
11. Dodanie użytkowników na zdalnych maszynach. Dodajmy w tym celu nowy task do playbooka:
– name: Add ssh users to system
  hosts: web,db
  tasks:
    – name: Add users
      user:
        name: „{{ item }}”
        shell: /bin/bash
      loop: „{{ ssh_user }}”

12. Wyślijmy teraz klucze SSH dla utworzonych użytkowników na maszyny. W tym celu wewnątrz zadania „Add ssh users to system” utwórzmy kolejny task:
– name: Add authorized_keys for users
  authorized_key:
    user: „{{ item }}”
    state: present
    key: „{{ lookup(’file’, '/root/playbook/ssh_keys/’ + item + ’.pub’) }}”
  loop: „{{ ssh_user }}”
13. Zainstalujmy paczki na maszynach. Najpierw zmieńmy nazwę grupy tasków na „Tasks for web and db”. Następnie dodajmy nowy task dla tej grupy:
– name: Install bind-utils on CentOS
  package:
    name: bind-utils
    state: present
  when: ansible_facts[’os_family’] == „RedHat”
– name: Update apt cache
  apt:
    update_cache: yes
  when: ansible_facts[’os_family’] == „Debian”
– name: Install bind-utils on Ubuntu
  package:
    name: bind9-utils
    state: present
  when: ansible_facts[’os_family’] == „Debian”
14. Zajmijmy się teraz plikami. Jeżeli nie określimy dokładnej ścieżki ansible domyślnie szuka plików katalogu files. Utwórz więc taki katalog, a wewnątrz niego dowolny plik z jakimś tekstem. Następnie do playbooka dodajmy task, który będzie kopiował ten plik na maszyny.
– name: „Copy file”
  copy:
    src: plik
    dest: /tmp
    owner: root
    group: root
    mode: u=rw,g=r,o=r

15. Plik dynamicznie modyfikowany na podstawie zdefiniowanych zmiennych. Utwórzmy katalog templates a wewnątrz niego plik z rozszerzeniem .j2
motd.j2:
Motd hosta
{{ ansible_host }}: {{ ansible_memtotal_mb }}

16. Dodanie hostsa. Wyszukuje w podanym pliku danego wyrażenia, jeżeli nie znajdzie to wpisuje.
– name: „Dodaj host Marian”
  lineinfile:
    path: /etc/hosts
    search_string: 'marian’
    line: 8.8.8.8 marian
    owner: root
    group: root
    mode: '0644′
  tags: hosts

Składnia taska jest identyczna jak w przypadku copy. Zmieniamy jedynie moduł „copy” na „template” oraz do pliku dopisujemy odpowiednie rozszerzenie.
17. Zajmijmy się teraz konfiguracją firewalla. W katalogu group_vars utwórzmy dwa pliki db oraz web.
db:
open_ports:
  – 3306
  – 22
web:
open_ports:
  – 80
  – 443

W playbooku dodajmy odpowiednie taski. (Wszystkie hosty mam w oparciu o Ubuntu, więc tylko takie tutaj przedstawię)
– name: „Firewall Ubuntu”
  include_tasks: ubuntu_firewall.yaml (zainkluowanie zewnętrznego pliku z taskami)
  when: ansible_facts[’os_family’] == „Debian”
  tags: firewall_ubuntu

A następnie tworzymy zainkludowany plik z następującą zawartością:
– name: „Open ports”
  ufw:
    rule: allow
    port: „{{ item }} „
    proto: tcp
  loop: „{{ open_ports }}”
  tags: firewall
– name: „Default policy to deny”
  ufw:
    state: enabled
    policy: deny
  tags: firewall

# Wykonywanie pojedynczych tasków z playbooka
W tym celu należy wyedytować playbook i dla danego taska dodać dyrektywę tags: z nazwą tagu np.:
tags: kopiowanie
Wywołanie odbywa się poprzez polecenie:
ansible-playbook –tags nazwa_tagu site.yaml

# Instalacja Dockera i uruchomienie kontenera
Role bierzemy z Ansible Galaxy. Wyszukujemy danej roli i szukam w niej informacji jak ją zainstalować. Na przykład:
ansible-galaxy install geerlingguy.docker
Domyślnie instaluje dla katalogu domowego użytkownika. Musimy zainstalować je globalnie dodając przełącznik -p /etc/ansible/roles/
Przechodząc z Galaxy do GitHub repo znajdziemy cały manual dla danej roli.
Zainstalujmy Dockera na serwerach Web, w związku z tym w pliku group_vars/web wklejmy zmienne z manuala.

Następnie dodajmy do playbooka:
– name: Docker for web
  hosts: web
  roles:
    – { role: 'geerlingguy.docker’, tags: 'docker’ }

* taski wykonują się po roli, aby wykonały się wcześniej musimy zamienić tasks na pre_tasks

Zainstalujemy tym sposobem dockera na maszynach z grupy hosts.

# Uruchomienie kontenera
Najpierw musimy doinstalować kilka rzeczy na maszynach.
– name: Install required packages
apt:
pkg:
– python3-pip
– python3-setuptools
state: latest
update_cache: true

A następnie zainstalujmy bibliotekę Docker na maszynach z wykorzystaniem narzędzia pip:
– name: Install docker python module
pip:
name: docker

Teraz możemy dodać zadania do obsługi Dockera. Pierwszy task pobiera obraz, a drugi uruchamia sam kontener.
– name: pull nginx image
community.docker.docker_image:
name: nginx:latest
source: pull
– name: run nginx container
community.docker.docker_container:
name: nginx
image: nginx:latest
state: started
ports:
– „80:80”

# Narzędzie do weryfikacji playbooków – ansible-lint

Wystarczy zainstalować je z repozytorium, a następnie wywołać jako argument podając nazwę pliku.

 


Pobierz hostname, zapisz go w zmiennej (register) a następnie wyświetl go w formie czystej (bez zbędnych danych) – zmienna.stdout. Następnie wrzuć go do pliku.

– tasks:
– name: Pokaz hostname
command: hostname
register: zmienna
– debug: msg=”{{ zmienna.stdout }}”
– lineinfile:
path: plik
line: „{{ zmienna.stdout }}”

W celu świadczenia usług na najwyższym poziomie stosujemy pliki cookies, które będą zamieszczane w Państwa urządzeniu (komputerze, laptopie, smartfonie). W każdym momencie mogą Państwo dokonać zmiany ustawień Państwa przeglądarki internetowej i wyłączyć opcję zapisu plików cookies. View more
Zaakceptuj