Nomad - easy implementation
Topologie / Design

Pripustne konfigurace clusteru (pocty nodu)
* Cluster se sklada z masteru a agentu.
master rozhoduje o deni v clusteru. Vetsinou se vyskytuji v lichem poctu (1,3,5,…) a jeden z masteru je vzdy leader. Leader si s ostatnimi mastery potvrzuje zmeny v clusteru. Nejhorsi mozny pocet masteru je 2.
agent jde o node, ktery je ovladan mastery, je schopen spoustet deploye dle sablon a o nicem v ramci clusteru nerozhoduje. Jejich mnozstvi na jeden cluster je v podstate neomezene.
Dulezite !!!
Kazdy cluster musi mit minimalne jednoho mastera.
Cluster bez leadera neni mozne slozit, protoze followeri se po spusteni snazi zjistit od leadera co maji delat
Masteri v clusteru musi byt usnaseni schopni (musi byt schopni zajisti quorum)
- Pokud jsem sam, snadno se dohodnu.
- Pokud jsme tri, 2 prehlasuji jednoho, ktery se podvoli.
- Pokud jsme dva a mame kazdy jiny nazor bez moznosti smiru, skupina se rozpadne => split-brain
Pro nas to znamena nasledujici:
Jedno-nodovy cluster
Node je soucasne master i agent
Je to silne neoptimalni, ale neni to o nic mene stabilni nez samostatny obycejny server bez orchestrace => muzeme pouzivat
Jakmile zacneme na serverech resit sdilena perzistentni uloziste, tato varianta nebude provozovatelna!!!
Dvou-nodovy cluster
- Node je soucasne master i agent
- Node je jen agent
Nejhorsi varianta, pokud padne leader, agent dlouho neprezije => Tomuto se chceme vyhnout
Nicmene existuji scenare, kdy je to akceptovatelne s vykricnikem (privatni clustery pro zakazniky, kde agent je i tak zavisly na masterovi)
Tri-nodovy cluster
Vsechny tri nody jsou soucasne master i agent
Nejmensi mozna idealni varianta, kde uz se da hovorit o clusteru. => Takovy deploj preferujeme jako zakladni pro kazdou lokalitu
Ctyr a vice nodovy cluster
Tri nody jsou soucasne master i agent Zbytek je v roli agenta
Idealni varianta
Takove clustery budeme stavet do velikosti 9 - 15 node a nasledne bud odloupneme 3 node jako novy cluster, nebo zacneme stavet dalsi.
Na kazdem serveru bezi nomad, docker a consul, v zasade v systemu neni nic moc dalsiho potreba a lze do budoucna i nase podpurne veci prehodit jako servisy v nomadovi (ma to sve znacne vyhody).
V nomad clusteru vedeme 2 namespacy (kuli zjednoduseni jen dva), prni je default a tam probiha deploj vsech aplikaci. Druhy je system, kde bezi servisni sluzby, jako napriklad traefic.
Cesta pozadavku
- chces jit na adresu moje-apka.ep.cz
- prohlizec udela dns resolv a zjisti, ze moje-appka je CNAME na ha.de1.easy2.cloud
- s tim se prohlizec nespokoji a udela jeste resolv ha.de1
- nakonec se prohlizec dostane napriklad k ip serveru n1.de1
- prohlizec tedy konecne posle pozadavek o web moje-apka na server n1.de1
- tam ceka ingress (v easy je to traefik.io)
- ten vi, ze aplikace je na n3.de1 a preposle pozadavek “vnitrkem clusteru” na n3.de1
- na n3.de1 se pozadavek dostava k aplikaci
- aplikace pozadavek zpracuje a skrz ingress odpovi zpet
Monitoring
Produkcni monitoring zajistuje AdminIT, co je v nem to plati a maji ho plne pod svou kontrolou a my jim v tom pomahame (nebo alespon neprekazime).
Fancy monitoring, abychom meli predstavu co se v clusteru a aplikacich deje je v grafane:
Oba dashboardy jsou POC, ktery by stal za dalsi rozvoj, teoreticky by mel davat zakladni vic nez zakladni informace alespon trochu znale obsluze.
Oba dashboardy krome zakladnich metrik poskytuji i pristup k logum. Nicmene je nutne vedet, ze zdroj dat techto metrik neni perzistentni a vznikne-li tento pozadavek, bude nutne upravit definici deploje v ansible
Zalohovani
Databaze MySQL/Percona/Maria
Na serverech je cron, ktery pousti kazdou hodinu dump databazi.
#Ansible: Run db backups
55 * * * * /bin/bash -lc '/usr/local/bin/nomad_db-backup /data/serveradminscp/databasedump/ serveradminscp'
Script v zasade iteruje nad kontajnery, ktere maji v nazvu maria, mysql, percona, nebo db a ve vsech pusti dump, ktery uklada do adresare /var/lib/mysql v danem kontajneru. To zpusobi, ze je dump nasledne dostupny jako soubor v ceste /home/docker/volumes/db-*/_data/*sql.gz a lze jej zalohovat baculou.
Aby to pro baculu bylo jednoduzsi, dela se tu pak jeste kopirovani techto dumpu do /data/serveradminscp/databasedump/
Zaloha DB tedy aktualne existuje ve forme:
- binarni data databaze (velmi neoptimalni, ale jsou zde vzdy)
- gzipnuty dump /home/docker/volumes/db-*/_data/*sql.gz, uplne v pohode pouzitelne
- dump pro baculu v /data/serveradminscp/databasedump/ (nevim jak je to zachytavano dal baculou)
- bacula by mela mit aktualni dump stazeny
Vedome plytvani mistem
Ja (Marek) osobne zalohovai do baculy prilis neverim, je to pro me black box, nevidim do toho, je to relativne dost komplexni system, ktery za sebou ma uz dlouhou historii a z tech stripku co mam i hromadu uprav ze strany Tlap. Ale verim TLAP a navic me pokusy delat zalozni zalohovani atp, nemely nikdy prilis podporu.
Nicmene, aby se mi lepe spalo, alespon plytvam na serverech mistem duplicitnimi zalohami, ktere v pripade selhani vsecho ostatniho, bud najdu primo na serveru, nebo v bacule po rucnim hledani v docker volume cestach.
Soubory
Postavil jsem nomada a cely server tak, aby vsechna zakaznicka data byla v /home/, ktery je cely dle domluvy s TLAP zalohovan rozdilovkou do baculy.
Docker volume
Vsechny volumy pripojene do kontajneru jsou videt jako soubory v adresari /home/docker/volume/JMENO_VOLUME/_data/.
Warning
Jsou to realtime ostra data, takze kazdy zasah, ktery zde provedu se rozhodne projevi
Runtime data z kontajneru
Pokud hledame data, ktera nebyla ve volumu a to vcetne dat, ktera mohla vzniknout uz pri buildu kontajneru (napriklad gemy, zdrojak aplikace atp). Existuje vysoka sance, ze tyto soubory najdu v ceste /home/docker/overlay2/LAYER/diff/. Hledat v tom neni snadne, ale kde je vule, tam je cesta a v situacich, kdy opravdu potrebuji najit neco velmi specifickeho, lze se divat i sem.
NEZALOHOVANE!!! Nomad sdilena data (/alloc a /local dir)
Nomad nabizi sve uloziste, ktere v nekterych deplojich vyuzivane pro pseudo perzistentni data, nicmene, muze se stat, ze se tam dostane i neco, co muzeme zpetne chtit najit.
Nicmene toto uloziste zalohovane neni, jednak, protoze by nemelo obsahovat nic uzitecneho, ale tato cesta se da vyuzit napriklad pro podsouvani adresaru do kontajneru.
Sitovani
Krome dockeriho sitovani zde neni nic zvlastniho.
Firewall
- cluster je z venku otevren pouze na portech 443, 80, a 113
- z bastionu a VPN jsou servery otevrene uplne
- nody jednoho clusteru mezi sebou maji firewall uplne otevren
- nody maji povoleno pro deploje network mesh (consul connect)
Docker / Nomad
- na serveru jsou pro nomada virtualni interface docker0 a nomad, tam se deje sitovani (neni zadouci na to sahat)
- mame nainstalovane CNI drivery, takze i velmi pokrocile sitovani lze okamzite pouzit
- by default se zadny deploj nevystavuje po siti svetu, vse by melo byt nastavene prez konfiguraci traefika pomoci service tagu
Update dockera
Update dockera vzdy zpusobi restart docker daemona a to ma za nasledek restart docker0 interfacu a casto i iptables.
Nasledkem byva, ze deploje na danem node ztrati sit a temer vzdy se nejaky deploj dostane do divneho stavu, kdy se pokousi nastartovat, ale nedari se mu nahodit interface. Je pak nutne tento deploy znovu pustit.
ESko integrace
Konfigurace v esku
Je nutne mit pro kazdy cluster spravne vytvorene datacentrum. Konkretne je nutne mit v datacentru spravne nastaveno:
Region
Region musi odpovidat nazvu datacentra v nomad clusteru, pokud to nebude sedet, nomad deplojment naplanuje, ale nikdy neprovede s hlaskou, ze v pozadovanem datacentru nema kapacitu.
V ansible se to definuje v souboru env/JMENO_CLUSTERU/hosts jako promene nomad_datacenter a consul_datacenter. Pro lepsi predstavu uvedu priklad:
Nomad cluster address
Jedna se o balancovanou adresu celeho nomad clusteru. Tato adresa “pluje” v celem clusteru a dokud je cluster usnaseni schopny, bude mozne ho prez tuto adresu spravovat i kdyz treba nejake nody vypadnou
Nomad cluster token
Nomad sam generuje tokeny, pokud se token ztrati, je nutne vygenerovat novy, proto je dobre ho neztracet.
Jak se token generuje bude v pasazi konfigurace nomada
Callback in pipeline - DEPRECATED
Toto uz se NEPOUZIVA, nechavam to zde pouze jako dokumentaci predchoziho stavu, na ktery pravdepodobne bude moznae narazit jeste nejaky cas.
Zatim na konci pipeliny volame takovyto curl, ale neni to idealni reseni, radeji bychom meli volat neco na konci spusteni aplikace.
curl -XPUT --data-binary "@running.json" \
-H "X-Redmine-API-Key: ${EP_API_KEY}" \
-H "Content-Type: application/json" \
${CALLBACK_URL}
Idealni by mohlo byt
- Kdyz dobehne init, zareportuje se do eska, ze instalace je done
- Kdyz dopadne dobre health check, da se vedet do eska, ze aplikace je up
- Zajistit nejaky post deploy task, ktery zkontroluje aplikaci a zareportuje, stav - REALIZOVANE RESENI
Konfigurace nomada
Nomad je spravovan samozrejme ansiblem, teoreticky by nemelo byt potreba delat zadne nastavovani rucne, vyjimkou je zatim pouze tvorba pristupovych tokenu do clusteru a obecne sprava ACL.
Instalace
Nomad ma svuj vlastni repozitar, kde probiha vse od instalace po udrzbu a to vcetne updatovani. Jiz neni nutne nic poustet z bastionu, vzdy staci jen pridt novy cluster a pipelinu.
To jak je organizovan repozitar je jako vzdy popsano primo v nem a to jak probiha instalace take.
Kompletni priklad pridani node do clusteru
Chceme pridat node n99.asia1.easy2.cloud do clusteru earth1.
Hlavni zasadou je nepoustet nic ze sveho PC, pokud to neni 100% nutne, na spravu clusteru je pipelina.
1) Jdu do online editoru git.easy.cz/devops/nomad-cluster
2) Pridam novy node do souboru env/earth1/hosts tak, aby to odpovidalo ostatnim zaznamum. Cili napriklad:
[nodes]
.
.
.
#-------- ASIA1
n99.asia1.easy2.cloud ansible_ssh_host=151.9.12.114
3) Do souboru env/earth1/group_vars/all/firewall-cluster.yaml pridam ip noveho serveru
4) Udelam commit a nasledny MR do masteru
5) Pustim rucne pipelinu pro earth1
Kompletni priklad zalozeni noveho clusteru
Chceme vytvorit nove datacentrum fra1
- V ESku zavedu datacentrum se jmenem napriklad “Nomad fra1 - OVH”, to je vlastne dost jedno.
- Do pole region vlozim string fra1
- Do pole nomad cluster address vlozim adresu https://nomad.fra1.easy2.cloud
- Pole token nezman, takze zatim necham volne
- V ansible vytvorim novou strukturu v adresari env/fra1 (nejcasteji zkopiruji nejake jine existujici prostredi)
- Pozmenim v ni konfiguraci dle potreby, zejmena v souboru env/fra1/hosts, kde je nutne nastavit hodnotu promenych nomad_datacenter a consul_datacenter na fra1
- dale nastavim v env/fra1/hosts nomad_url promenou
- za zminku stoji urcite nastavni IP adress clenu clusteru v souboru env/fra1/group_vars/all/firewall-cluster.yaml
- ted mohu pustit instalaci cluster prikazem
ansible-install -i env/**fra1**/hosts nomad-deploy.yml --diff - na konci instalace by na me melo vyskocit summary vypadajici cca takto:
Summary ======= Nodes ----- infra1.cz.easy2.cloud - 185.178.173.81 infra2.cz.easy2.cloud - 185.178.173.82 infra3.cz.easy2.cloud - 185.178.173.83 infra1.de.easy2.cloud - 138.201.62.226 Nomad master access ------------------- export NOMAD_ADDR="https://nomad.infra.easy2.cloud" export NOMAD_TOKEN="591982a1-BOOTSTRAP_TOKEN-ce49079efe86" # because I can't use mTLS with own CA export NOMAD_SKIP_VERIFY="true" `` * nyni vezmu BOOTSTRAP_TOKEN z vypisu a vytvorim sifrovany soubor env/**fra1**/group_vars/all/vault_nomad_token.yaml * ted je potreba pustit jeste jednou cast ansible, konfigurujici nagios ```bash ansible-install -i env/**fra1**/hosts nomad-deploy.yml --diff --tags nagios - po uspesne instalaci clusteru se pripojim na libovolny master node (pokud nevim, ktery to je, pravdepodobne ctu navod, ktery mi neni urcen)
- na tomto node overim, ze vse funguje
- nasledne zacnu vytvaret tokeny pro dalsi kolegy a predevsim token pro esko vytvorim token, ktery nasledne vlozim do ESka (jde o pole token zmineny v zacatku navodu)
-
nastavim DNS pro:
- ha.fra1.easy2.cloud ukazujici na vsechny nody clusteru
- nomad.fra1.easy2.cloud na ha.fra1.easy2.cloud
- prometheus.fra1.easy2.cloud na ha.fra1.easy2.cloud
- loki.fra1.easy2.cloud na ha.fra1.easy2.cloud
- Pripadne lze zavest i hvezdicku .fra1.easy2.cloud na ha.fra1*.easy2.cloud
-
nyni zavedu servery do datacentra a nemelo by mi nic branit v deplojovani aplikaci
- nasleduje nastaveni monitoringu a zalohovani:
- nagios u adminit
- monitoring u TLAP
- zavedeni pormethea a lokiho v grafane
- … (bude se dale rozsirovat v case)
- takto nainstalovany cluster je treba pravidelne aktualizaovat a starat se o nej, coz by nemelo zabrat vic nez par hodin mesicne (odhadem 30minut mesicne na jeden node v clusteru)
Ansible sam je schopen nainstalovat kompletni cluster z nuly, nicmene stale je treba chapat jak to cele funguje!!!
BOOTSTRAP_TOKEN
BOOTSTRAP_TOKEN se NEpouziva!!! Je to unikatni TOKEN, ktery nema opustit server, nema se pouzivat na nic jineho, nez vytvoreni dalsich tokenu. To ze je volne dostupny pod rootem neznamena, ze ho budu lenoch a misto vygenerovani sveho tokenu budu pouzivat BOOTSTRAP token.
Pokud nectu dokumentaci a nezajimam se o to s cim pracuji. V odstavci nize se mohu naucit jak si ACL token vygenerovat.
ACL
Aktualni verze definice policy je k nalezeni v ansible repozitari, ktery ji i nasazuje pomoci playbooku nomad-configure-master.yml.
# Configure predefined policy
nomad acl policy apply -description "read only access for developers" developers acl/policy-developer.hcl
nomad acl policy apply -description "full access for admins" admins acl/policy-admin.hcl
# create token for admin
nomad acl token create -name=marek -policy=admins
Vytvoreni tokenu
Ukazeme si to na prikladu vytvoreni tokenu pro esko, ale uzivatelske tokeny se vytvereji uplne stejne.
ESko pouziva policy admins, ktera by mela byt pripravena na kazdem serveru, takze pro vytvoreni tokenu staci zavolat jen prikaz:
nomad acl token create -name=esko -policy=admins
Vystupem, pokud mame prava je i token, ktery se vklada v esku do pole nomad cluster token
Namespace
Defaultni namespace existuje vzdy, my v easy pouzivame jeste namespace system, kam schovavame systemove joby, jako treba traefika, monitoring atp.
# List existujicich namespace
nomad namespace list
# pridani namespace
nomad namespace apply -description "My private laboratory" lab
Vice info o namespace je v oficialni dokumantaci nomada
Memory oversubscription
Jde o moznost docasne umoznit deploymentu vzit si libovolne mnozstvi zdroju, ktere jsou dostupne v ramci clusteru.
Proc ANO:
- Nase aplikace je strasne zrava, ale ne continualne
- Samotny init si dokaze vzit o dost vic nez nasledne aplikace potrebuje pro provoz
- Chceme efektivneji vyuzivat zdroje
Temna stranka: - po restartu plneho clusteru pravdepodobne nektere aplikace nenastartuji, protoze nebudou mit zdroje a bude nutne je opozdene startovat rucne - zakaznici se perou o zdroje a nekdy se to muze projevit pomalou aplikaci
Jak se to pouziva
Jednoduse lze pouzivat pri definovani resources memory_max parametr, viz priklad
task "nginx" {
driver = "docker"
resources {
memory = 64
memory_max = 256
}
...
Jak to zapnout
Zjisteni stavu
curl -s $NOMAD_ADDR/v1/operator/scheduler/configuration
zajima na s hodnota promene “MemoryOversubscriptionEnabled”
Povoleni oversubscription
curl -k -XPUT http://localhost:4646/v1/operator/scheduler/configuration \
--header "X-Nomad-Token: ${NOMAD_TOKEN}" \
--data-binary @- <<EOF
{
"MemoryOversubscriptionEnabled": true
}
EOF
Overeni Probiha stejne jako zjisteni stavu
Vice na toto tema lze najit v dokumentaci nomada