Mobilní vývoj v Zonky

Lukáš Gergel
zonky-developers
Published in
5 min readFeb 4, 2019

S příchodem mobilní aplikace jsme v Zonky začali řešit také CI/CD pro vývoj našich mobilních aplikací. Hned od začátku jsme měli dva „jednoduché” požadavky:

  1. Použít stávající technologie pro CI (použít pro orchestraci Jenkins).
  2. Použít cloudové řešení pro sestavování aplikací a testování (firma běží na AWS, nechceme se starat o železo).

Jeden z bodů se nám nepodařilo zcela splnit.

Mobilní aplikace u nás vyvíjíme nativně pro Android a iOS. Řešili jsme tak automatizaci pro obě platformy. Pro Android platformu bylo řešení přímočaré. Stačilo nakonfigurovat Jenkins tak, aby spouštěl sestavení v Dockeru přímo na našem AWS.

S iOS byla situace komplikovanější. Jablkový projekt si jen tak v dockeru nesestavíte. Vydali jsme se cestou pronájmu Mac stroje v cloudu.

Macstadium.com

První služba, kterou jsme zkusili. Za cca $70/měsíc poskytují „dedikovaný” Mac mini. Dostanete veřejnou IP, ke které se lze připojit přes VNC nebo SSH. Stroj běží jako u jiných poskytovatelů na VmWare virtualizaci. Ze začátku jsme byli spokojeni. Čas čistého sestavení ad-hoc verze naší iOS aplikace se držel kolem 20 minut. S tím jsme prozatím dokázali žít.

V okamžiku, kdy se našemu security oddělení přestalo líbit, že stroj má otevřené porty do internetu, to začalo skřípat. S podporou jsme začali řešit, jak omezit přístupy na stroj jen pro nás. Byla nám nabídnuta doplňková služba, pojmenovali to, myslím, „VPN”. Bohužel si zmiňovanou doplňkovou službu cenili téměř na dvojnásobek ceny pronájmu stroje. Za takovou cenu nám to přestalo dávat smysl.

Macincloud.com

Pokus číslo dva, tentokráte se službou za cenu výrazně nižší. Vše se tváři podobně. Virtualizovaný Mac mini na technologii VmWare. Čas čistého sestavení poloviční jako u konkurence. Bohužel se během krátkého času ukázalo, že provozovatelé nemají moc dobře dimenzovaný HW. Po pár týdnech čas čistého sestavení stoupl na 1 hodinu! Za pracovní dobu stihneme sestavit iOS aplikaci 4x? Vážně? (1h pro test + 1h ad-hoc verze)

Opět se psalo na support, co to má být. K dotazům jsem přiložil benchmark žalostné rychlosti zápisu/čtení disků. Z dřívějška jsem měl s virtualizací své zkušenosti, tak jsem tipoval hned, že problém bude souviset s rychlostí úložiště. Převedli nás na jiný HW a sestavení jedné varianty trvalo kolem 5 minut. Nádhera. Bohužel jen dočasně. Během týdnů čas sestavení postupně rostl, až byl zpět na 50 minutách. Au revoir, vážení.

Kam dál? Povrchně jsem zkusil CircleCI, ale nejspíš díky mé neznalosti se mi nepodařilo korektně zprovoznit podepisování aplikace. Tyto pokusy nás stály hromadu času. Bylo by vhodné najít fungující řešení. A také se našlo. Objednali jsme právě vydanou novou verzi Mac mini v konfiguraci: 16 GB RAM, SSD, i3 4 core.

Carthage

Aktuálně jsou pro Swift projekty použitelné dva hlavní nástroje pro správu externích závislostí. Starší CocoaPods a Carthage. Oficiální Swift Package Manager od Apple zatím, co vím, nepodporuje iOS.

V projektu používáme primárně Carthage. Pro závislosti, které přes něj nelze instalovat, používáme CocoaPods. Kdo používá „pody” ví, že po „clean” projektu sestavuje znovu všechny externí závislosti a to zabere dost času. Carthage tímto neduhem netrpí, zato je s ním jiný potíž. Sestavené závislosti jsou v adresáři projektu což má za následek, že když Jenkins sestavuje novou branch (=> nový projekt => nový adresář), musí znovu sestavit závislosti a to je také zabiják času. Nebyl problém čekat 20–30 minut jen na Carthage. Začarovaný kruh. Jak z toho ven?

Rome — cache pro Carthage

K časům kolem 4 minut o kterých jsem psal výše nám výrazně napomáhá Rome — nástroj pro kešování Carthage. Stručně řečeno, Rome vezme frameworky sestavené pomocí Carthage a vykopíruje je mimo adresář projektu. A to verzovaně. Pro nové sestavení pak před spuštěním Carthage zavoláme Rome. Ten se pokusí dle Cartfile.resolved natáhnout existující frameworky odpovídajících verzí ze své cache. Pokud jsou všechny závislosti nalezeny, Carthage nemá co dělat. Tohle vše se stihne během několika vteřin. Jako úložistě podporuje Rome několik možností. Lokální úložitě je základ, zajímavá je možnost použít některé z podporovaných cloud úložišt. Např. Amazon’s S3. Použitím cloudového úložiště tak celý tým i Jenkins může používat stejnou cache. Problém není ani pokud část týmu potřebuje stejné verze závislostí, ale už třeba pracují s novou verzí jayzka Swift. Pro tyto případy lze použít prefixování.

Konfigurace

Rome nainstalujeme pomocí Homebrew.

brew install blender/homebrew-tap/rome

Pro konfiguraci se používá YAML soubor nazvaný Romefile, umístěný v adresáři ve kterém leží Cartfile.resolved. Jak je uvedeno dokumentaci, konfigurační soubor může mít několik částí:

  1. sekce cache — definice úložistě pro cache (povinná)
  2. sekce repositoryMap — mapování názvu repository na název výsledného frameworku/frameworků. Často se liší. Např. lottie-ios = Lottie
  3. sekce ignoreMap — definice ignorovaných názvů frameworků (např. pokud závislost v Cartfile.resolved nevytváří framework)

Jak Rome použít

Budeme potřebovat tři základní příkazy: upload, download a list. Inicializaci nebo aktualizaci cache po změne závislostí provádí příkaz rome upload. Pro sestavení závislostí a jejich upload do cache stačí použít složený příkaz:

carthage update --platform iOS --cache-build && rome upload

V opačném směru, stažení závislostí z cache dle Cartfile.resolved, realizuje příkaz rome download. Doporučuji přidat parametr platform a omezit tak případné stahování frameworků pro jiné platformy. Používáme Rome výhradně pro iOS platformu, může se ale stát, že někdo spustí sestavení Carthage bez omezení na platformu a tím by se do cache mohly dostat také verze pro jinou platformu. Samotný příkaz je následující:

rome download --platform iOS

Poslední částí skládačky je příkaz rome list kterým lze po stažení závislostí z cahe zkontrolovat a vypsat chybějící frameworky. Příkaz opět podporuje parametr platform. Jeho výstup lze poslat přímo na vstup Carthage a tím optimalizovat sestavování pouze na chybějící součásti. V našem případě:

rome list --missing --platform ios | awk '{print $1}' | xargs carthage bootstrap --platform iOS --cache-builds

Všimněte si parametru --cache-builds pro carthage. V dokumentaci doporučují jeho použití. Rome pak pracuje s .version soubory které při použití tohoto parametru carthage vytvoří. Zmíněné tři příkazy nám pomáhají k tomu, aby vše hladce fungovalo a Carthage už nebyl úzkým hrdlem v našem CI procesu. Jako příklad uvádím odpovídající část z našeho fastfile:

lane :cart do
# download missing frameworks
sh "rome download --platform iOS"
# list what is missing and update/build if needed
sh "rome list --missing --platform ios | awk '{print $1}' | xargs carthage bootstrap --platform iOS --cache-builds"
# upload what is missing
sh "rome list --missing --platform ios | awk '{print $1}' | xargs rome upload --platform ios"
end

Ná obrázku níže je ukázka pipeline při releasu naší iOS aplikace. Při běžném provozu, kdy se sestavují ad-hoc verze, jsou časy v kroku Build o cca 2 minuty kratší.

Často si můžeme přečíst, kterak se uživatelé jedné či druhé mobilní platformy popichují která je ta lepší. V tomto článku jsem se jako vývojář snažil přiblížit jak u nás v Zonky vypadalo rozjetí CI pro obě mobilní platformy. Kdo dočetl až sem už ví, která platforma nás více potrápila.

A co u Vás? Jak děláte mobilní CI? Podělte se s námi v komentářích.

--

--