Automatizace infrastruktury
1. část

Každý určitě znáte ten pocit zmaru, kdy se připojíte přes SSH na server a přemýšlíte, co jste na něm instalovali, v jaké verzi, s jakou konfigurací. Ano člověk by si mohl vést někde inventář s poznámkami a hesly – samozřejmě ideálně formou kusu papíru přilepeném na monitoru (i tím jsme si kdysi prošli :-)). Ale co když o server přijdete? Budete jej znovu ručně instalovat a konfigurovat? Třeba i celý cluster? Samozřejmě, že nemusíte. Je ale třeba se trochu nad celým procesem automatizace zamyslet a zvolit vhodné nástroje.

Automatizace strojů přichází

Byť tento název může znít spíše jako titulek nějakého sci-fi filmu s Arnoldem v hlavní roli, nebojte, jedná se pouze o postup, jak automatizovat vytváření a konfiguraci virtuálních strojů, sítí, disků atd. My se obecně snažíme jít vždy tou pro všechny nejjednodušší cestou, a proto používáme Terraform od HashiCorp.

Terraform

Tento nástroj je silný v mnoha ohledech – je psaný v GO, tudíž nic dalšího k jeho běhu není třeba. Využívá deklarativní přístup, což v praxi vede i k tomu, že máte zároveň vyřešenou inventarizaci a snadno tak víte, co Vám kde běží a co s čím souvisí. V neposlední řadě je však velice jednoduchý na pochopení a používání.

Nejspíše by se našla spousta dalších pozitiv, ale uveďme si rovnou příklad z praxe:
máme ve firmě Openstack, se 2 regiony, přičemž potřebujeme rozdistribuovat 4 stroje, po 2 na jeden region.

Konfigurace by mohla vypadat takto:

variable-m-"regions"-m-{ -m--m-default-m-=-m-{ -m--m--m--m-"0"-m-=-m-"RegionOne" -m--m--m--m-"1"-m-=-m-"RegionTwo" -m--m--m--m-"2"-m-=-m-"RegionOne" -m--m--m--m-"3"-m-=-m-"RegionTwo" -m--m-} } provider-m-"openstack"-m-{ -m--m-tenant_name-m-=-m-"tenant" -m--m-user_name-m--m--m-=-m-"username" -m--m-password-m--m--m--m-=-m-"password" -m--m-auth_url-m--m--m--m-=-m-"https://server1:5000/v2.0" -m--m-insecure-m--m--m--m-=-m-true } resource-m-"openstack_compute_instance_v2"-m-"servers"-m-{ -m--m-region-m--m--m--m--m--m-=-m-"${lookup(var.regions,-m-count.index)}" -m--m-name-m--m--m--m--m--m--m--m-=-m-"server-${count.index-m-+-m-1}" -m--m-image_name-m--m-=-m-"centos-7" -m--m-flavor_name-m-=-m-"m1.nano" -m--m-key_pair-m--m--m--m-=-m-"bsedlak" -m--m-count-m--m--m--m--m--m--m-=-m-4 }

Všimněte si, že zde používají proměnné, což nám umožňuje určitou úroveň dynamičnosti a v příkladu ji tak využijeme pro samotnou distribuci mezi regiony.

Následně pak můžete spustit tyto příkazy:

  • terraform init – stáhne moduly pro OpenStack (můžete použít třeba Azure, AWS atd.)
  • terraform plan – porovná vaši konfiguraci s aktuálním stavem a pokud je rozdílný, navrhne Vám plán, jak dosáhnout cílového stavu
  • terraform apply – pak aplikuje požadované změny.

 

Dobrej hardware! A co software?

Poté co máme takto vytvořené stroje, potřebujeme provést základní SW instalaci a konfiguraci. Na tento úkol by se dal použít Terraform, ale my se nakonec přiklonili k jinému nástroji, který je přímo na tuto problematiku zaměřen. Dříve jsme například používali Chef, který ovšem potřebuje ke svému běhu agenta na cílovém stroji a konfigurace a deploy cookbooků v Ruby je pro každého nové člena týmu dosti strastiplné.

Ansible

Opět jsme tedy zvolili cestu deklarativního přístupu a vybrali si Ansible od Red Hatu. Jeho konfigurace v YAMLu je velice jednoduchá, funguje přes SSH a má také celkem velkou komunitu v podobě Ansible Galaxy (veřejný repozitář s komunitními moduly).

Pro začátek bude nejlepší si vytvořit základní adresářovou strukturu:

inventories/ -m--m--m-prod/ -m--m--m--m--m--m-hosts-m--m--m--m--m--m--m--m--m--m--m--m--m--m--m-#-m-inventory-m-file-m-for-m-production-m-servers -m--m--m--m--m--m-group_vars/ -m--m--m--m--m--m--m--m--m-group1.yml-m--m--m--m--m--m--m-#-m-here-m-we-m-assign-m-variables-m-to-m-particular-m-groups -m--m--m--m--m--m--m--m--m-group2.yml -m--m--m--m--m--m-host_vars/ -m--m--m--m--m--m--m--m--m-hostname1.yml-m--m--m--m-#-m-here-m-we-m-assign-m-variables-m-to-m-particular-m-systems -m--m--m--m--m--m--m--m--m-hostname2.yml -m--m--m-test/ -m--m--m--m--m--m-hosts-m--m--m--m--m--m--m--m--m--m--m--m--m--m--m-#-m-inventory-m-file-m-for-m-test-m-environment -m--m--m--m--m--m-group_vars/ -m--m--m--m--m--m--m--m--m-group1.yml-m--m--m--m--m--m--m-#-m-here-m-we-m-assign-m-variables-m-to-m-particular-m-groups -m--m--m--m--m--m--m--m--m-group2.yml -m--m--m--m--m--m-host_vars/ -m--m--m--m--m--m--m--m--m-stagehost1.yml-m--m--m-#-m-here-m-we-m-assign-m-variables-m-to-m-particular-m-systems -m--m--m--m--m--m--m--m--m-stagehost2.yml main.yml prod.yml test.yml roles/ -m--m--m--m-common/ -m--m--m--m--m--m--m--m-tasks/ -m--m--m--m--m--m--m--m--m--m--m--m-main.yml

a vysvětlit si základní pojmy:

  • inventory – seznam serverů, který lze členit do různých skupin, které lze následně i zanořovat
  • role – obsahuje seznam úkolů (task), které se mají vykonat
  • task – úkol, který se má vykonat, lze používat různé moduly (např. authorized_key, mongo_user atd.)
  • playbook – seznam kroků, které se mají provést a u každého z nich se definují role a servery / skupiny z inventory, na které se mají aplikovat
  • group_vars – proměnné pro danou skupiny, název skupiny vždy určuje název souboru, obdobně pak fungují host_vars, přičemž u obou all.yml znamená aplikovat pro všechny.

Jak to celé funguje si můžeme ukázat na malém příkladu z praxe:

v předchozí části jsme vytvořili 4 stroje ve 2 regionech a teď bychom na ně chtěli povolit někomu přístup přes SSH.

Nadefinujeme si seznam serverů a rozdělme si je na test a prod.

inventories/prod/hosts

[region-1] server-1 [region-2] server-2

inventories/test/hosts

[region-1] server-3 [region-2] server-4

Následně si vytvoříme roli s názvem common, protože bude společná pro všechny. Poté do ní přidáme task, který samotnou operaci provede.

roles/common/tasks/main.yml

--- --m-name:-m-Copy-m-Public-m-Keys-m-to-m-Other-m-Hosts -m--m-authorized_key: -m--m--m--m-user:-m-'{{-m-item.user-m-}}' -m--m--m--m-state:-m-'{{-m-item.state-m-}}' -m--m--m--m-key:-m-'{{-m-item.key-m-}}' -m--m-loop:-m-'{{-m-ssh_authorized_keys-m-}}'

Použili jsme jsme proměnnou ssh_authorized_keys, kterou musíme někde nadefinovat. Pro tento příklad nám poslouží adresář group_vars (lze však využít host_vars pro konkrétní servery), kde nadefinujeme pro konkrétní prostředí jednotlivé klíče (group_vars lze vytvořit i v rootu celého projektu, potom bychom měli proměnné společné pro všechny prostředí).

inventories/prod/group_vars/all.yml

ssh_authorized_keys: -m--m---m-user:-m-user1 -m--m--m--m-state:-m-present -m--m--m--m-key:-m-ssh-rsa-m-...-m-user1 -m--m---m-user:-m-user2 -m--m--m--m-state:-m-absent -m--m--m--m-key:-m-ssh-rsa-m-...-m-user2

Všimněte si, že u uživatele číslo 2 je state: absent, což znamená, že mu chceme přístup odebrat.

Nyní můžeme roli přidat do našeho hlavního playbooku main.yml.

main.yml

--- --m-name:-m-common-m-setup -m--m-hosts:-m-all -m--m-roles: -m--m--m--m---m-common

V adresářové struktuře výše jste si určitě všimli i playbooků test.yml a prod.yml. Jelikož oba importují hlavní playbook main.yml, budeme tak schopni zajistit konfiguraci obou prostředí nezávisle na sobě s jedním společným nastavením.

prod.yml

--- --m-import_playbook:-m-main.yml

Následně spustíme ansible-playbook -i inventories/prod/hosts prod.yml a po dokončení budou klíče na produkčních serverech a uživatelé se mohou ihned přihlásit.

Ansible Galaxy

Tímto způsobem pak můžete například sestavit celý MongoDB cluster a ani nemusíte role znovu vytvářet, jelikož můžete využít některou z rolí v oficiálním repozitáři. Do projektu Vám stačí přidat pouze requirements.yml

requirements.txt

--m-src:-m-undergreen.mongodb -m--m-version:-m-v2.4.4 -m--m-name:-m-mongodb

kde uvedete závislosti a spustíte ansible-galaxy install -r requirements.yml.
Roli pak použijete v playbooku uvedením celého názvu v src výše nebo si ji jednoduše přejmenujte pomocí name. Jak tuto roli pak používat lze ve většině případů vyčíst v readme daného projektu.

Ansible Tower / AWX

Ač je celý systém velmi efektivní a rychlý, stále vzniká potřeba mít vše centrálně dostupné, ideálně formou grafické nadstavby, kdy celý proces provedete stiskem jednoho tlačítka. Přece jen obvykle člověk pracuje v týmu, kde vzniká delegovat určité automatizované úlohy i na kolegy bez hlubších technických znalostí. Například pokud budete zrovna na dovolené, někdo musí udělat release nové verze aplikace.

Za zmínku tedy stojí nástroje jako Ansible Tower (komerční) nebo AWX, jako jeho otevřená varianta. Zde jednoduše nastavíte různé úrovně přístupu, popř. si připojíte přímo LDAP a jiné podporované autentizační metody. A když si nastavíte třeba notifikace do Slacku, hned budete vědět, že se máte podívat do audit logu, kdo všechno za Vaší nepřítomnosti co nasadil nebo rozbil :-).

Závěr

Takto jsme si zhruba nastínili základy, jak pracovat s infrastrukturou a ušetřit si nějaký ten čas. Určitě však téma vyčerpané není. Mohli bychom se bavit ještě o tom, jak řešit verzování, pracovat s automatizací v týmu, nasazovat infrastrukturu pro mikroservisní architekturu atd. Ale to už jsou témata, která stojí za samostatný článek a určitě se o nich rozepíšeme co nejdříve nebo se za námi stavte na jedné z našich přednášek a můžeme probrat nějaký Váš konkrétní problém z praxe.