Cvičení: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14.

Písemka z T02 (shellové skriptování) bude tento týden pro čtvrteční cvičení.

Hlavním tématem tohoto cvičení je používání kontejnerů: lehkých virtuálních strojů, které jsou velmi užitečné pro testování a vývoj.

Budou také použity v “královském” tématu toho cvičení: nastavení continuous integration na GitLabu takže budete moci kontrolovat zdraví vašeho softwaru s co nejmenší námahou.

Předstartovní kontrola

  • Víte, že software se na Linuxu instaluje pomocí správce balíčků.

Kontejnery

Pokud jste s kontejnery již obeznámeni, všimněte si, že v úvodní části textu záměrně ignorujeme rozdíl mezi obrazem kontejneru a samotným kontejnerem. Věříme, že je to pro první kroky o něco jednodušší.

Kontejnery jsou dalším způsobem izolace. Zatím jsme viděli izolování projektu sandboxingem a mnoho z vás si vyzkoušelo virtualizovanou instalaci Linuxu.

Kontejnery jsou někde na pomezí. Nabízejí izolované prostředí, které se v podstatě chová jako virtualizovaný stroj. Z implementačního hlediska jsou blíže virtuálním prostředím, protože procesy uvnitř kontejneru jsou viditelné z hostitele. Můžeme si to představit tak, že kontejner dostane jeden adresář (který obsahuje obvyklé podadresáře jako /dev, /proc nebo /home) a z něj nemůže uniknout.

Kvůli tomu mohou kontejnery spouštět jen aplikace napsané pro tentýž operační systém (na rozdíl od plnohodnotného virtuálního stroje).

Protože jsou kontejnery od hostitelského systému odděleny, jsou v mnoha situacích velmi užitečné. Pochopitelně je tu i možnost použít plně virtualizovaný stroj (např. VirtualBox nebo QEMU), ale kontejnery jsou lehčí a mají menší režii (např. rychlejší start).

Oddělení od hostitelského systému je poměrně velké: bez dodatečné konfigurace se kontejner nemůže dostat na hostitelův systém souborů a nemůže poslouchat na žádných portech (pro příchozí spojení). Může ale začít odchozí komunikaci (např. stahovat balíčky, které je potřeba nainstalovat). Kontejner může být též omezen množstvím paměti RAM, kterou může použít. Ve výchozím nastavení jsou procesy uvnitř kontejneru plánovány jako běžné procesy (tj. mají stejnou prioritu), je ale možné omezit i jejich přístup k CPU (čili je zpomalit jako úlohy s nízkou prioritou).

Typickým příkladem je potřeba spustit izolovaný server, který potřebujete pro vývoj. Zde si můžete představit třeba databázový nebo webový server. Určitě můžete takový server nainstalovat do systému (vzpomeňte si na cvičení 08). Tam ale není od systému nijak oddělený a odinstalace také není úplně přímočará. Vzpomeňte si, jak fungují virtuální prostředí: odstraněním jednoho adresáře odstraníme kompletně celé prostředí.

Podobně, odstranění kontejneru je jednoduchá a rychlá operace a nový můžete nastartovat během pár vteřin.

Používání kontejneru vám také umožní přesně určit, jak bude vše vypadat: které procesy se spustí, na kterém portu bude poslouchat atd. Tuto konfiguraci pak můžeme lehce kodifikovat (podobně jako requirements.txt) a díky tomu snadno zopakovat na jiném stroji.

Obrazy kontejnerů jsou také často používány, když potřebujete distribuovat složitou aplikaci, která vyžaduje běh několika služeb. Namísto poskytnutí detailního manuálu nebo obrazu disku pro VirtualBox můžete dodat kontejner, který již bude připraven ke spuštění. Uživatel pak spustí celý kontejner a ten si už sám uvnitř vyřeší zbytek a navenek zpřístupní cílovou službu. Například celý GitLab lze stáhnout a používat v kontejneru.

Docker a Podman

V tomto cvičení se podíváme na základy Linuxových kontejnerů postavených nad Dockerem a Podmanem. Obě implementace jsou v podstatě stejné. Jejich hlavní příkazy (docker a podman) podporují úplně stejné argumenty a mají skoro vždy úplně stejnou sémantiku.

Hlavním rozdílem je, že Docker je trochu starší (ale je stále ještě vyvíjen) a byl zamýšlen pro systémové kontejnery (např. pokud byste si chtěli pustit vlastní GitLab). Podman je o něco mladší a využívá nové vlastnosti Linuxového jádra, které mu dovolují spouštět kontejnery bez práv superuživatele (což je pořád ještě poměrně nová funkce Linuxu). Navíc, Podman se lépe integruje do zbytku systému.

Z tohoto pohledu je Podman perfektní volbou pro vývojáře. Potřebujete databázový server? Použijte Podman s tím správným kontejnerem a spusťte ho. Vaše databáze je připravená k použití. To vše bez potřeby práv superuživatele (často se setkáte s označením rootless mode).

Na druhou stranu, pokud máte o něco starší verzi Linuxu nebo kontejner vyžaduje specifické vlastnosti Dockeru, Docker může být lepší volbou.

Terminologie …

V tomto cvičení jsou důležité dva koncepty. Obraz (image) a kontejner (container). Jsou trochu podobné třídě a objektu (instanci) nebo programu a běžícímu procesu.

Obraz je něco jako pevný disk pro izolované prostředí. Obsahuje všechny potřebné soubory: spustitelné i datové soubory.

Abychom ho spustili, vytvoříme kontejner. Kontejner je spuštěn se stejným stavem jako obraz, ale má i běžící procesy, které mohou měnit jeho stav. Pokud o to explicitně nepožádáme, změny provedené kontejnerem nejsou uloženy zpátky na obraz: místo toho je kontejner spuštěn s kopií obrazu a mění tuto kopii.

Procesy v kontejneru jsou izolovány od okolí (hostitele) a kontejner nevidí procesy hostitele.

Na druhou stranu, procesy v kontejneru jsou viditelné na hostiteli. Kořenovému adresáři kontejneru odpovídá nějaký podadresář na hostiteli. ID uživatelů v kontejneru jsou přeložena na uživatelská ID hostitele. To samé platí o skupinách.

Docker/Podman obvykle spouští své procesy s privilegii kontejnerového uživatele root, který se navenek – v hostiteli – tváří jako obyčejný uživatel (obvykle s velmi vysokým UID).

Skládání obrazů

Nové obrazy jsou obvykle odvozeny od jiných, již existujících. Například existují základní obrazy systému a z nich jsou vytvářeny další specializované obrazy. To zjednodušuje konfiguraci, protože můžeme začít s předpřipraveným stavem a nemusíme začínat od nuly.

Pro ušetření místa jsou odvozené obrazy ukládány jen jako rozdíl oproti základnímu (rodičovskému) obrazu. Rozdíly jsou pak sloučeny (overlay) se základním obrazem v okamžiku, kdy se vytváří kontejner.

To zlepšuje výkon a šetří místo na disku i v paměti (pokud vám běží více kontejnerů se stejným základním obrazem, tak stačí jedna sdílená instance základního obrazu). Také když stahujete nový obraz, můžete stahovat jen rozdíly, pokud jste už dříve stáhli základní obraz.

Tento mechanismus je trochu podobný tomu, co dělá Git. Tváří se, že každý commit je vlastně kompletní kopie celého stromu souborů v projektu. Interně si ale zaznamenává jen rozdíly mezi soubory.

Distribuce a Alpine

Obrazy můžou být vytvořeny nad různými distribucemi. Díky tomu jsou kontejnery snadnou cestou, jak vyzkoušet váš program v různých distribucích bez nutnosti instalovat triple- (nebo více-) boot nebo se starat o několik virtuálních strojů.

Brzy uvidíte, že mnoho kontejnerů je postaveno nad distribucí Alpine Linux. To je minimalisticky navržená distribuce (velikostí i složitostí) – má okolo 6 MB a nemá žádnou složitou konfiguraci.

Alpine používá Apk (Alpine package manager) pro správu balíčků. Například následující příkaz nainstaluje curl (který není nainstalován ve výchozím stavu):

apk add curl

Nastavení Dockeru/Podmanu

Nainstalujte Docker nebo Podman.

Následující příkaz by vám měl pomoci rozhodnout, který z nich vlastně potřebujete.

grep cgroup /proc/filesystems

Pokud uvidíte jen následující řádku, váš kernel nezná cgroups v2, které potřebuje Podman.

nodev   cgroup

Pokud ale uvidíte následující, máte cgroups v2 povolené a měli byste používat Podman.

nodev   cgroup
nodev   cgroup2

Pak pokračujte s instalací. Nejnovější verze Fedory už přešly na cgroup v2 a instalace Podmanu je jedinou možností. Takže ho instalujte pomocí sudo dnf install podman.

Všechny následující příklady budou používat příkaz podman. Pokud vaše distribuce Podman nepodporuje, nahraďte jej příkazem sudo docker.

Podman: nastavení /etc/subuid a /etc/subgid

Jak jsme vysvětlovali výše, Podman potřebuje určitý rozsah volných ID uživatelů a skupin, aby do nich mohl namapovat UID a GID z kontejneru.

Superuživatel může bloky UIDů/GIDů přidělovat obyčejným uživatelům, kteří je pak mohou takto využívat. Říká se tomu sub-UID/sub-GID a jejich nastavení je zaznamenáno v souborech /etc/subuid a /etc/subgid.

Nejdříve si, prosím, zkontrolujte, zda-li váš /etc/subuid neobsahuje něco jako intro:100000:65536. Pokud ano, máte už vše připravené a můžete zbytek této sekce přeskočit.

Jinak se ujistěte, že tento soubor existuje, a vytvořte nové přiřazení pomocí usermod:

sudo touch /etc/subuid /etc/subgid
sudo usermod --add-subuids 100000-165536 --add-subgids 100000-165536 YOUR_LOGIN

Systémová (balíčková) aktualizace může občas Podman z různých důvodů rozbít. Pokud se vám to stane, zkuste vždy nejdříve spustit podman system migrate, který obvykle vyřeší většinu chyb spojených s přechodem na novější verzi.

Docker: spuštění služby

U Dockeru je potřeba se ujistit, že běží dockerd. Obvykle by měl stačit následující příkaz:

sudo package-manager-of-your-distribution install docker
sudo systemctl enable docker
sudo systemctl start docker

Základní test funkčnosti

Spusťte podman info, čímž získáte základní informace o systému. Pravděpodobně uvidíte něco jako:

host:
  arch: amd64
  ...
  cgroupManager: systemd
  cgroupVersion: v2
  conmon:
    ...
  ...
  idMappings:
    gidmap:
    - container_id: 0
      host_id: 1000
      size: 1
    - container_id: 1
      host_id: 100000
      size: 65536
    uidmap:
    - container_id: 0
      host_id: 1000
      size: 1
    - container_id: 1
      host_id: 100000
      size: 65536
  ...
  os: linux
...
store:
  graphRoot: $HOME/.local/share/containers/storage
  ...
  runRoot: /run/user/1000/containers
  volumePath: $HOME/.local/share/containers/storage/volumes
version:
  APIVersion: 3.0.0
  ...

Až budete ladit problémy s Podmanem, vždy vložte tuto informaci (bez dalších úprav) do popisu Issue (pochopitelně, vkládejte text do ```, nikoliv jako screenshot!).

Abyste ověřili, že můžete kontejnery spouštět, zkuste následující příkaz:

podman run --rm docker.io/library/alpine:latest cat /etc/os-release

Pokud uvidíte něco jako následující výpis, vše je připraveno. Jinak klidně otevřte Issue na Fóru a pokusíme se to nějak vyřešit (nezapomeňte říct, kterou distribuci používáte).

Trying to pull docker.io/library/alpine:latest...
Getting image source signatures
Copying blob 4abcf2066143 done   |
Copying config 05455a0888 done   |
Writing manifest to image destination
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.19.1
PRETTY_NAME="Alpine Linux v3.19"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"

První polovina výstupu se týká stažení obrazu. Teprve druhá polovina odpovídá výstupu příkazu. Neváhejte a spusťte výše uvedený příkaz ještě jednou (protože obraz je již stažen), abyste získali následující výstup:

NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.19.1
PRETTY_NAME="Alpine Linux v3.19"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"

Podman je částečně k dispozici i na počítačích v IMPAKTu a jeho instalace (i když s určitými omezeními) by měla být pro naše účely dostatečná.

Je však mnohem pohodlnější používat vlastní počítač.

Pokud spouštíte podman na linux.ms.mff.cuni.cz, vždy odstraňte nepoužívané obrazy. Zatímco systém má dostatek místa pro experimentování, obrazy mohou snadno zaplnit celý disk. Až je nebudete potřebovat, použijte k jejich odstranění příkazy podman images a podman rmi IMAGE_ID (další podrobnosti viz níže).

Příprava na cvičení

Před zahájením dalších pokusů s Podmanem se ujistěte, že máte aktuální kopii repozitáře examples.

Budeme používat podadresář 13/.

Pokud příklady spouštíte na počítačích v IMPAKTu nebo v Rotundě, naklonujte repozitář do /tmp, protože -v by nefungovalo se soubory na svazku souborového systému AFS.

Spuštění prvního kontejneru

První spuštění bude trochu komplexnější, abyste si mohli udělat představu o tom, co je možné. Podrobnosti si vysvětlíme v následujících kapitolách.

Předpokládáme, že se nacházíte v adresáři 13 v repozitáři examples. Následující příkaz spustí webový server Nginx.

podman run --rm --publish 8080:80/tcp -v ./web:/usr/share/nginx/html:ro docker.io/library/nginx:1.27

Zobrazí se podobný výstup jako v následujícím případě.

Trying to pull docker.io/library/nginx:1.27...
Getting image source signatures
Copying blob 10fe6d2248e3 done   |
Copying blob 3dce86e3b082 done   |
Copying blob 75b642592991 done   |
Copying blob 3b6e18ae4ce6 done   |
Copying blob 8a628cdd7ccc done   |
Copying blob 553c8756fd66 done   |
Copying blob e81a6b82cf64 done   |
Copying config 4cad75abc8 done   |
Writing manifest to image destination
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2025/04/09 11:26:03 [notice] 1#1: using the "epoll" event method
2025/04/09 11:26:03 [notice] 1#1: nginx/1.27.4
2025/04/09 11:26:03 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
2025/04/09 11:26:03 [notice] 1#1: OS: Linux 6.12.1-arch1-1
2025/04/09 11:26:03 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 524288:524288
2025/04/09 11:26:03 [notice] 1#1: start worker processes
2025/04/09 11:26:03 [notice] 1#1: start worker process 24
2025/04/09 11:26:03 [notice] 1#1: start worker process 25
2025/04/09 11:26:03 [notice] 1#1: start worker process 26
2025/04/09 11:26:03 [notice] 1#1: start worker process 27

Otevřete ve vašem prohlížeči http://localhost:8080/. Měla by se vám v něm zobrazit stránka NSWI177 Test Page.

Pokud se místo toho zobrazí 403 Forbidden, přidejte na konec argumentu volby -v znaky ,Z. Příkaz by tedy obsahoval -v ./web:/usr/share/nginx/html:ro,Z. To je potřeba (a obecně je to dobrý postup), pokud pracujete na počítači s povoleným SELinuxem v režimu vynucování (výchozí instalace Fedory, ale ne na USB discích od nás).

Při spouštění na linux.ms.mff.cuni.cz je třeba zadat jedinečné číslo portu (na daném portu může naslouchat pouze jedna aplikace).

Prakticky libovolné číslo je v pořádku, pokud je větší než 1024 a nekoliduje s ničím jiným.

Pokud si pamatujete forwardování portů pomocí SSH (bavili jsme se o něm na minulém cvičení), můžete ho nastavit tak, abyste výsledek viděli ve svém (grafickém) prohlížeči. Pro základní vyzkoušení ale stačí použít pouhý curl.

Podman ukončete stiskem Ctrl-C.

Všimněte si, že běžící webový server Nginx vypisoval svůj log – tj. seznam zobrazených stránek – na stdout.

Nyní otevřete v prohlížeči stránku web/index.html. Opět se zobrazí NSWI177 Test Page, ale adresa URL bude ukazovat na váš místní souborový systém (tj. file:///home/.../examples/13/web/index.html).

Výše uvedený příklad ilustruje tři důležité funkce, které jsou u kontejnerů k dispozici:

  • Webový server v kontejneru není třeba konfigurovat ani instalovat v rámci celého systému.
  • Kontejner může naslouchat na portech hostitelského systému a předávat síťovou komunikaci dovnitř kontejneru.
  • Kontejner může přistupovat k souborům hostitele a používat je.

Všechny tyto funkce jsou velmi dobré pro vývoj, testování i distribuci softwaru.

Stahování a kontrola obrazů

Při spuštění kontejneru je nejprve třeba získat jeho obraz. Ačkoli Podman umí stáhnout obraz jako součást podpříkazu run, někdy je užitečné získat jej v samostatném kroku.

Příkaz podman images vypíše seznam obrazů, které se nacházejí ve vašem systému. Výstup může vypadat takto.

REPOSITORY                        TAG                  IMAGE ID      CREATED        SIZE
docker.io/library/alpine          latest               9ed4aefc74f6  2 weeks ago    7.34 MB
docker.io/library/nginx           1.20.0               7ab27dbbfbdf  6 days ago     137 MB
docker.io/library/fedora          34                   8d788d646766  2 weeks ago    187 MB
...

Sloupec repository odkazuje na on-line repozitář, ze kterého jsme obraz získali. Sloupec tag je v podstatě verze. Sloupec image id je jedinečná identifikace obrazu, obvykle se odvozuje z kryptografického hashe jeho obsahu. Zbývající sloupce jsou samovysvětlující.

Když spustíte podman pull IMAGE:TAG, Podman stáhne obraz, aniž by spustil kontejner. Pokud jako značku (TAG) použijete latest, bude stažena nejnovější dostupná verze.

Stáhněte docker.io/library/python:3-alpine a zkontrolujte, zda se poté objevil v podman images.

Kratší názvy obrazů

Pokud do souboru /etc/containers/registries.conf.d/unqualified.conf vložíte následující obsah, nebudete muset před každý název obrazu zadávat docker.io/. Říká se tomu unqualified search (nekvalifikované vyhledávání) a pro každý název obrazu se vyzkouší jako první.

unqualified-search-registries = ["docker.io"]

Různé společnosti mohou mít svá vlastní úložiště. Pokud si přejete v případech, když není uveden plně kvalifikovaný název obrazu, vyzkoušet více různých úložišť , můžete jich zde nastavit několik.

Repozitář obrazů

Pokud vás zajímá, odkud obrazy pocházejí, podívejte se na https://hub.docker.com/. Každý tam může nahrát své obrazy, které pak mohou ostatní používat.

Podobně jako v případě Python package index, i zde můžete narazit na škodlivé obrazy. Kontejnery alespoň běží izolovaně, takže šance na špatné chování jsou trochu omezené (ve srovnání s pip install, který spouštíte v kontextu běžného uživatele).

Obrazy ze skupiny library jsou oficiální obrazy schválené samotným nástrojem Docker, a proto jsou relativně důvěryhodné.

Spouštění kontejnerů

Po stažení obrazu z něj můžeme vytvořit kontejner.

Začneme obrazem Alpine, protože je velmi malý, a tudíž velmi rychlý.

podman run --interactive --tty alpine:latest /bin/sh

Pokud vše proběhlo v pořádku, měli byste vidět interaktivní prompt / # a při kontrole /etc/os-release byste měli vidět následující text (čísla verzí se mohou lišit):

NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.19.1
PRETTY_NAME="Alpine Linux v3.19"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"

Podpříkaz run spustí kontejner ze zadaného obrazu. Pomocí --interactive a --tty (které se často spojují do jediného -it) určíme, že chceme ke kontejneru připojit terminál, abychom jej mohli používat interaktivně. Poslední částí příkazu je program, který se má spustit.

Uvnitř kontejneru můžeme provádět libovolné příkazy. Jsme bezpečně uzavřeni a změny neovlivní hostitelský systém.

Nainstalujte curl a zkontrolujte, zda máte funkční přístup k síti. Řešení.

Otevřete druhý terminál, abychom mohli zkontrolovat, jak kontejner vypadá zvenčí.

Uvnitř kontejneru spusťte sleep 111 a v druhém terminálu (který je spuštěn v hostiteli) spusťte ps -ef --forest. Zobrazí se následující řádky:

student    1477313       1  0 16:29 ?        00:00:00 /usr/bin/conmon ...
student    1477316 1477313  0 16:29 pts/0    00:00:00  \_ /bin/sh
student    1477370 1477316  0 16:33 pts/0    00:00:00      \_ sleep 111

To potvrzuje, že procesy běžící uvnitř kontejneru jsou viditelné zvenčí.

Spusťte ps -ef uvnitř kontejneru (nebo se podívejte do /proc). Co uvidíte? Je tam něco překvapivého? Řešení.

Spusťte také podman ps. Ten vypíše seznam spuštěných kontejnerů.

CONTAINER ID  IMAGE                            COMMAND  CREATED        STATUS            PORTS   NAMES
643b5e7cea06  docker.io/library/alpine:latest  /bin/sh  4 minutes ago  Up 4 minutes ago          practical_bohr

ID kontejneru je opět jedinečná identifikace, ostatní sloupce jsou samovysvětlující. Všimněte si, že vzhledem k tomu, že jsme nezadali název, Podman kontejneru přiřadil náhodný název.

Pokud relaci ukončíte uvnitř kontejneru (exit nebo Ctrl-D), vrátíte se do hostitelského terminálu.

Znovu spusťte podman ps. Výstup je prázdný: kontejner neběží. Pokud přidáte --all, uvidíte, že se STATUS změnil.

Exited (130) 1 second ago

Všimněte si, že kdybychom znovu spustili podman run ..., spustili bychom nový kontejner. Vyzkoušejte si to nyní.

Životní cyklus kontejneru popíšeme později, pokud chcete kontejner odstranit nyní, spusťte podman rm NAME. Jako NAME použijte náhodně přidělený název nebo CONTAINER ID.

Jednorázová spuštění

Příkazu podman run můžete předat libovolný příkaz, který se má provést. Pokud víte, že kontejner ihned poté odstraníte, můžete přidat --rm, abyste Podmanu řekli, že má kontejner po dokončení příkazu automaticky odstranit.

podman run --rm alpine:latest cat /etc/os-release

Pokud chcete předat složitější příkaz, je lepší použít sh -c. Změňte výše uvedený příkaz tak, že nejprve provedeme cd do etc a poté zavoláme cat os-release. Proč by nefungoval příkaz podman run --rm alpine:latest cd /etc && cat os-release? Řešení.

Správa životního cyklu kontejneru

Kontejnery jsou vlastně dost podobné službám, o kterých jsme hovořili ve Cvičení 09.

Spuštění kontejneru

Po ukončení interaktivní relace byl kontejner ukončen. Pro jeho opětovné spuštění můžeme zavolat podman start CONTAINER.

Každý kontejner má tzv. vstupní bod, který se spustí při jeho spuštění. U kontejneru typu služba (např. s webovým serverem) by se služba spouštěla znovu.

V našem příkladu s Alpine je vstupním bodem /bin/sh (shell), takže se nic zajímavého nestane.

Zkontrolujte, že je kontejner spuštěn, pomocí podman ps.

Připojení ke spuštěnému kontejneru

Když je kontejner spuštěn, můžeme se k němu připojit. podman attach v podstatě připojí stdout vstupního bodu k vašemu terminálu. S naším kontejnerem Alpine můžeme opět spustit příkaz uvnitř kontejneru.

Můžeme také zavolat podman exec -it CONTAINER CMD, který se připojí ke spuštěnému kontejneru v novém terminálu (jako nová karta). V našem případě bude fungovat spuštění následujícího příkazu (použijte název vašeho kontejneru).

podman exec -it practical_bohr /bin/sh

Spusťte znovu ps -ef uvnitř kontejneru. Které procesy vidíte? Řešení.

Ukončení execnutého shellu nás vrátí zpět k hostiteli. Ukončení attachnutého shellu ukončí celý kontejner.

Kontejnery na pozadí (s názvy)

U kontejnerů typu služba (např. nginx, který poskytuje webový server) je často chceme spouštět v režimu démona – na pozadí.

To je možné pomocí volby --detach příkazu run.

Do příkazu přidáme také jméno webserver, abychom na kontejner mohli snadno odkazovat.

podman run --detach --name webserver --publish 8080:80/tcp -v ./web:/usr/share/nginx/html:ro  nginx:1.20.0

Volby -v a --publish si vysvětlíme později.

Tento příkaz spustí kontejner a skončí. Webový server běží na pozadí. Zkontrolujte, zda máte opět přístup k http://localhost:8080/ v prohlížeči.

Takový kontejner můžete zastavit příkazem podman stop webserver. Je to něco podobného jako systemctl stop .... Není to náhoda.

Zkontrolujte, že po zastavení webového serveru http://localhost:8080/ již nefunguje.

Opětovné spuštění kontejneru je možné pomocí příkazu podman start webserver.

start, stop a standardní výstup

Všimněte si, že jak start, tak stop vypisují na standardní výstup jméno kontejneru, který byl spuštěn (zastaven). To je užitečné při provádění ve skriptech; při interaktivním použití můžeme tento výstup jednoduše ignorovat.

Úklidové akce

Jakmile s kontejnerem skončíme, můžeme jej odstranit (nejprve jej však musíme zastavit).

Spuštěním následujícího příkazu by byl kontejner webserver zcela odstraněn.

podman rm webserver

Pomocí podpříkazu rmi můžete také odstranit stažené obrazy.

Například pro odstranění nginx:1.20.0 můžete spustit následující příkaz.

podman rmi nginx:1.20.0

Všimněte si, že Podman odmítne obraz odstranit, pokud jej používá existující kontejner. Připomeňme, že obrazy jsou naskládané na sebe, a proto Podman nemůže odstranit spodní vrstvy.

Omezení izolace

Kontejner je ve výchozím nastavení izolovaný svět. Pokud k němu chcete přistupovat zvenčí, musíte se do něj execnout (pro práci v terminálu) nebo zveřejnit jeho služby navenek.

Přesměrování portů (tzv. publikování portů)

U kontejnerů serverového typu (např. Nginx, který jsme použili výše) to znamená vystavení některých portů hostitelskému počítači. To se provádí pomocí argumentu --publish, ve kterém určíte, který port na hostiteli (např. 8080) má být přesměrován do kontejneru: na který port a který protokol (např. 80 a tcp).

Argument --publish 8080:80/tcp tedy znamená, že očekáváme, že kontejner sám nabízí službu na svém portu 80 a chceme tento port (kontejneru) zpřístupnit jako 8080.

To je velmi podobné jako SSH port forwarding, který jsme si ukazovali na minulém cvičení.

Kontejner nginx můžeme spustit i bez --publish, ale to neznamená, že to má velký smysl. Proč? Řešení.

Připojování svazků

Další možností, jak narušit izolaci kontejneru, je připojit do kontejneru určitý adresář. Existuje několik možností, jak to provést. My si ukážeme parametr --volume (nebo -v).

Instalace Podmanu na počítačích v IMPAKTu a v Rotundě vyžaduje, aby připojovaný adresář byl vně souborového systému AFS. Dobrá volba je použít /tmp.

Parametr -v přijímá tři argumenty (opět oddělené dvojtečkou): zdrojový adresář na hostiteli, mapování uvnitř kontejneru a volby (options).

Náš příklad ./web:/usr/share/nginx/html:ro tedy určuje, že místní (hostitelský) adresář web bude viditelný pod /usr/share/nginx/html uvnitř kontejneru v režimu pouze pro čtení. Je to velmi podobné běžnému připojování (mountování), které již znáte.

Pokud zadáte rw místo ro, můžete uvnitř kontejneru upravovat hostitelské soubory.

Připojení svazku je užitečné pro jakýkoli kontejner typu služba. Typickým příkladem je databázový server. Spustíte kontejner a přidělíte mu připojený svazek. Do tohoto svazku (adresáře) bude ukládat vlastní databázi (datové soubory). Po ukončení kontejneru jsou tedy vaše data ve skutečnosti trvalá, protože byla uložena mimo kontejner.

To má obrovskou výhodu při testování aktualizací služeb. Zastavíte kontejner, vytvoříte zálohu datového adresáře a spustíte nový kontejner (s novější verzí) nad stejným datovým adresářem. Pokud vše funguje správně, můžete pokračovat. V opačném případě můžete nový kontejner zastavit, obnovit data ze zálohy a vrátit se ke staré verzi.

Velmi jednoduché a účinné.

Zkontrolujte si vaše porozumění

Vyberte všechna pravdivá tvrzení o kontejnerech. You need to have enabled JavaScript for the quiz to work.

Cvičení

Nainstalujte příkaz fscat pro celý systém uvnitř kontejneru.

Doporučujeme použít python:3.13-alpine.

Všimněte si, že v tomto případě nemusíte nastavovat žádné virtuální prostředí: celý počítač (kontejner) je váš. Můžete v něm instalovat věci na úrovní celého systému.

Nápověda.

Řešení.

Proč máme všechny ty systemctl, dnf, podman, pip, …

V tuto chvíli by mohlo dojít k určitým nejasnostem, proč existuje tolik konceptů, které se v podstatě zabývají stejnou problematikou.

  • K instalaci softwaru máme správce balíčků (dnf install). Některý software však můžeme instalovat také prostřednictvím správců specifických pro daný jazyk (pip install).
  • Webový server lze spustit pomocí systemctl start nebo vytvořením kontejneru.
  • Máme virtuální prostředí pro vývoj softwaru, ale také kontejnery a plnohodnotné virtuální stroje.

Pravdou je, že některé koncepty a nástroje jsou důsledkem historického vývoje, zatímco jiné řeší některé problémy z různých úhlů.

Klidně se k tomuto textu vraťte později, např. až trochu vstřebáte téma kontejnerů.

Pokusíme se stručně vysvětlit, proč má smysl je všechny znát. Pokud se vám zdá, že je naše zobecnění příliš široké, připojte prosím ke každé větě přívlastek většinou, obvykle nebo jiné podobné příslovce :-).

Především je důležité rozlišovat potřeby koncového uživatele (což může být i správce webového serveru) od potřeb vývojáře.

  • Koncový uživatel obvykle požaduje snadnou instalaci a spokojí se s jednou verzí. Očekává, že aktualizace bude bezproblémový proces.

  • Vývojáři mohou mít nainstalováno více verzí stejného softwaru a mohou dokonce používat dvě různé verze současně. Aktualizace (např. ve smyslu aktualizace potřebných knihoven) je křehký proces, při kterém je třeba otestovat spoustu věcí.

  • A můžeme k tomu přidat i testery, kteří musí zajistit, aby software fungoval na široké škále hardwarových a softwarových platforem.

Všechny tyto skupiny ve skutečnosti používají stejný software (stejný kus kódu), ale jejich požadavky se liší.

Správci balíčků tak dodávají do uživatelova počítače dobře otestovanou verzi programu, která je připravena ke spuštění. Použití správce balíčků znamená, že existuje centrální autorita, která zabraňuje instalaci konfliktních souborů a zjednodušuje hromadné aktualizace.

Vývojáři nechtějí svůj program instalovat pro celý systém, ale přesto jej chtějí spouštět, jako by byl pro celý systém nainstalován (protože tak bude program nakonec používán). Virtuální prostředí poskytuje čisté prostředí, které je dostatečně dobré pro emulaci čisté instalace do stejného systému, jaký používá vývojář. Je také velmi nenáročné, protože soubory zůstávají ve stejném souborovém systému, a proto je konfigurace ostatních nástrojů – například IDE – jednoduchá.

Tato izolace (na úrovni virtuálního prostředí) je však poměrně slabá, protože neizoluje od ostatních nainstalovaných aplikací (připomeňme, že $PATH se ve virtuálním prostředí rozšiřuje, nikoli nahrazuje), ani od síťové konfigurace. Kontejnery poskytují vyšší úroveň izolace, ale za vyšší cenu. Přístup k souborům je možný, ale vyžaduje další nastavení, kontejner obvykle neobsahuje žádný další software, který by zjednodušil rutinní úlohy, atd.

Na druhou stranu kontejner poskytuje čistší prostředí pro testování, protože uživatel může mít plnou kontrolu nad tím, co se instaluje.

Kontejnery i virtuální prostředí mohou spokojeně koexistovat, a to i ve více kopiích, což opět zjednodušuje testování a vývoj.

Uvedené nástroje plní ve vývojovém cyklu softwaru různé role. Teoreticky můžeme kontejnery použít prakticky na všechno, protože jejich izolace (alespoň částečně) ruší potřebu správců balíčků i virtuálních prostředí, ale hlavní roli zde hraje snadnost použití.

Vždy zvolte pro danou práci správný nástroj. Potřeby správců, uživatelů, vývojářů a testerů se liší. A právě proto existuje tolik nástrojů, které zdánlivě řeší stejnou úlohu. Všechny mají své využití.

GitLab CI

Pokud jste ještě nikdy neslyšeli pojem kontinuální integrace (Continuous Integration — CI), pak je to v kostce následující.

O kontinuální integraci

Abyste zajistili, že software, který vytváříte, je ve zdravém stavu, měli byste na něm často provádět testy a co nejdříve opravovat nefunkční věci (protože náklady na opravu chyb dramaticky rostou s každým dnem, kdy nejsou odhaleny).

To znamená, že vývojář musí při každé revizi spustit testy. Protože je obtížné to vynutit, je lepší to dělat automaticky. CI ve své nejjednodušší podobě označuje stav, kdy se automatické testy (např. na bázi BATS nebo Pythonu) provádějí automaticky po každém odeslání (push), např. po odeslání změn v libovolné větvi do GitLabu.

CI však dokáže mnohem víc: pokud testy projdou, posloupnost příkazů (pipeline) může software zabalit a publikovat jako artefakt (např. jako instalační program). Nebo může spustit úlohu pro nasazení do produkčního prostředí a zpřístupnit jej zákazníkům. A tak dále.

Toto se často označuje jako CI/CD, což znamená kontinuální integrace a kontinuální dodávka (nebo nasazení).

V tomto předmětu zůstaneme u nejužšího záběru a zaměříme se jen na to, jak spouště automatizované testy (ale budeme tomu hrdě říkat CI).

Nastavení CI na GitLabu

Důležité je vědět, že GitLab CI může běžet nad Podmanovými kontejnery. Takže pro nastavení GitLabové pipeline si vyberete obraz pro Podman a příkazy, které je potřeba v takovém kontejneru spustit. GitLab pak vytvoří daný kontejner a spustí v něm vaše příkazy.

Podle výsledku celého skriptu (tj. jeho exit kódu) pak označí buď pipeline jako procházející nebo selhanou.

V tomto kurzu se zaměříme na nejjednodušší konfiguraci, kdy chceme provádět testy po každé revizi. GitLab lze nakonfigurovat i pro složitější úlohy, kdy lze software dokonce nasadit na virtuální cloudový stroj, ale to je bohužel mimo náš rozsah.

Pokud vás toto téma zajímá, GitLab má rozsáhlou dokumentaci. Dokumentace je často hustě zaplněna množstvím informací, ale je skvělým zdrojem znalostí nejen o GitLabu, ale o mnoha principech softwarového inženýrství obecně.

.gitlab-ci.yml

Konfigurace GitLab CI je uložena v souboru .gitlab-ci.yml, který musí být uložen v kořenovém adresáři projektu.

Očekáváme, že máte vlastní fork webového repozitáře a že jste rozšířili původní soubor Makefile (více ve cvičení 10 o make).

Pokud ještě vlastní fork nemáte, teď si ho vytvořte. A rovnou si připojte (merge) naší větev lab/13, abyste měli potřebnou verzi.

Nyní nastavíme úlohu CI, která sestaví pouze web. Bude to ta nejzákladnější CI, jakou si lze představit. Ale alespoň zajistí, že web bude vždy v sestavitelném stavu.

Pro urychlení však z našeho Makefile odstraníme generování PDF, protože instalace OpenOffice vyžaduje stažení 400 MB, což je pro každou revizi poměrně hodně.

Umístěte následující do .gitlab-ci.yml v kořenovém adresáři vašeho projektu.

image: fedora:41

build:
  script:
    - dnf install -y make pandoc python3
    - make

Určuje úlohu pipeline build (tento název se zobrazí ve webovém uživatelském rozhraní), která se spustí pomocí obrazu fedora a provede dva příkazy. První nainstaluje závislost a druhý spustí make.

Nepoužíváme Alpine, protože instalace Pandocu do Alpine je trochu složitější. Vyžaduje, abychom ji buď nainstalovali prostřednictvím nástrojů pro správu balíčků programovacího jazyka Haskell, nebo abychom si stáhli předpřipravenou statickou binárku.

Přidejte soubor .gitlab-ci.yml do svého repozitáře Git (tj. do svého forku), odevzdejte jej (commit) a odešlete (push).

Pokud otevřete stránku projektu na webu GitLabu, měla by se vedle ní zobrazit ikona pipeline, která by měla nakonec zezelenat.

Log by pravděpodobně vypadal takto.

Running with gitlab-runner 17.6.1 (6826a62f)
  on gitlab.mff docker Mtt-jvRo, system ID: s_7f0691b32461
Preparing the "docker" executor 00:03
Using Docker executor with image fedora:41 ...
Pulling docker image fedora:41 ...
Using docker image sha256:9645f4e2280d9175edc72cd6195576bf9fa396cbde7d1c120756768a5e7399e0 for fedora:41 with digest fedora@sha256:f84a7b765ce09163d11de44452a4b56c1b2f5571b6f640b3b973c6afc4e63212 ...
Preparing environment 00:01
Running on runner-mtt-jvro-project-19856-concurrent-0 via gitlab-runner...
Getting source from Git repository 00:00
Fetching changes with git depth set to 20...
Reinitialized existing Git repository in /builds/teaching/nswi177/infra/experiments/web/.git/
Checking out accfb9f7 as detached HEAD (ref is master)...
Removing out/group-a.html
Removing out/group-b.html
Removing out/index.html
Removing out/main.css
Removing out/news.html
Removing out/rules.html
Removing out/score.html
Skipping Git submodules setup
Executing "step_script" stage of the job script 00:12
Using docker image sha256:9645f4e2280d9175edc72cd6195576bf9fa396cbde7d1c120756768a5e7399e0 for fedora:41 with digest fedora@sha256:f84a7b765ce09163d11de44452a4b56c1b2f5571b6f640b3b973c6afc4e63212 ...
$ dnf install -y make pandoc python3
Updating and loading repositories:
 Fedora 41 openh264 (From Cisco) - x86_ 100% |  12.9 KiB/s |   6.0 KiB |  00m00s
 Fedora 41 - x86_64                     100% |  25.2 MiB/s |  35.4 MiB |  00m01s
 Fedora 41 - x86_64 - Updates           100% |  17.2 MiB/s |  12.2 MiB |  00m01s
Repositories loaded.
Package                     Arch   Version          Repository      Size
Installing:
 make                       x86_64 1:4.4.1-8.fc41   fedora       1.8 MiB
 pandoc                     x86_64 3.1.11.1-32.fc41 fedora     185.0 MiB
 python3                    x86_64 3.13.2-1.fc41    updates     31.8 KiB
Installing dependencies:
 expat                      x86_64 2.7.1-1.fc41     updates    298.3 KiB
 libb2                      x86_64 0.98.1-12.fc41   fedora      42.2 KiB
 mpdecimal                  x86_64 2.5.1-16.fc41    fedora     204.9 KiB
 pandoc-common              noarch 3.1.11.1-31.fc41 fedora       1.9 MiB
 python-pip-wheel           noarch 24.2-1.fc41      fedora       1.2 MiB
 python3-libs               x86_64 3.13.2-1.fc41    updates     40.4 MiB
Installing weak dependencies:
 python-unversioned-command noarch 3.13.2-1.fc41    updates     23.0   B
Transaction Summary:
 Installing:        10 packages
Total size of inbound packages is 38 MiB. Need to download 38 MiB.
After this operation, 231 MiB extra will be used (install 231 MiB, remove 0 B).
[ 1/10] pandoc-common-0:3.1.11.1-31.fc4 100% |  16.4 MiB/s | 537.1 KiB |  00m00s
[ 2/10] make-1:4.4.1-8.fc41.x86_64      100% |  15.9 MiB/s | 586.1 KiB |  00m00s
[ 3/10] python3-0:3.13.2-1.fc41.x86_64  100% |   4.0 MiB/s |  28.5 KiB |  00m00s
[ 4/10] libb2-0:0.98.1-12.fc41.x86_64   100% |   4.2 MiB/s |  25.7 KiB |  00m00s
[ 5/10] mpdecimal-0:2.5.1-16.fc41.x86_6 100% |  10.9 MiB/s |  89.0 KiB |  00m00s
[ 6/10] python-pip-wheel-0:24.2-1.fc41. 100% |  54.6 MiB/s |   1.2 MiB |  00m00s
[ 7/10] expat-0:2.7.1-1.fc41.x86_64     100% |  16.2 MiB/s | 116.0 KiB |  00m00s
[ 8/10] python-unversioned-command-0:3. 100% |   1.9 MiB/s |  11.6 KiB |  00m00s
[ 9/10] python3-libs-0:3.13.2-1.fc41.x8 100% | 103.6 MiB/s |   9.1 MiB |  00m00s
[10/10] pandoc-0:3.1.11.1-32.fc41.x86_6 100% | 132.0 MiB/s |  26.0 MiB |  00m00s
--------------------------------------------------------------------------------
[10/10] Total                           100% | 120.8 MiB/s |  37.7 MiB |  00m00s
Running transaction
[ 1/12] Verify package files            100% | 104.0   B/s |  10.0   B |  00m00s
[ 2/12] Prepare transaction             100% | 357.0   B/s |  10.0   B |  00m00s
[ 3/12] Installing expat-0:2.7.1-1.fc41 100% |  29.3 MiB/s | 300.4 KiB |  00m00s
[ 4/12] Installing python-pip-wheel-0:2 100% | 177.4 MiB/s |   1.2 MiB |  00m00s
[ 5/12] Installing mpdecimal-0:2.5.1-16 100% |  40.2 MiB/s | 206.0 KiB |  00m00s
[ 6/12] Installing libb2-0:0.98.1-12.fc 100% |   5.3 MiB/s |  43.3 KiB |  00m00s
[ 7/12] Installing python3-libs-0:3.13. 100% | 147.2 MiB/s |  40.8 MiB |  00m00s
[ 8/12] Installing python3-0:3.13.2-1.f 100% |   6.5 MiB/s |  33.5 KiB |  00m00s
[ 9/12] Installing pandoc-common-0:3.1. 100% |  75.8 MiB/s |   1.9 MiB |  00m00s
[10/12] Installing pandoc-0:3.1.11.1-32 100% | 466.1 MiB/s | 185.0 MiB |  00m00s
[11/12] Installing python-unversioned-c 100% |  11.8 KiB/s | 424.0   B |  00m00s
[12/12] Installing make-1:4.4.1-8.fc41. 100% |  16.7 MiB/s |   1.8 MiB |  00m00s
Complete!
$ make
pandoc --template template.html -o out/index.html src/index.md
pandoc --template template.html -o out/rules.html src/rules.md
src/news.bin >out/news.html
./table.py <src/score.csv | pandoc --template template.html --metadata title="score" - >out/score.html
./table.py <src/group-a.csv | pandoc --template template.html --metadata title="group-a" - >out/group-a.html
./table.py <src/group-b.csv | pandoc --template template.html --metadata title="group-b" - >out/group-b.html
cp main.css out/
Cleaning up project directory and file based variables 00:00
Job succeeded

Všimněte si, že GitLab nejprve připojí úložiště Git do kontejneru a poté provede příkazy uvnitř klonu. Příkazy se provádějí pomocí set -e: první neúspěšný příkaz ukončí celou pipeline.

Pokuste se emulovat výše uvedený běh lokálně. Nápověda. Řešení.

Další drobnosti

Všimněte si, jak je použití pipeline GitLab snadné. Najdete správný obraz (image), zadáte skript a GitLab se postará o zbytek.

Od této chvíle by měl mít každý Váš projekt vytvořený na GitLabu pipeline, která spustí testy (včetně Shellcheck, Pylint atd.). Nastavte ji TEĎ pro své úkoly v jiných předmětech. Nastavte si ji pro svůj ročníkový projekt (NPRG045) v příštím roce. Využijte možnosti nechat si pravidelně testovat svůj kód. Z dlouhodobého hlediska vám to ušetří čas.

Pokud si nejste jisti, který obraz zvolit, oficiální obrazy jsou dobrým začátkem. Skript může mít několik kroků, ve kterých před spuštěním programu nainstalujete chybějící závislosti.

Připomeňme, že nemusíte vytvářet virtuální prostředí: celý počítač je váš (a bude stejně odstraněn), takže můžete instalovat věci globálně.

Může být definováno více úloh, které jsou spouštěny paralelně (ve skutečnosti mezi nimi mohou existovat poměrně složité závislosti, ale v následujícím příkladu jsou všechny úlohy spuštěny najednou).

Následující příklad ukazuje fragment souboru .gitlab-ci.yml, který testuje projekt na více verzích jazyka Python.

# Default image if no other is specified
image: python:3.10

stages:
  - test

# Commands executed before each "script" section (for any job)
before_script:
    # To have a quick check that the version is correct
    - python3 --version
    # Install the project
    - python3 -m pip install ...

# Run unit tests under different versions
unittests3.7:
  stage: test
  image: "python:3.7"
  script:
    - pytest --log-level debug tests/

unittests3.8:
  stage: test
  image: "python:3.8"
  script:
    - pytest --log-level debug tests/

unittests3.9:
  stage: test
  image: "python:3.9"
  script:
    - pytest --log-level debug tests/

unittests3.10:
  stage: test
  image: "python:3.10"
  script:
    - pytest --log-level debug tests/

Úlohy k ověření vašich znalostí

Očekáváme, že následující úlohy vyřešíte ještě před příchodem na cvičení, takže se budeme moci o vašich řešeních na cvičení pobavit.

Nainstalujte následující balíček Pythonu do kontejneru (vzpomeňte si, že na instalování balíčku můžete přímo použít pip).

Připomeňte si, proč zde nemá smysl používat virtuální prostředí.

Po instalaci spusťte nově nainstalovaný program nswi177-lab13.

Pro instalaci doporučujeme použít obraz fedora:41 nebo Alpine. Možná ale budete muset nejdříve nainstalovat python3.

Řešení.

Spusťte webový server Apache na adresář 13/web. Použijte tento obraz httpd. Ověřte, že skutečně používáte webový server Apache.

Řešení.

Účelem této úlohy je ukázat, jak lze kontejnery snadno použít pro kontrolu toho, zda je váš projekt v rozumném stavu. I když používáte virtuální prostředí apod. je důležité ověřit, zda lze váš projekt nainstalovat do čistého prostředí.

Vaším úkolem je napsat do 13/test-in-alpine.txt příkazy, které naklonují fscat a spustí jeho testy.

Pak spusťte váš skript pomocí níže uvedeného příkazu a zkontrolujte, že byly testy spuštěny (testy jsou spuštěny pomocí pytest -v tests/).

podman run --rm alpine:3.19 /bin/sh -c "$( cat 13/test-in-alpine.txt )"

Ujistěte se prosím, že nepřesměrováváte výstup BATS testů a že spouštíte Pythononí testy s -v, abyste ve výstupu viděli následující (... je místo, kde se mohou objevit další zprávy).

1..3
ok 1 Works with a tarball
ok 2 Failure on bad filesystem path
ok 3 Failure on bad filename path
...
tests/test_fscat.py::test_cat_from_tar PASSED                            [ 25%]
tests/test_fscat.py::test_raises_on_invalid_filesystem_path PASSED       [ 50%]
tests/test_fscat.py::test_raises_on_invalid_filename_path PASSED         [ 75%]
tests/test_fscat.py::test_raises_when_filename_is_directory PASSED       [100%]

Váš skript musí používat set -e, aby byly detekovány chyby v testech (konec při prvním selhaném příkazu).

Pro sledování toho, co se děje, je zcela v pořádku použít set -x (doporučujeme použít tento přepínač jako první příkaz v souboru 13/test-in-alpine.txt).

Důrazně doporučujeme, abyste tuto úlohu nejprve vyřešili interaktivně a poté si pomocí příkazu history prohlédli, jaké příkazy jste spustili, a z nich sestavili výsledný skript.

Poznámka pod čarou: jakmile tento úkol dokončíte, všimněte si, jak kontejnery usnadňují testování vašeho projektu v různých verzích Linuxu: nahrazení apk za dnf a alpine za fedora vám umožní testovat projekt ve Fedoře prakticky bez další práce navíc.

Řešení.

Přidejte do GitLabu vlastní pipeline, která kontroluje, zda jako shebang nikdy nepoužíváte /usr/bin/python.

Nápověda.

Řešení.

Učební výstupy a kontrola po cvičení

Tato část podává zhuštěný souhrn základních konceptů a dovedností, které byste měli umět vysvětlit a/nebo použít po každém cvičení. Také obsahují absolutní minimum, které je potřebné pro pochopení navazujících cvičení (a dalších předmětů).

Znalosti konceptů

Znalost konceptů znamená, že rozumíte významu a kontextu daného tématu a jste schopni témata zasadit do většího rámce. Takže, jste schopni …

  • vysvětlit, co je to kontejner

  • porovnat kontejner s virtuálním strojem a procesem

  • vysvětlit, kde se hodí izolace, kterou nabízí kontejnery

  • vysvětlit životní cyklus kontejneru

  • vysvětlit, proč použití virtuálních prostředí (nebo jiných typů sandboxů) není uvnitř kontejneru obvykle potřeba

  • vysvětlit rozdíl mezi běžícím kontejnerem a obrazem kontejneru

  • vysvětlit principy continous integration

  • vysvětlit výhody používání continous integration

  • vysvětlit v širším smyslu, jak funguje GitLab CI

Praktické dovednosti

Praktické dovednosti se obvykle týkají použití daných programů pro vyřešení různých úloh. Takže, dokážete …

  • spustit v Podmanu interaktivní kontejner

  • spustit kontejner Podmanu se službou

  • zpřístupnit (expose) porty kontejneru

  • připojit svazek dovnitř kontejneru

  • vymazat nepoužívané kontejnery a obrazy

  • nastavit GitLab CI pro jednoduché projekty