Přejít k navigační liště

Zdroják » Různé » Jak vypadá naše vývojové prostředí

Jak vypadá naše vývojové prostředí

Články Různé

Někdy před rokem jsme se rozhodli – snad finálně! – vyřešit problém, že i když používáme multiplatformní technologie jako je Node.JS, tak ve výsledku má každý vývojář mírně odlišný systém, což způsobuje, že kód, který je funkční na jednom počítači, není funkční na jiném. Cestou se na naše řešení nabalila i jiná pozitiva, a o tom všem si v článku povíme.

Nálepky:

Článek původně vyšel na autorově webu Programio.

Před rokem trpělo naše vývojové prostředí přibližně těmito neduhy:

  • Stáhli jste si zdrojáky webového UI, rozjeli jste ho, ale nefungovalo vám, protože jste si zapomněli ručně stáhnout jednu chybějící knihovnu.
  • Po stažení se sice UI rozběhlo, ale moc toho nefungovalo, protože jste zapomněli spustit backendový server.
  • Spustili jste backend, ale nefungovaly statistiky, protože jste u sebe měli starou verzi backendu.
  • Napsali jste nějaký kód, vyzkoušeli jste ho, otestovali, commitli&pushli a po chvíli vám přišel email z Jenkinsu, že neprošly unit testy, protože máte lokálně jinou verzi testovacího frameworku, než je na Jenskinsu.

Podobných chyb si jistě dokážete představit stovky.

Docker to the rescue!

Docker asi znáte, je teď kolem něj docela hype. Je to něco trochu podobného jako virtualizovaný OS. Pomocí Dockeru můžeme vytvořit kontejner, což je jakýsi sandbox, který je co možná nejvíce odstíněný od hostitelského OS. Tento kontejner si můžeme různě přizpůsobit a nainstalovat tam své aplikace. Z pohledu uživatele se pak Docker kontejner jeví jako samostatný operační systém se svým file systémem a se svými procesy, ale fakticky v rámci Dockeru žádný virtualizovaný OS neběží a vše zkrátka vykonává hostitelský OS.

Můžeme proto na jednom systému spustit třeba deset kontejnerů, v pěti můžeme provozovat Node.JS aplikace, v dalších třech Java aplikace a ve zbývajících můžeme mít třeba nějaký monitoring. Každý kontejner bude jinak nakonfigurovaný, budou tam běžet jiné procesy a přitom nemusíme virtualizovat deset OS. Hlavní výhoda je v úspoře prostředků. Představte si, že na jednom počítači skutečně virtualizujete deset OS.

Námi v současnosti vyvíjený produkt se skládá z několika desítek Node.JS projektů. Některé z nich jsou HTTP servery, další jsou ZeroMQ servery a zbytek jsou sdílené knihovny. Nevím, jestli se vejdeme do definice microservices, nicméně platí, že při běžném vývoji nám běží několik desítek Docker kontejnerů.

Tím, že nám všechny aplikace běží v kontejnerech, získáváme jednotné prostředí pro všechny vývojáře. Už žádné rozdílné verze testovacího frameworku – pro testování používáme framework, který je nainstalovaný v kontejneru. Aplikace se spouští v Nodu, který je opět nainstalovaný v kontejneru. Všechny tyto závislosti se jednou nastaví v konfiguraci daného kontejneru a programátoři už do toho nehrabou.

Veškeré externí závislosti, které se nějak využívají pro běh našich aplikací, máme vždy ve stejných verzích, takže pokud se naše aplikace chová na dvou různých počítačích jinak, obvykle to znamená, že si někdo nesynchronizoval změny v kódu.

No jo, jenže Docker zatím běží pouze na Linuxu a my máme v týmu i Windowsáře a Macaře. Co s tím?

Vagrant to the rescue!

Vagrant je jakýsi wrapper nad virtualizačními programy, jako je VirtualBox nebo VMware apod. Umožňuje nám pomocí jednoduchého konfiguračního souboru nakonfigurovat běžící virtualizovaný OS. Vagrant jsme proto využili tak, že v něm virtualizujeme CentOS, ve kterém spouštíme naše Docker kontejnery. Ráno zkrátka přijdeme do práce, spustíme Vagrant, v něm se spustí kontejnery a jedeme. Všem vývojářům, nehledě na OS, běží všechny aplikace v identickém prostředí.

Další příjemný bonus je jednoduchost prvotní instalace. Pokud přijde do týmu nový člověk, jako první si nainstaluje samotný Vagrant, pak si stáhne konfigurační soubory z repozitáře definující naše vývojové prostředí a jedním příkazem vagrant install nainstaluje všechny aplikace potřebné pro vývoj současného produktu. Druhým příkazem vagrant up pak prostředí spustí. To je celé.

Pokud se během toho procesu nic nepokazí, má někdy po dvou hodinách funkční a běžící aplikaci. Může si v prohlížeči zobrazit naše UI psané v Angularu, tam si může zkusit založit novou kampaň, což odchytí backend – HTTP server, který přes ZeroMQ dá vědět ostatním částem systému o nové kampani. Ty přijmou zprávu a aktualizují nějaké údaje v Mongu, které nám také běží v jednom z kontejnerů. A tak dále.

Protože máme v Dockeru nainstalované i Mongo, což je naše hlavní databáze, má každý vývojář na svém počítači úplnou a nezávislou instalaci celého systému. Pokud například v UI naklikám novou kampaň, data o ní bude mít v Mongu jen ten daný vývojář a nebude tím otravovat ostatní.

Stejně snadno lze psát i integrační testy. Po restartu celého prostředí se všechny kontejnery dostanou do původního stavu, takže můžeme snadno napsat nějaké scénáře a otestovat, zda vše proběhlo, jak mělo. Tyto integrační testy si pak může pustit kterýkoliv vývojář, když si například chce ověřit, že novou fíčurou nezničil nějakou starou.

A co statistiky?

Z předchozích článků víte, že pro statistiky používáme hromadu různých služeb, které jsou navíc napsané v Javě, takže jsou to docela žrouty paměti. Nakonec se ukázalo, že to zase tak velký problém nebyl a zprovoznili jsme všechny části našich statistik přes Docker kontejnery, takže je opravdu možné provozovat celý náš systém na svém počítači bez toho, aby jakákoliv součást byla sdílená. Stručně k jednotlivým službám:

  • Kafce jsme pouze nastavili, aby nežrala tolik paměti přes -Xmx a -Xms parametry a všechny topiky vytváříme pro jednoduchost pouze s jednou partition a bez replikací.
  • Samzy jsme se báli nejvíce, protože jsme standardně pouštěli přes Hadoop a že by se nám do Vagrantu chtělo instalovat ještě Hadoop, to se říci nedalo. Nicméně Samza lze pro testovací účely spustit jako obyčejný Java proces, což jsme využili a spouštíme ji v běhu hodně procesů a nějaké ty externí závislosti. Nakonec jsme ale žádnou závislost navíc neinstalovali. Druid je robustní, takže pokud nějaká služba neběží, Druid se snaží stále fungovat dále v omezených podmínkách. To nám pro testovací účely stačí. Segmenty lze buď neukládat, nebo je lze ukládat na lokální disk.

V kontejnerech nám tedy běží light-weight verze statistik, která se ale chová identicky jako na ostrých serverech, což je přesně to, co potřebujeme.

Další vychytávky

  • Všechny Node.JS aplikace se spouští pod supervisorem, který sleduje změny ve zdrojácích a při každé změně restartuje danou službu.
  • Jak jsem psal výše, celý náš systém se skládá z několika desítek běžících aplikací či knihoven. Jedním z problémů je, jak zařídit, aby se změna v jedné knihovně automaticky projevila ve všech aplikacích, které tuto knihovnu používají. V kontejnerech máme projekty nainstalované a prolinkované tak, aby se přesně toto dělo.
  • Protože díky Vagrantu máme všichni všechny zdrojáky na stejném místě, mohli jsme snadno napsat skripty, které třeba kontrolují, jestli jsme něco nezapomněli commitnout, které umí stáhnout všechny změny z repozitářů nebo které umí spustit unit testy pro danou aplikaci, nehledě na to, jestli je to webová aplikace, nebo serverová. Protože se tyto shell skripty vykonávají uvnitř Vagrantu, automaticky fungují všem, nehledě na OS.
  • Díky Dockeru si můžeme snadno zobrazit logy z každé aplikace, tail-efnout se aktuální logy nebo restartovat kontejner, pokud je zrovna nějaký nemocný.

Na jaké problémy jsme narazili

  • Dlouhodobě jsme měli největší problémy s DNS. Všechny naše projekty běží na nějaké doméně, takže třeba Mongo běží na mongo.adserver.dev, Ad Selector běží na adselector.adserver.dev a podobně. Jenomže aby to fungovalo, potřebujeme něco, co bude dané domény překládat. K tomu jsme používali třeba SkyDNS, což sice fungovalo, ale občas se stávalo, že SkyDNS nastartoval později, než bylo potřeba, a na několik prvních dotazů zkrátka nestihl odpovědět. Částečně to bylo způsobeno i vysokým zatížením systému, viz další bod.
  • Občas jsou problémy s výkonem, hlavně kvůli všem těm watcherům, které sledují zdrojáky. To jsme ze začátku dlouho ladili, než se to vyladilo k plné spokojenosti všech. Na Linuxech jsme nakonec skončili u NFS, se kterým je vše nejrychlejší a nevytěžuje to systém. Při běžném provozu mi celý Vagrant vytěžuje asi 40 % jednoho CPU a přibližně 4 GB RAM.
  • Nebylo úplně jednoduché zařídit, aby se ty desítky kontejnerů spustily ve správném pořadí, ve správném čase, až když běží jiná služba apod.
  • Přesměrování portů. Pokud nějaká aplikace běží v Dockeru a běží na nějakém portu, musíme zařídit, aby se ostatní mohli na tento port dostat. Chceme-li, ať se vidí jednotlivé kontejnery mezi sebou, stačí to uvést v Dockerfilu. My ale občas chceme poslat ze svého lokálního počítače dotaz na nějaký server běžící v kontejneru. Proto musí ještě nastavit, ať je port viditelný i z venku, ne jen z jiného kontejneru. No jo, jenže „z venku“ znamená ve Vagrantu, protože Docker kontejner běží ve Vagrantu. Proto musíme port přesměrovat ještě jednou, mezi naším lokálním strojem a Vagrantem. Jo, je to přesně takový chaos, jaký z tohoto odstavce máte pocit.
  • Co se týče operačních systémů, nejhorší zkušenosti máme s OS X, nejlepší s Linuxem. Windows je tak nějak mezi.

Komentáře

Subscribe
Upozornit na
guest
18 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
karel

Docker na vyvoj moc pekna vec.
Ceho ja se dost obavam je ze se zacne cim dal tim vic docker pouzivat i na produkcni servery pokud to bude jen pro localhost nebo vlan tak s primhourenim oka ok, ale porty ven auu. Narazim na to jak nekteri radi ne-aktualizuji se slovy, kdyz to bezi tak na to nesahej.

Snow

No i v tom je výhoda kontejnerů…
Zauktualizuju kontejner, zjistím že je vše OK, případně vyřeším problémy a nasadím. Mám totiž jistotu že když mě aplikace běžela jinde, poběží stejně i na konkrétním serveru, protože kontejner :-)

Když kontejner nemám, raděj to nechám vbežet když to běží i třeba neaktuální.

To samé jak se pak krásně mění železo, vezmu kontejner a pustím ho kdekoliv a kdekoliv poběží stejně…
Neříkám že má smysl na každej prd používat kontejnery, ale na některé věci to smysl má a na produkční určitě.

David K.

Zajímavý článek. Co používáte na sdílení souborů mezi Windows a VM běžící na Vagrantu? Zkoušel jsem shared folders, ale tam je problém se symlinky. Tak jsem nakonec skončil s tím, že jsem nainstaloval Sambu a připojil jsem si jí do Windows jako sdílený diskový oddíl. Ale občas je to poněkud pomalejší, například phpStormu docela trvá, než detekuje změny v souborech.

Michal P.

Sdílení souborů mezi Windows a VM ve virtualboxu (Vagrantu) je obecný problém. Všem, kteří běží pod Linuxem, Mac OS doporučujeme aktivovat sdílení přes NFS. Vývojáři na Windows však většinou používají klasické shared folders. S trochou snahy se dá NFS rozchodit také pod windows s pluginem vagrant-winnfsd, ten má však svoje mouchy a při testech se choval nestabilně. Symlinky jsou také jedním z problémů, ale to se dá vyřešit poměrně jednoduchou úpravou Vagrantfilu a instalací vagrant pluginu vagrant-vbguest např.:

vagrant plugin install vagrant-vbguest

vb.customize [„setextradata“, :id, „VBoxInternal2/SharedFoldersEnableSymlinksCreate/vagrant“, „1“]

Jakub M.

Jak řešíte to, aby všichni mohli v klidu vyvíjet a nemuseli bojovat s nastavením tohoto vývojového prostřední? Podle článku to zní, že celý proces není zdaleka bezproblémový a pokud se něco pokazí třeba na virtualizaci, tak je například takový UI vývojář v pasti.

Zatím se mi nejvíce osvědčilo maximální část centralizovat – mimo jiné pro nás důležitá výhoda je, že k tomu, aby viděl stejnou chybu jako kolega, stačí většinou jen aktualizovat repozitáře.

Pokud bych tedy chtěl spustit něco pro každého vývojáře zvlášť, tak bych zkusil dát všechny instance vaším způsobem na jeden server. Zkoušeli jste něco takového?

Jan K.

Jak u vás vzniká nová microapps? Zvládne to i běžný programátor nebo to je magie pro guru? V hledáčku jsme nedávno měli i podobný systém, ale při testování se nám to prostě nelíbo, je to příliš neflexibilní, problémy mají zásadně win/osx vývojáři, kteří si s tím moc neporadí, linuxákům je vesměs vše jedno a vyřeší si to sami.

Co nám vadilo:

  • dlouhá aktualizace, každé ráno by měl každý vývřojář stahovat stovky mb až několik gb dat, v momentě když jsme začali řešit lokální reverzní proxy s přednačítáním, byla to stopka
  • udělat si vlastní mikroslužbu nebo vyzkoušet novou databázi bylo příliš komplikované
  • pokud se vyskytl netriviální problém, získat stav (image) z vývojářova stroje bylo prostě časově náročné
  • přílišna náročnost velkou část služeb a databází spustit na vývojářově stroji (stovky mikroslužeb) a s tím i komplikované zjisťování závislostí
  • vývojáři neřešili performance a často navrhli nevhodné modely nebo jejich řešení nebylo škálovatelné, opravy a kontroly zabraly dost času
  • načítání frontendů bylo příliš rychlé a pozornost se tolik nevěnovala UX při horší latency
  • pro tým testerů bylo velice komplikované a časově náročné vše stahovat k sobě, distribuce testovacích databází v tomhle pokulhávala a špatně se nám to udržovalo zároveň s vývojem kódu

Tím narážím i na poslední otázku předřečníka, ptal se, jestli máte vývojový společný dev server, kde by tyhle containery běžely a vývojáři je mohli používat.

Narazili jste už na nějaký z těhle problémů a případně počítáte s nimi nebo to už máte nějak vyřešené?

Ondřej
  • Novou aplikaci zakládá obvykle náš guru, ale zvládl by to i obyčejný programátor, kdyby bylo potřeba (já to zvládl, když jsem tam integroval statistiky). Nové aplikace nezakládáme zase tak často, takže to není problém.
  • Ranní aktualizace trvá asi patnáct, dvacet minut. Stáhnou se aktuální verzi Dockerfilů, databázových dumpů, zbuildí se znova kontejnery a následně se pullnout projekty. Zatím to není problém a dá se to stihnout během ranní kávy nebo ranní porady, takže to moc nezdržuje. Asi nemáme řešení pro případ, kdy by to lezlo do stovek kontejnerů.
  • Pokud se vyskytne netriviální problém, zavolá se guru, který ho chudák musí vyřešit. Většinou ale stačí restart některé ze služeb.
  • S náročností velký problém nemáme, i když jsme třeba už párkrát museli upravovat watche, aby nesledovaly úplně všechno. Ale máme desítky služeb, ne stovky.
  • Performance cíleně také neřešíme, ale produkt už je reálně nasazený a zatím o stížnosti na performance nevím. Je možné, že jsme to navrhli blbě, ale to ukáže až čas.
  • V produkci neběžíme na Dockeru, tam je to releasnuté bez něj. Není tedy problém releasnout to na ještě jeden server pro testovací účely. Vývoj ale probíhá výhradně v Dockeru&Vagrantu. Tedy ne že by to byl nějaký příkaz přes který nejede vlak, ale zkrátka to funguje a je to nejpohodlnější.
Jan K.

Díky za odpověď :). Ano, jen nás ve firmě přes sto programátorů a mnoho týmů, aplikace nám běží napříč všemi kontinenty, technologií používáme několik desítek, proto jsme narazily na již zmíněné problémy.

Přeji tedy hodně úspěchů s vaší architekturou a doufám, že za rok se podělíte s novými zkušenostmi.

Kapral

Stáhli jste si zdrojáky webového UI, rozjeli jste ho, ale nefungovalo vám, protože jste si zapomněli ručně stáhnout jednu chybějící knihovnu.
Po stažení se sice UI rozběhlo, ale moc toho nefungovalo, protože jste zapomněli spustit backendový server.
Spustili jste backend, ale nefungovaly statistiky, protože jste u sebe měli starou verzi backendu.
Napsali jste nějaký kód, vyzkoušeli jste ho, otestovali, commitli&pushli a po chvíli vám přišel email z Jenkinsu, že neprošly unit testy, protože máte lokálně jinou verzi testovacího frameworku, než je na Jenskinsu.

Všechny tyhle body na mě působí spíš tak, že vývojář je prase a závislosti nebo tasky pro npm/composer/bower/gulp/grunt/… nenadefinoval správně. Pokud potřebuju knihovnu ve verzi 16.5.2, tak snad příslušnýmu package manageru tohle sdělím. Pokud je v projektu prostor proto, aby do něj vývojář stáhnul jinou verzi libky, tak je to fail.

Osobně vidím sílu kontejnerů spíš v tom, že na různých prostředích se app může chovat jinak a pokud má každý vývojář jiný OS, používá jiný webserver apod. tak dochází k problémům. Zde je to opravdu užitečné.

Ještě bych rád upozornil na to, že vagranty a dockery nejsou zrovna 2x bezpečné.

Zdeněk Tisoň

S tím UI máš pravdu, ale naše prostředí se skládá z mnoha oddělených mikro služeb, které spolu komunikují pomocí různých kanálů (kafka, zeromq, http) a tady už ti moc správně napsaný soubor pro package manager nepomůže.

wsh

Ještě bych rád upozornil na to, že vagranty a dockery nejsou zrovna 2x bezpečné.

Můžeš to nějak víc rozvést? V použití docker kontejnerů vidím v produkci vidím určité výzvy (třeba aktualizaci bundlovaných programů a knihoven), ale paušálnímu prohlášení, že nejsou zrovna bezpečné úplně nerozumím.

Jan K.

nejspíš není myšlena bezpečnost samotných technologií, ale stav, kdy používáš veřejné neověřené containery, které mohou kdykoliv aktualizací způsobit průnik zákeřného kódu nebo shodit celou produkci.

V produkci prostě nesmí být nic, co nemáš sám pod kontrolou a co nevytváří tvoji admini. Docker/Vagrant není technologie primárně pro bezpečnost, ale šiřitelnost a přenositelnost.

wsh

To se ale příliš neliší od stavu, kdy se aplikace instaluje pomocí composer, npm, bower apod. z desítek až stovek externích repositářů, které také nemáš pod kontrolou. Pokud to firemní procesy dovolí, bude se to dít s dockerem i bez něj. Naopak pokud admini udržují ověřené image, mohou pak díky dockeru stejné používat vývojáři na svých stanicích.

Jan K.

ano, s tím plně souhlasím. Docker to riziko nepřináší, ono v té firmě už musí být zakořeněné.

S dockerem je ale ještě jiná věc, na kterou narážíš v poslední větě, často ho používají pouze programátoři, kteří si tohle nedokážou zkontrolovat. Pokud je tým adminů, kteří udržují kontainery, je to v pořádku, pokud ale o kontainery se starají programátoři, je zadaěláno na průser.

Kontrolou ideálně musí projít vše, ale php programátor bez komplikací zkontroluje/projde composer balíček, naopak už těžko docker obraz, pokud zároveň není admin.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.