Před několika měsíci jsem napsal článek o urychlení vytváření kontejnerů uvnitř kontejneru. Tento článek se soustředil na rychlost stahování obrázků kontejneru a různé způsoby, jak předem naplnit úložiště obrázků, pomocí připojení svazků od hostitele a konceptu Buildah „dalších obchodů“.
Buildah je nástroj příkazového řádku pro rychlé a snadné vytváření obrázků kompatibilních s Open Container Initiative (to znamená i kompatibilní s Dockerem a Kubernetes). Buildah lze snadno začlenit do skriptů a sestavovacích kanálů a nejlepší ze všeho je, že k vytvoření image nevyžaduje běžícího démona kontejneru.
Tento článek se bude zabývat druhým problémem s rychlostí sestavení při použití dnf
/yum
příkazy uvnitř kontejnerů. Všimněte si, že v tomto článku budu používat název dnf
(což je název pro upstream) namísto toho, co používají některé downstreamy (yum
) Tyto komentáře platí pro oba dnf
a yum
.
Rychlost stahování
Všimli jste si někdy, že když spustíte dnf -y update
? nebo dnf -y install
poprvé po nějaké době se příkaz na dlouhou dobu pozastaví, než vůbec začne snižovat otáčky? Co se děje?
První věc, kterou dnf
je stahování velkých souborů mezipaměti. Tyto soubory jsou napsány v XML a obsahují každý jednotlivý balíček ve vzdáleném úložišti, včetně spousty dat o balíčku. Dokonce obsahují všechny cesty v balíčku. Tato data jsou potřebná, abyste mohli spustit něco jako dnf -y install /usr/bin/httpd
a poté dnf
zjistí balíček, který se má nainstalovat. Mnoho balíčků obsahuje příkazy jako (requires: /usr/bin/sendmail
), které tuto funkci využívají a umožňují dnf
vytáhnout vhodný balíček k uspokojení potřeby.
Vytažení těchto obrovských souborů – a co je důležitější, zpracování těchto souborů – může trvat i minutu. Tato data používá libsolv
, takže musí být převeden na solv
formátu, který je pomalý. Rychlost není velký problém, když to na svém hostiteli děláte jen pravidelně, ale pokud jde o stavbu kontejnerů, je to mnohem větší problém.
Syntaxe souboru Docker
Přestože Buildah umožňuje vytvářet obrazy kontejnerů přímo v prostředí, většina lidí používá soubory Dockerfiles a Containerfiles k vytváření kontejnerů a definování reprodukovatelných obrazových receptur. Buildah ve výchozím nastavení hledá Containerfile
a Dockerfile
Nyní. Každý sdílí stejnou syntaxi, takže použiji Containerfile
pro zbytek tohoto dokumentu.
Běžná věc v Containerfile
je použít syntaxi jako:
FROM ubi8
RUN dnf -y update; dnf -y install nginx; dnf -y clean all
…
RUN dnf -y install jboss; dnf -y clean all
Podívejme se na dnf
linky. První dnf
řádek:
(dnf -y update; dnf -y install nginx; dnf -y clean all
):
- Aktualizuje všechny balíčky v kontejneru.
- Nainstaluje vybraný balíček
nginx
. - Vyčistí vše.
Od ubi8
obrázek byl pravděpodobně vytvořen před chvílí a jeho /var/cache/dnf
adresář pravděpodobně neexistuje uvnitř obrazu kontejneru dnf
musí stáhnout soubor mezipaměti XML a zpracovat jej. Poté dnf
nainstaluje skutečné balíčky před dnf -y clean all
odstraní všechna přebytečná data, která předchozí příkazy umístily do obrazu, jako jsou soubory protokolu a mezipaměti.
Uživatelům se doporučuje spustit clean all
aby byl obrázek co nejmenší. Každý RUN
vytvoří novou vrstvu, a to i v případě, že obsah odstraníte později RUN
bude počáteční vrstva obsahovat veškerý obsah. To znamená, že každý, kdo kdy stáhne váš obrázek, skončí stahováním protokolů a souborů mezipaměti. Nyní, pokud váš Containerfile
obsahuje jeden nebo více dnf
příkazy, budete cenu platit znovu a znovu. Nejen to, ale pokaždé, když znovu postavíte tento obraz, zaplatíte tuto cenu znovu. Pokud jste na sestavení serveru, každý obrázek kontejneru, který vytvoříte, bude tyto soubory XML stahovat znovu a znovu, čímž se plýtvá spoustou zdrojů a času.
Buildah s překryvnými držáky
Viděli jsme výše popsaný problém a mysleli jsme si, že bychom to mohli zvládnout lépe. Nemohli bychom jednoduše stáhnout data XML do hostitele, zpracovat je na hostiteli a připojit je do kontejnerů? Možná bychom mohli nastavit úlohu cron nebo systemd
časovač, který provádí dnf makecache
jednou pro každou verzi OS, pro kterou budete vytvářet obrázky kontejnerů? Tuto úlohu byste mohli spustit jednou nebo vícekrát denně na hostiteli a poté nechat všechny svazky tvůrců kontejnerů připojit příslušné mezipaměti do kontejnerů buildah.
Buildah podporuje adresáře pro připojení svazku z hostitele do kontejnerů. To by mělo problém vyřešit a také se to řeší. ALE kontejnery často chtějí zapisovat do tohoto adresáře, pokud musí aktualizovat mezipaměť, takže je třeba mezipaměť namontovat do kontejnerů pro čtení/zápis. To způsobuje obrovskou bezpečnostní díru. Představte si situaci, kdy nepřátelské sestavení kontejneru zapsalo do této mezipaměti obsah, který přečetl pozdější tvůrce kontejnerů. Mohlo by to přimět druhý kontejner k instalaci napadeného softwaru. Potřebujeme řešení, kde je obsah namontován do kontejneru, nelze jej zapisovat kontejnerem, ale přesto do něj lze zapisovat z pohledu kontejneru. To je v podstatě to, co je bod připojení překrytí.
Překryvný souborový systém připojí lower
adresář a poté připojí upper
adresáře do merged
montážní bod. Když proces zapisuje do nového souboru do merged
nový soubor se zapíše do upper
adresář. Když proces upraví existující soubor v lower
jádro zkopíruje soubor z lower
adresáře do upper
adresář a umožňuje procesu upravit soubor v upper
adresář.
Představili jsme koncept Overlay mount do Buildah. Nyní můžete spouštět sestavení pomocí
buildah bud -v /var/cache/dnf:/var/cache/dnf:O -f /tmp/Containerfile /tmp
Dnf
uvnitř kontejneru bude stále kontrolovat, zda je v úložišti novější obsah, a pokud existuje, stáhne obsah dolů. Ale pokud je obsah na hostiteli aktuální, rychle použije mezipaměť hostitele. Doporučil bych vám aktualizovat mezipaměť hostitelů alespoň jednou denně.
Další funkcí, kterou jsme přidali pro držák Buildah Overlay, je zničit upper
adresář na každém RUN
směrnice. Připomeňme si, že v našem příkladu jsme použili více RUN
příkazy, z nichž každý prováděl dnf -y clean all
. dnf -y clean all
příkaz způsobí upper
adresář, aby se veškerý obsah z nižšího adresáře zobrazoval jako smazaný. Pokud je další dnf
příkaz sdílel předchozí horní, viděl by mezipaměť jako prázdnou a musel by stáhnout datové úložiště XML a zpracovat jej. Odstranění upper
adresář znamená, že každý dnf
příkaz znovu uvidí lower
adresář z hostitele a pokračujte ve sdílení mezipaměti hostitelů.
Rozdíl v rychlosti
Vytvořím jednoduchý Containerfile
obsahující dva dnf
spustit příkazy.
FROM fedora:31
RUN dnf -y install net-utils; dnf -y clean all
RUN dnf -y install iputils; dnf -y clean all
Spouštím to lokálně na mém boxu Fedora 31
# time -f "Elapsed Time: %E" buildah bud -f Containerfile .
STEP 1: FROM fedora:31
STEP 2: RUN dnf -y install procps-ng; dnf -y clean all
Fedora Modular 31 - x86_64 2.0 MB/s | 5.2 MB 00:02
Fedora Modular 31 - x86_64 - Updates 1.6 MB/s | 4.0 MB 00:02
Fedora 31 - x86_64 - Updates 4.2 MB/s | 19 MB 00:04
Fedora 31 - x86_64 1.8 MB/s | 71 MB 00:39
Last metadata expiration check: 0:00:01 ago on Wed Feb 5 13:55:54 2020.
Dependencies resolved.
================================================================================
Package Architecture Version Repository Size
================================================================================
Installing:
procps-ng x86_64 3.3.15-6.fc31 fedora 326 k
Transaction Summary
================================================================================
Install 1 Package
Total download size: 326 k
Installed size: 966 k
Downloading Packages:
procps-ng-3.3.15-6.fc31.x86_64.rpm 375 kB/s | 326 kB 00:00
--------------------------------------------------------------------------------
Total 218 kB/s | 326 kB 00:01
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : procps-ng-3.3.15-6.fc31.x86_64 1/1
Running scriptlet: procps-ng-3.3.15-6.fc31.x86_64 1/1
Verifying : procps-ng-3.3.15-6.fc31.x86_64 1/1
Installed:
procps-ng-3.3.15-6.fc31.x86_64
Complete!
33 files removed
STEP 3: RUN dnf -y install iputils; dnf -y clean all
Fedora Modular 31 - x86_64 741 kB/s | 5.2 MB 00:07
Fedora Modular 31 - x86_64 - Updates 928 kB/s | 4.0 MB 00:04
Fedora 31 - x86_64 - Updates 3.8 MB/s | 19 MB 00:05
Fedora 31 - x86_64 7.9 MB/s | 71 MB 00:08
Last metadata expiration check: 0:00:01 ago on Wed Feb 5 13:57:13 2020.
Dependencies resolved.
================================================================================
Package Architecture Version Repository Size
================================================================================
Installing:
iputils x86_64 20190515-3.fc31 fedora 141 k
Transaction Summary
================================================================================
Install 1 Package
Total download size: 141 k
Installed size: 387 k
Downloading Packages:
iputils-20190515-3.fc31.x86_64.rpm 252 kB/s | 141 kB 00:00
--------------------------------------------------------------------------------
Total 141 kB/s | 141 kB 00:01
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : iputils-20190515-3.fc31.x86_64 1/1
Running scriptlet: iputils-20190515-3.fc31.x86_64 1/1
Verifying : iputils-20190515-3.fc31.x86_64 1/1
Installed:
iputils-20190515-3.fc31.x86_64
Complete!
33 files removed
STEP 4: COMMIT
Getting image source signatures
Copying blob ac0b803c5612 skipped: already exists
Copying blob 922380d685bc done
Copying config 566e2afbb4 done
Writing manifest to image destination
Storing signatures
566e2afbb417f0119109578a87950250b566a3b4908868627975a4c7428accfb
566e2afbb417f0119109578a87950250b566a3b4908868627975a4c7428accfb
Elapsed Time: 2:15.00
Tento běh trval 2 minuty a 15 sekund, než se vytvořil nový obrázek kontejneru se dvěma novými balíčky.
Nyní to zkusme s překryvným držákem od hostitele.
# dnf -y makecache
# time -f "Elapsed Time: %E" buildah bud -v /var/cache/dnf:/var/cache/dnf:O -f Containerfile .
STEP 1: FROM fedora:31
STEP 2: RUN dnf -y install procps-ng; dnf -y clean all
Last metadata expiration check: 0:02:34 ago on Wed Feb 5 13:51:54 2020.
Dependencies resolved.
================================================================================
Package Architecture Version Repository Size
================================================================================
Installing:
procps-ng x86_64 3.3.15-6.fc31 fedora 326 k
Transaction Summary
================================================================================
Install 1 Package
Total download size: 326 k
Installed size: 966 k
Downloading Packages:
procps-ng-3.3.15-6.fc31.x86_64.rpm 496 kB/s | 326 kB 00:00
--------------------------------------------------------------------------------
Total 245 kB/s | 326 kB 00:01
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : procps-ng-3.3.15-6.fc31.x86_64 1/1
Running scriptlet: procps-ng-3.3.15-6.fc31.x86_64 1/1
Verifying : procps-ng-3.3.15-6.fc31.x86_64 1/1
Installed:
procps-ng-3.3.15-6.fc31.x86_64
Complete!
285 files removed
STEP 3: RUN dnf -y install iputils; dnf -y clean all
Last metadata expiration check: 0:02:41 ago on Wed Feb 5 13:51:54 2020.
Dependencies resolved.
================================================================================
Package Architecture Version Repository Size
================================================================================
Installing:
iputils x86_64 20190515-3.fc31 fedora 141 k
Transaction Summary
================================================================================
Install 1 Package
Total download size: 141 k
Installed size: 387 k
Downloading Packages:
iputils-20190515-3.fc31.x86_64.rpm 556 kB/s | 141 kB 00:00
--------------------------------------------------------------------------------
Total 222 kB/s | 141 kB 00:00
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : iputils-20190515-3.fc31.x86_64 1/1
Running scriptlet: iputils-20190515-3.fc31.x86_64 1/1
Verifying : iputils-20190515-3.fc31.x86_64 1/1
Installed:
iputils-20190515-3.fc31.x86_64
Complete!
285 files removed
STEP 4: COMMIT
Getting image source signatures
Copying blob ac0b803c5612 skipped: already exists
Copying blob 524bb3b83d61 done
Copying config 0f82aa6064 done
Writing manifest to image destination
Storing signatures
0f82aa6064814ff3dcb603c34c75e516e00817811681b83b8632f3e9b694e518
0f82aa6064814ff3dcb603c34c75e516e00817811681b83b8632f3e9b694e518
Elapsed Time: 0.17.44
Díky připojení Overlay jsme byli schopni vytvořit nový obraz se dvěma dalšími balíčky za 17 sekund místo 2 minut a 15 sekund. To je téměř 8krát rychlejší vytvořit stejný obrázek kontejneru.
Nyní to ukazuje, že pokud vytváříte obrazy na hostitelském operačním systému, který má dnf
metadata předem uložená v mezipaměti můžete urychlit rychlost instalace o OBROVSKÉ množství. Ale co když váš systém sestavení vytváří obrazy pro jiné verze operačního systému? Řekněme, že chcete vytvářet obrázky pro Fedoru 30 i Fedoru 31. Poznámka:Toto by fungovalo také na systému RHEL8, kde možná budete chtít sestavit obrázky RHEL7 a možná i RHEL6.Dnf
obsahuje skvělou funkci, kde můžete určit různá vydání při stahování obsahu pomocí --releasever
volba. Dnf
také umožňuje zadat alternativní adresáře pro umístění cachedir, --setopt=cachedir
.
V následujícím příkladu vytáhnu dvě mezipaměti na hostiteli a poté použiji Buildah v režimu příkazového řádku.
# dnf -y makecache --releasever=31 --setopt=cachedir=/var/cache/dnf/31
# dnf -y makecache --releasever=30 --setopt=cachedir=/var/cache/dnf/30
# ctr31=$(buildah from fedora:31)
# time -f 'Elapsed Time: %E' buildah run -v /var/cache/dnf/31:/var/cache/dnf:O ${ctr31} dnf -y install iputils
Last metadata expiration check: 0:00:15 ago on Wed Feb 5 14:17:41 2020.
Dependencies resolved.
================================================================================
Package Architecture Version Repository Size
================================================================================
Installing:
iputils x86_64 20190515-3.fc31 fedora 141 k
Transaction Summary
================================================================================
Install 1 Package
Total download size: 141 k
Installed size: 387 k
Downloading Packages:
iputils-20190515-3.fc31.x86_64.rpm 192 kB/s | 141 kB 00:00
--------------------------------------------------------------------------------
Total 107 kB/s | 141 kB 00:01
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : iputils-20190515-3.fc31.x86_64 1/1
Running scriptlet: iputils-20190515-3.fc31.x86_64 1/1
Verifying : iputils-20190515-3.fc31.x86_64 1/1
Installed:
iputils-20190515-3.fc31.x86_64
Complete!
Elapsed Time: 0:06.85
# ctr30=$(buildah from fedora:30)
# time -f 'Elapsed Time: %E' buildah run -v /var/cache/dnf/30:/var/cache/dnf:O ${ctr30} dnf -y install iputils
Last metadata expiration check: 0:00:15 ago on Wed Feb 5 14:17:47 2020.
Dependencies resolved.
================================================================================
Package Architecture Version Repository Size
================================================================================
Installing:
iputils x86_64 20180629-4.fc30 fedora 123 k
Transaction Summary
================================================================================
Install 1 Package
Total download size: 123 k
Installed size: 351 k
Downloading Packages:
iputils-20180629-4.fc30.x86_64.rpm 370 kB/s | 123 kB 00:00
--------------------------------------------------------------------------------
Total 138 kB/s | 123 kB 00:00
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : iputils-20180629-4.fc30.x86_64 1/1
Running scriptlet: iputils-20180629-4.fc30.x86_64 1/1
Verifying : iputils-20180629-4.fc30.x86_64 1/1
Installed:
iputils-20180629-4.fc30.x86_64
Complete!
Elapsed Time: 0:08.88
Jak můžete vidět, byli jsme schopni spustit kontejnery Buildah pomocí dnf
mezipaměť ze dvou různých verzí Fedory ze stejného hostitele sestavení a kontejnerů pro Fedoru 31 trvalo 6+ sekund a sestavení Fedory 30 trvalo 8+ sekund.
Poznámka:Vybral jsem podadresář /var/cache/dnf
pro soubory mezipaměti, abyste se ujistili, že štítky SELinux jsou správné. Stačí spustit dnf clean all
nevyčistí /var/cache/dnf/31
. Budete muset spustit dnf clean all --setopt=cachedir=/var/cache/dnf/31
správně vyčistit soubory v mezipaměti úložiště, ale některé artefakty stejně zůstanou (klíče gpg, prázdné adresáře).
Nyní se jen podívejte, jak dlouho by to zabralo spuštění sestavení na Fedoře 31 bez připojení Overlay.
# ctr31=$(buildah from fedora:31)
# time -f 'Elapsed Time: %E' buildah run ${ctr31} dnf -y install iputils
Fedora Modular 31 - x86_64 1.2 MB/s | 5.2 MB 00:04
Fedora Modular 31 - x86_64 - Updates 875 kB/s | 4.0 MB 00:04
Fedora 31 - x86_64 - Updates 2.4 MB/s | 19 MB 00:07
Fedora 31 - x86_64 1.7 MB/s | 71 MB 00:41
Dependencies resolved.
================================================================================
Package Architecture Version Repository Size
================================================================================
Installing:
iputils x86_64 20190515-3.fc31 fedora 141 k
Transaction Summary
================================================================================
Install 1 Package
Total download size: 141 k
Installed size: 387 k
Downloading Packages:
iputils-20190515-3.fc31.x86_64.rpm 279 kB/s | 141 kB 00:00
--------------------------------------------------------------------------------
Total 129 kB/s | 141 kB 00:01
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : iputils-20190515-3.fc31.x86_64 1/1
Running scriptlet: iputils-20190515-3.fc31.x86_64 1/1
Verifying : iputils-20190515-3.fc31.x86_64 1/1
Installed:
iputils-20190515-3.fc31.x86_64
Complete!
Elapsed Time: 1:29.85
V tomto případě trvalo spuštění stejného kontejneru téměř 1,5 minuty. Buildah s držáky Overlay běžel 14krát rychleji.
Kontejnery bez kořenů
Všechny mé příklady až dosud spouštěly sestavení pomocí Containerfiles
jako kořen. Ale můžete to udělat i s bezkořenovými nádobami. V několika dalších příkladech budu mít Buildah spouštět kontejnery pomocí buildah run
syntaxe k demonstraci použití mezipaměti.
Probíhá
$ buildah run -v /var/cache/dnf/30:/var/cache/dnf:O ${ctr30} dnf -y install iputils
funguje dobře. Pokud uživatel může číst /var/cache/dnf/30
adresář, lower
adresář lze číst. Ale musíte se spolehnout na to, že hostitel bude mezipaměť pravidelně aktualizovat.
Pokud uživatelé chtějí, mohou dokonce použít dnf
vytvořit mezipaměť ve svém domovském adresáři.
$ dnf -y makecache --releasever=30 --setopt=cachedir=$HOME/dnfcache
$ chcon --reference /var/cache/dnf -R $HOME/dnfcache
$ ctr30=$(buildah from fedora:30)
$ buildah run -v $HOME/dnfcache:/var/cache/dnf:O ${ctr30} dnf -y install iputils
Všimněte si, že jsem musel změnit štítek SELinux $HOME/dnfcache
adresář, aby SELinux umožnil kontejnerům číst lower
adresář pro připojení Overlay.
Závěr
Urychlení sestavování kontejnerů vyžaduje pochopení toho, co se děje při instalaci balíčků. Předběžné ukládání do mezipaměti dnf
data na hostiteli a použití překryvných připojení k připojení mezipaměti do kontejneru pomocí Buildah může výrazně zvýšit rychlost sestavení a snížit počet zdrojů potřebných k podpoře sestavovací farmy.
Buildah se rovná jednoduchosti, ale má také několik skvělých funkcí, jako je Overlay mounts
a additional stores
což vám může pomoci urychlit vytváření obrázku kontejneru.
[ Jste v kontejnerech noví? Stáhněte si Containers Primer a naučte se základy linuxových kontejnerů. ]