Teorie
Role jsou v Ansible od verze 1.2. Jejich smyslem je popsat ucelenou jednotku konfigurace tak, aby byla opakovatelně použitelná. Podobají se například třídám z Puppetu (jen je nelze vnořovat). Standardně jsou uloženy v adresáři /etc/ansible/roles/
. Adresářová struktura obsahuje:
files/ handlers/ tasks/ templates/ vars/
Roli přiřadíte do scénáře v main.yml:
--- - hosts: webservers roles: - common - apache - {role: apache_vhost, vhost_domain=simplewebpage.com, vhost_dir=/var/www/simplewebpage.com/www}
Common a apache jsou zavolány bez parametrů. Apache_vhost je parametrizována, vytvoří apache vhost pro simplewebpage.com. Při přehrání Ansible hledá soubory tasks/main.yml, handlers/main.yml, vars/main.yml, pokud je najde, přidá je do hry. Moduly copy a script automaticky hledají soubory ve files/ a modul template v templates/, není potřeba uvádět cesty. Pojďme si to ukázat v praxi.
Praktická ukázka, role pro instalaci utilit
Při své práci mám pod správou několik instalací různých zákazníků. Abych si ulehčil převzetí správy u nového zákazníka, vytvořil jsem si roli common
, s pomocí které nainstaluji na server základní utility, ssh klíč (i když bývá na server nahrán zákazníkem, toto mi umožní jej budoucnu snadno kdykoliv hromadně změnit) a zapnu si zobrazování syntaxe ve vim u root uživatele. V main.yml v tasks adresáři najdeme:
# /etc/ansible/roles/common/tasks/main.yml --- - name: nahravam ssh klic authorized_key: user=root state=present key={{ item }} with_file: - public-keys/david.karban.pub - name: ladim .vimrc lineinfile: dest=/root/.vimrc regexp=^syntax line="syntax on" create=yes - name: instaluji utility na RHEL systemy yum: name={{ item }} state=present with_items: common_packages when: ansible_os_family == "RedHat" - name: instaluji utility na Debian systemy apt: name={{ item }} state=present with_items: common_packages when: ansible_os_family == "Debian" - name: instaluji dalsi utility na Debian systemy apt: name={{ item }} state=present with_items: common_debian_packages when: ansible_os_family == "Debian"
Je vidět, že jde o běžnou hru s jedním rozdílem, vše v main.yml je automaticky bráno jako task
. Ve hře jsou dodány další modifikátory kroků, které jsem zatím nezmínil. With_files
nahraje data ze souboru,v tomto případě můj veřejný SSH klíč. Zde pozor, jak jsem psal, že u role se automaticky berou relativní cesty, tak to skutečně platí jen pro moduly copy
, script
a template
, v tomto případě se bere cesta relativně k playbooku (tedy k /etc/ansible
).
Další modul, lineinfile
, umí změnit v cílovém souboru konkrétní řádek na základě regexp. výrazu, zde jej používám místo celého konfiguračního souboru, abych nepřemazal jiné zákaznické nastavení. V další části instaluji balíky, které obvykle používám, když je potřeba. Jejich seznam jsem uložil do proměnných, které jsou nadefinovány v adresáři vars
, viz níže. Ansible nemá univerzální modul pro package, proto instaluji utility 2×, vždy s filtrem na druh distribuce, viz. sekce when
. Fakt ansible_os_family
obsahuje rodinu distribucí, tj. Debian platí i pro Ubuntu, Red Hat zase i pro CentOS a Scientific Linux. Samotná distribuce je ve faktu ansible_distribution
.
Pokračujme k nadefinovaným proměnným.
# /etc/ansible/roles/common/vars/main.yml --- common_packages: - links - mc - strace common_debian_packages: - htop
Ansible nemá podporu pro lokální proměnné, proměnné nadefinované v rámci rolí jsou na stejné úrovni, jako například proměnné nadefinované ve scénáři v sekci vars. Aby se daly role jednoduše opakovaně použít, doporučuje se mít u proměnných prefix jejich názvu, aby byly unikátní. Proto oba seznamy balíčků začínají common_.
Postupné nasazení aplikace a práce s monitoringem
S dobře popsanými rolemi je instalace nového serveru velmi jednoduchá, prostě přidáme jeho hostname do hosts souboru do vhodné skupiny. Ale co v případě, že provádíme deploy aplikace, jak nám Ansible pomůže zde? Pomocí delegace a postupného zpracování scénáře. Standardně se scénáře aplikují na skupiny serverů paralelně, pomocí klíčového slova serial
si vynutíme jejich postupné zpracování:
--- - hosts: webservers serial: 1 roles: - common - apache - {role: apache_vhost, vhost_domain=simplwebpage.com, vhost_dir=/var/www/simplewebpage.com/www}
Hodnota u atributu serial určuje kolik serverů ze skupiny najednou se má přehrávat. V tomto případě jde jeden po druhém. Abychom odstínili návštěvníky stránek od serverů, na kterých se zrovna provádí deploy, deaktivujeme jej na tu dobu z load balanceru (v tomto případě z haproxy) a z nagiosu, použijeme delegate_to
:
- hosts: webservers serial: 1 # Ukoly ke spusteni pred provedením update aplikace pre_tasks: - name: vypinam nagios alert pro web na serveru nagios: action=disable_alerts host={{ ansible_hostname }} services=webserver delegate_to: "{{ item }}" with_items: groups.monitoring - name: deaktivuji server v haproxy shell: echo "disable server myapplb/{{ ansible_hostname }}" | socat stdio /var/lib/haproxy/stats delegate_to: "{{ item }}" with_items: groups.lbservers roles: . . . # Ukoly po provedeni update aplikace post_tasks: - name: Aktivuji server v haproxy shell: echo "enable server myapplb/{{ ansible_hostname }}" | socat stdio /var/lib/haproxy/stats delegate_to: "{{ item }}" with_items: groups.lbservers - name: zapinam nagios alerty pro web na serveru nagios: action=enable_alerts host={{ ansible_hostname }} services=webserver delegate_to: "{{ item }}" with_items: groups.monitoring
Úkoly vypnutí/zapnutí nagiosu a deaktivace/aktivace serveru v haproxy provádějí na všech monitoring serverech (definováni v hosts souboru jako skupina monitoring) a na všech load balancerech (skupina lbservers). Pre_tasks
a post_tasks
se provádějí na začátku, resp. konci scénáře před hlavní sekci tasks.
Protože není potřeba při každé změně konfigurace na serverech provádět i deploy, je v tomhle případě výhodné mít jej v samostatném scénáří. Ukázka takového skriptu je na GitHubu Ansible. Ukázku nastavení skupiny serverů, vč. haproxy a monitoringu najdete tamtéž.
Závěrem, aneb mé důvody pro Ansible
Vždy, když to lze, snažím se konfiguraci přenést do her a scénářů, abych ji mohl příště aplikovat jen dodáním role k serveru. Ptáte se jak je to odlišné od Puppet a Chef? Je to flexibilnější. Při své práci mám pod správou více druhů instalací u různých zákazníků. V Ansible pro ně mám jak individuální konfiguraci, tak specifické konfigurace jen pro ně. Proto jsem si vytvořil adresář customers
, co zákazník to podadresář. Role, které mají všichni zákazníci stejně (základní utility, nastavení httpd.conf
, nastavení ntp) mám v /etc/ansible/roles/
a do customers je jen symlinkuji.
Když takto přebírám správu serverů u nového zákazníka, tak příprava prostředí je jen dodání adres do hosts souborů. U zákazníka nemám nainstalován žádný dodatečný software, který by mu zabíral systémové prostředky. Ačkoliv bych mohl dosáhnout dost podobného s Puppetem, musel bych mít všechny manifesty v jednom stromu konfigurace a musel bych mít všude nainstalován Puppet agent. Pro mě zbytečně komplikované.