The Twelve-Factor Application

Už nějakou dobu je známo, že Geetoo nabízí Kubernetes v cloudu zákazníkům. Upřesním-li, Kubernetes v beta testu. Postupně přicházejí zajímavá témata a zkušenosti z provozu. Jedno z častěji diskutovaných je o tom, jak vlastně upravit nebo napsat aplikace tak, aby byly co nejlépe provozovatelné v Kubernetes prostředí.

Faktem je, že dnes je téma kontejnerů a jejich orchestrace velmi populární. Téměř všichni o něm hovoří, či o něm už slyšeli, a nebo dokonce vědí, že Kubernetes se za poslední dobu stal de facto standardem na poli kontejnerové orchestrace. I přes to, že pojmy, jako cloud native aplikace a mikroservices, nejsou nijak nové, ne všichni je znají. Přitom pochopení základních principů ulehčí zpravidla provoz a nasazení aplikací. Stejně tak šetří výpočetní zdroje, což při provozu v cloudu přímo snižuje finanční nákladnost.

Dobré znalosti a zkušenost mají vývojáři, kteří se již s cloud native vývojem setkali.  Ne však ti, kteří přecházejí z virtuálních serverů na kontejnery.

Jednou z osvědčených cest je metodika pocházející původně z PaaS služby Heroku: “dvanáctifaktorová aplikace,”  The Twelve-Factor Application. Jedná se o sadu dvanácti doporučení.
Pokud se jich budete při návrhu a vývoji držet, velmi si zjednodušíte práci a předejdete nejběžnějším problémům při nasazení aplikace do cloudu.

Není potřeba, abyste si všechny zapamatovali jako básničku. Jde spíše o to je zmínit a říct si, proč jsou důležité a proč usnadní život aplikace v cloudu.  

The Twelve-Factor Application

Rozepsané detaily jednotlivých bodů najdete na 12factor.net. 

1. Codebase – Používejte jeden repozitář pro svůj kód. Zjednodušeně, “aplikace = repozitář”. Je jedno, zda použijete Git, Mercurial nebo Subversion. Více branches (větví) je OK. Více repozitářů jedné aplikace už ne. Z toho repozitáře pak můžete nasazovat aplikace do různých “stages”, ve kterých mohou být různé verze commitů kódu.

2. Dependencies – Nikdy slepě nepředpokládejte existenci knihoven nebo systémových nástrojů. Programovací jazyky mají deklaraci závislostí vyřešenou sami. Například Ruby má Bundler s gemfile. Java má Maven ap. Používejte je.  Stejně tak nepředpokládejte automatickou přítomnost nástrojů jako je ImageMagic. Ideální by bylo, kdyby tento nástroj byl vždy “zabalen” s vaší aplikací. Myslím si však, že než strávit dny práce s tím, jak to udělat,  plně postačí nějaký skript, který při deploymentu zjistí přítomnost potřebných nástrojů, a pokud tam nejsou, zareaguje správně. 

3. Config – Striktně oddělte konfiguraci od kódu. Ve zdrojovém kódu by neměly být proměnné  „zadrátované“ uvnitř. 

Zde platí jedno cvičení. Představte si, že přijde šéf a řekne: “Od teď je náš kód veřejně dostupný na Githubu a každý si ho může stáhnout a použít.”  Zamyslete se, zda tam nemáte odkazy na interní IP adresy nebo proměnné, které by byly platné pouze ve vašem prostředí. To, že v kódu nemáte hesla, je samozřejmé a ani mě nenapadne se o tom zmiňovat, že? 🙂 

Metodika 12factor doporučuje používat “environment variables” pro ukládání proměnných. Nejsem si jistý, zda je nejvhodnější ukládat proměnné do souboru. Dle mého názoru to porušuje závislost na podkladovém operačním systému. Moje preference je key-value store nebo aplikace typu Vault, nicméně doporučení z metodiky je jasné. Kód a vstupní proměnné držet odděleně.

4. Backing Services – Jsou odpůrné služby jako SMTP, MYSQL databáze nebo hostované monitorovací systémy typu New Relic. Z pohledu 12factoru je jedno, zda je to lokální nebo hostovaná služba.  Měla by být dostupná pomocí URL nebo přístupná přes přístupové údaje v konfiguračním souboru. Aby bylo jednoduché změnit třeba lokální MYSQL na cloudovou pouhou změnou URL a přihlašovacích údajů.




5. Build, Release, Run – Striktně oddělujte vývojové “stages”. Každý takový stupeň by měl své “release ID” se svou konfigurací a možnost rollbacku. Je jasné, že pro menší společnosti je potřeba méně stupňů a pro velké je staging zahrnut v CI/CD procesech. 

6. Stateless Processes – Pokud si myslíte, že kontejnery by měly mít své stavové informace na lokálních discích nebo v paměti serverů, tak je to špatně. Dvanácti faktorová aplikace musí být bezstavová (stateless) a “share-nothing”. Veškeré stavové informace by měly být v podpůrných systémech typu databáze. 

Toto by se mělo dodržovat i v aplikacích, které si udržují tzv. “sticky sessions”, a tyto potřebné informace by měly být udržovány v systémech typu Memcahed nebo Redis. 

7. Port Binding – Vaše aplikace by neměla být přímo dostupná na portech otevřených aplikačním serverem. Místo toho by měly být instance aplikace sloučeny do “služby”, která dokáže routovat a udržovat spojení nad mnoha aplikačními porty. V Kubernetes je to například “Service” který se stará o toto slučování, vytváření virtuálních IP a portů ap. 

8. Concurrency  – Pokud navrhujete cloud native aplikace v principech 12 factor, tak vás moc nebude zajímat vertikální škálování. Tedy zvyšování výkonu aplikace přidáváním výkonu na jednom serveru. Naopak. Aplikace by měla být velmi jednoduše škálovatelná horizontálně přidáváním dalších “nodů” nebo serverů. Důvodů je mnoho. Jeden z nich je ten, že vertikální škálování má své limity. Jak technické, tak ekonomické. Škálování horizontální je levnější a technicky dostupnější. 

Obdobně je také možné přemýšlet o procesech, ve kterých běží vaše aplikace. Mělo by je být možné zastavit a spustit bez toho, aniž by ovlivnily chod ostatních. Tedy psát aplikace co nejmenší a co nejvíce izolované.

9. Disposability – Velkou změnou myšlení je nahlížet na aplikaci úplně jinak než jsme dosud zvyklí ze světa virtuálních serverů, kde má každý server své jméno. Víte, co na něm běží, a pokud se něco rozbije, tak o něj máte strach a jdete ho opravit. Klidně o půlnoci.

V cloud native  je na infrastrukturu  nahlíženo jako na množství výpočetních nodů. Žádný z nich nemá pěkné jméno, ale své ID. Pokud se rozbije, tak se neléčí, ale ničí a místo něho se hned vytvoří nový klon.  Toto je myšlenka “jednorázového použití”. Vaše aplikace by měla bez problémů přežít SIGTERM, ale pro uživatele to neznamená nedostupnost služby. 

10. Dev/Prod Parity– Držte vývojové, testovací a produkční prostředí co nejvíce podobné, ne-li stejné. 12factorové aplikace jsou připraveny na CI-CD  (Continous Integrations Continous Delivery pipeline). Jsou tedy připraveny na situace, kdy vývojáři publikují své změny téměř okamžitě a nečekají na sprinty trvající týdny. 

Prostě zajistěte co nejjednodušší cestu od vývoje do produkce. Využívejte knihovny, které dělají transparentní přístup k podpůrným službám, napříkad ActiveRecord v Railsech pro přístup k databázím.

11. Logs – Každá aplikace by měla zapisovat logy na STDOUT bez cachingu. Externím procesem mimo aplikaci by potom mělo dojít k cílovému nasměrování logu na nějaké centrální místo, například do Log Insight nebo Splunk. Tedy nasměrovat logy mimo proces aplikace a teprve tam je potom obsluhovat, aby nedošlo k možné ztrátě důležitých informací. 

12. Admin Processes – Jednorázové administrátorské úkony, třeba jako je migrace schémat databáze nebo spuštění předpřipravených scriptů, by měly probíhat ve stejném stage,kde běží aplikace. I tyto jednorázové administrační scripty a nástroje by měly být součástí centrálního kódu v repozitáři a měly by se distribuovat spolu s ostatním kódem.

Celkově si myslím, že tato metodika je souhrnem velmi dobrých doporučení, kterými je dobré se zabývat, pokud přemýšlíte o „cloud native“ aplikacích a Kubernetes. Sledujte další příspěvky, ve kterých se podíváme na konkrétní použití metodiky pro aplikaci nasazenou do Kubernetes.