A konténerek mára már iparági tényezővé váltak. Megtalálhatók mindenhol ahol gyorsan kell környezeteket építeni, vagy ahol a fejlesztések számára automatizált teszt rendszerekre van szükség, vagy ott ahol IT biztonsági megfontolásokból kell szeparálni az egyes szolgáltatásokat.

Bárki aki a konténerekkel kezd foglalkozni elsőre a Dockert fogja megtalálni. Azonban a Red Hatnak van egy másik megoldása ez a Podman. Hogy mi a különbség a Docker és a Podman közt? Több különbség is van, de ami nekem tetszik benne az az, hogy míg a Docker démonként fut és a konténereket szálakban futtatja addig a Podman a Systemd segítségével tudja futtatni a konténereket. Akár minden konténert külön szolgáltatásként.

Ebben a cikkben bemutatom a Podman használatát CentOS8/RHEL8 alatt. Bemutatom hogy kell konténert készíteni és azt ad-hoc módon vagy szervizként futtatni. Igyekszem bemutatni többféle megoldási lehetőséget, mindazonáltal nem térek ki minden lehetőségre. Ha ennél többet szeretnél, ott a Podman dokumentációja.

A bemutatóhoz CentOS8 szervert használok. Alapvetően egy szerveren fogok végig dolgozni, azonban a külső tesztekhez kell egy lehetőség, hogy kívülről is elérd a teszt gépet.hogy ez a a saját géped vagy egy másik virtuális gép, azt te döntöd el, lényeg, hogy egy hálózatban legyenek.

A Podman majdnem ugyanúgy működik mint a Docker. A parancsok gyakorlatilag kompatibilisek egymással, ezt mindjárt meg fogjátok látni. A leggyakoribb használati eset, hogy kész konténert töltesz le és azt futtatod. Számos helyen találsz konténereket előre elkészítve amelyeket már nem kell konfigurálni. A Red Hat szintén gyárt konténereket amit le lehet tölteni. A Red Hat ezeket karban is tartja. Időről időre készít belőlük új verziókat. Jó megoldás az előre elkészített konténerek használada, de én most nem ezt szeretném bemutatni. Ha mindazt amit alább megmutatok megcsinálod, a letöltés-futtatás már nem fog gondot okozni.

Hogy értsük mi is ez valójában. A konténert utólag már nem lehet módosítani. Gyakorlatilag a konténer addig létezik amíg futtatod. Ha leállítod, akkor visszaáll alaphelyzetbe. Kissé felemás példával élve olyan ez mintha virtuálgépen snapshotot készítenél és mindig a snapshottal indulna a gép. Azzal a különbséggel, hogy a konténer csak a kiinduló állapotot tárolja. Amit a konténer felépítésénél beleraktál, az úgy marad. Ha valamit még bele szeretnél rakni, akkor új konténert kell építsél. További különbsés a virtualizáció és a konténerek közt, hogy a konténerbe nem kell telepítsd a teljes operációs rendszert. Azonban a futtatáshoz szükséges környezetet és konfigurációt bele kell rakjad.

Engem elsősorban az érdekelt, hogy hogyan tudok egyedi konténereket létrehozni és azokat futtatni. Ezt fogom most bemutatni.

Előkészületek

Kiinduló állapotnak telepítettem egy CentOS8 szervert Minimal installal. Ezen fogom elkészíteni a konténereket, magyarán ez lesz a Host (container) gép. A teszt hálózat a lehető legegyszerűbb. A hálózatban DHCP-t használok, különleges DNS bejegyzés nincs. A feladatokban ahol szükséges IP címekkel hivatkozom a szerverre. A container gép IP címe: 192.168.1.187. Telepítés után teljesen felfrissítettem.

yum update -y

Aktuális verziószám a következő:

[root@container ~]# cat /etc/redhat-release 
CentOS Linux release 8.2.2004 (Core)

Telepítsük fel a konténerkezeléshez szükséges eszközöket! Meg is nézheted mik ezek:

yum module info container-tools

Az alábbi parancs feltelepíti mindazokat az eszközöket amire szükségünk van. Module installt használok. Ha nem tudod mi ez, akkor nézz utána, hogy mik azok a modulok yum alatt. Nagy vonalakban ez a RHEL8 újdonsága, amikor bizonyos összetartozó verziószámú komponenseket egyszerre "modulban" kezelünk. Ezzel azt lehet elérni, hogy a kipróbált verziók miatt stabilabb lesz a rendszerünk és a megjelenő új verziószámú frissítések csak akkor lépnek életbe, ha azt modul szinten kezeljük. Általában elmondható, hogy amire van modul, azt telepítsük abból.

yum module install container-tools -y

Konténer készítése

Eddig nem volt bonyolult. Akkor most készítsünk egyedi konténert. Ehhez a Buildah programot fogom használni. Készítsünk egy minimális méretű kiinduló image-t az alábbi paranccsal. A parancs létrehozza az úgynevezett working-containert ami a létrehozandó konténereink alapjául fog szolgál. Ebbe fogunk belerakni mindent amiből a konténert építjük. A konténer legyártása után nem szükséges ezt megtartsuk. Hiszen ha a parancsok megvannak, bármikor tudunk ilyet építeni.

buildah from scratch

Mountoljuk fel!

buildah mount working-container

A montolás során létrejön egy egyedi ID amire majd még többször hivatkozunk.

[root@container ~]# buildah mount working-container
/var/lib/containers/storage/overlay/24c86...ID...dcd1/merged

Ezen a ponton kell eldönteni, hogy mit építünk és mit tartalmazzon a konténerünk. Három programot fogok bele telepíteni. Bash: Kell ahhoz, hogy be tudjunk lépni. Coreutils: Ez az ami a rendszer alapját adja. Httpd: Web szerver.
Csak az lesz benne amit bele telepítesz. Például ha szükséged van később valami diagnosztikai programra, akkor azt is most kell beleraknod. Jó megoldás, ha a tanulás/tesztelés idejére beleteszed a yum-ot is, hogy tudjál a konténerbe futás közben telepíteni, hogy esetleg függőségeket könnyebben meghatározd, azonban a konténer újraindítása után a telepített komponensek és módosítások elvesznek. Azt se felejtsd el, hogy ha te tudsz telepíteni, akkor egy esetleges támadó is tud telepíteni amit akar, ezért ne hagyj benne olyan komponenseket amelyekre nincs szükség. Biztonságosabb, ha éles rendszerben ezt kihagyod és ha kell még valami komponens, akkor új konténert készítesz azzal együtt.

yum install --installroot /var/lib/containers/storage/overlay/24c86...ID...dcd1/merged bash coreutils httpd --releasever 8 --setopt install_weak_deps=false

A fenti parancs a megadott útvonalra telepíti fel a kiválasztott komponenseket. Figyeld meg az ID-t a working-container útvonalában! Csökkentsük a konténer méretét azzal, hogy kiürítjük a cache-t!

yum clean all --installroot /var/lib/containers/storage/overlay/24c86...ID...dcd1/merged --releasever 8

Állítsuk be a working-container-t! Adjuk meg neki, hogy a Bash legyen a parancsértelemző és a httpd pedig induljon el a konténer indításakor.

buildah config --entrypoint "/usr/sbin/httpd -DFOREGROUND" working-container
buildah config --cmd /bin/bash working-container

Adjuk meg a konténer nevét!

buildah config --label name=torig-base working-container

Mountoljuk le a working-containert és commitoljuk a változásokat.

buildah unmount working-container
buildah commit working-container torig-base

A commit művelet során jön létre a konténerünk a commit során megadott névvel. Ellenőrizzük, megvan-e!

[root@container ~]# buildah images 
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/torig-base latest 156f22ae8937 About a minute ago 424 MB

Nézzük meg a tulajdonságait! A Sok beállítás közt figyeljük meg a config paramétereket!

podman inspect localhost/torig-base

"Config": {
"Entrypoint": [
"/bin/sh",
"-c",
"/usr/sbin/httpd -DFOREGROUND"
],
"Cmd": [
"/bin/bash"
],
"Labels": {
"io.buildah.version": "1.11.6",
"name": "torig-base"
}
...

Az így létrehozott konténer tulajdonképpen ugyanolyan konténer image mint amit szokásosan a Dockerről vagy más forrásokból le szoktunk készen tölteni, azzal a különbséggel, hogy a mi egyedi konfigurációnkat tartalmazza. Nyissunk egy másik terminált és ellenőrizzük a futó konténereket.

[root@container ~]# podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Sehol semmi. Persze. Eddig nem is futtattunk semmit. :P Hozzuk létre a web szerverhez az index.html-t. Ebben az az érdekes, hogy a konténer elkészítése során nem raktunk a konténerbe semmilyen adatot. A web szerver által megjelenített adatokat a futtató container gépen fogjuk elhelyezni. Ez biztosítja, hogy az adataink dinamikusak legyenek. Persze lehet statikus adatokat is használni. Ha például olyan web szervert szeretnénk készíteni ami kizárólag a konténerben levő adatokat használja, akkor ezt is megtehetjük. Készítsük el az index.html-t a web szerverhez a root könyvtárába!

 mkdir -p ~/webdata/html
echo "Webszerver 1 OK" > ~/webdata/html/index.html

Most van az a pont, hogy úgy kell elindítsuk a konténert, hogy adunk neki nevet, felcsatoljuk a konténer /var/www mappájába a konténeren kívül levő ~/webdata/html/ mappánkat. Ebben a könyvtárban lesz az a web tartalom amit a konténerünk kezel. Egyúttal kell csináljunk egy port átirányítást, ahol a lokális 8080-as portot átirányítjunk a konténer 80-as portjára.
A --rm paraméter biztosítja, hogy a torigweb konténer a leállításkor törlésre kerüljön. A “Z” paraméter biztosítja a konténer és az általa elért fájlok számára a megfelelő Selinux jogokat.
most root-ként futtatjuk a konténert. Ha nem lenne a Selinux beállítva, akkor a konténer az egész fájlrendszerünkre ráláthatna. Ez nem éppen kívánatos. Érdemesebb volna rootless üzemmódban futtatni a konténert, de erről majd később. Előbb értsük meg mi történik.

podman run --rm -d --name torigweb -p 8080:80 -v ~/webdata:/var/www:Z localhost/torig-base

És fut a konténerünk!

[root@container ~]# podman run -rm -d --name torigweb -p 8080:80 -v ~/webdata:/var/www:Z localhost/torig-base
64e94a023f755398359ef06d42a18cb7473fd7eca60ef21ea7f9bd2d849a263b

Ellenőrizzük!

[root@container ~]# podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
64e94a023f75 localhost/torig-base:latest /bin/bash 43 seconds ago Up 42 seconds ago 0.0.0.0:8080->80/tcp torigweb

Kérdezzük le, hogy a web szerver válaszol-e a kérésekre!

[root@container ~]# curl http://localhost:8080
Webszerver 1 OK

Próbáljunk belépni a konténerbe! Ezt a podman exec paranccsal tehetjük meg. Futtatandó parancsnak meg megadjuk a /bin/bash -t, és akkor már be tudunk lépni a konténerünkbe. Figyeld meg, hogy itt már a konténer nevére hivatkozunk.

[root@container ~]# podman exec -it torigweb /bin/bash
bash-4.4#

Kipróbálhatunk pár parancsot a móka kedvéért. Hamar be fogjuk látni, hogy csak az működik amit telepítettünk. Például:

bash-4.4# pwd 
/
bash-4.4# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
bash-4.4# cd root
bash-4.4# pwd
/root
bash-4.4# exit
[root@container ~]#

Ez az a pont amikor kipublikáljuk a web szolgáltatást a host gépen kívülre! Ehhez tűzfalat kell nyitni a host gépen.

[root@container ~]# firewall-cmd --add-port=8080/tcp
success
[root@container ~]# firewall-cmd --reload
success

Teszteljük kívülről a szolgáltatást! lépjünk át egy másik gépre a hálózatban és curé-el kérdezzük le a web szerverünket.

[outside@user ~]$ curl http://192.168.1.187:8080
Webszerver 1 OK

Láthatjuk, hogy működik a konténer a webes szolgáltatással.
Állítsuk le a konténert!

[root@container ~]# podman stop torigweb

Ne felejtük el, hogy --rm paraméter hatására a konténer kilépéskor törlődik. Amennyiben nem --rm paraméterrel indítjuk a konténert, most ki kéne adnunk a podman --rm torigweb parancsot. Lesz rá példa mindjárt, csak előbb kavarjuk meg egy kicsit ezt az egészet. Csináljunk másik portra is konténert egy másik webes szolgáltatással.
Indítsuk el még egyszer a konténerünket úgy mint az előbb, aztán indítsunk egy másik konténert más néven és másik portot irányítsunk át és legyen neki saját index.html-je! Készítsünk neki saját index.html fájlt!

[root@container ~]# mkdir -p ~/webdata2/html
[root@container ~]# echo "Webszerver 2 OK" > ~/webdata2/html/index.html

Futtassuk mindkét konténert. Figyelj oda a gépnevekre, portokra és az index.html-t tartalmazó mappákra a parancsban!

[root@container ~]# podman run --rm -d --name torigweb1 -p 8080:80 -v ~/webdata:/var/www:Z localhost/torig-base
27c2601b2d87557c1aba9c2fcdd93ab68fde268a4ca31df00e8417c64462d412
[root@container ~]# podman run --rm -d --name torigweb2 -p 8081:80 -v ~/webdata2:/var/www:Z localhost/torig-base
14b7e90b831117c8ff592bb9f9f1eaebe8ebd28d89d2be913babf76298d41b84

Nyissuk ki a 8081-es portot is!

[root@container ~]# firewall-cmd --add-port=8081/tcp
success
[root@container ~]# firewall-cmd --reload
success

Ellenőrizzük a konténereket!

[root@container ~]# podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
aa539194c284 localhost/torig-base:latest /bin/bash 40 seconds ago Up 39 seconds ago 0.0.0.0:8081->80/tcp torigweb2
39ab36339f90 localhost/torig-base:latest /bin/bash 54 seconds ago Up 53 seconds ago 0.0.0.0:8080->80/tcp torigweb1

Látható, hogy mindkettő fut! Működik is kívülről? Ellenőrizzük!

[outside@user ~]$ curl http://192.168.1.187:8080
Webszerver 1 OK
[outside@user ~]$ curl http://192.168.1.187:8081
Webszerver 2 OK

Láthatod, hogy nem kellett újra image-t buildelni. Elég a meglévő konténert újra elindítani, tehát ha úgy vesszük bármikor tetszőleges számú fejlesztő vagy éles környezet akárhány példányban indíthatunk. A fentiekből az is látszik, hogy mindez remekül scriptelhető.

A working-container-re már nincs szükségünk többé, mert kész a konténerünk.

buildah rm working-container

A két konténert egy paranccsal is leállíthatjuk.

podman stop torigweb1 torigweb2

Ha már nincs szükségünk a konténer image-re, akkor azt így törölhetjük.

buildah rmi torig-base

Amennyiben újra szeretnénk építeni egy konténert, akkor a fentebb leírt procedúrát végigcsinálva a working-container újraépítésével akármikor új konténer image hozható létre igényeink szerint. Látható, hogy ez is kiválóan scriptelhető. Így a konténer környezet például a working-container a parancsok tárolásával és újrafuttatásával bárhol bármikor létrehozható. Ezzel azt is el tudjuk érni, hogy a konténer környezetünk hordozhatóvá válik.

Most viszont vágjunk bele egy olyan témába, hogy hogyan használjuk ki azt a lehetőséget, hogy a konténerünk boot időben perzisztens módon a gépünkkel elinduljon.

Podnam konténer futtatása systemd-vel

Hogyan tegyünk egy konténer konfigurációját perzisztenssé? A perzisztencia azt jelenti, hogy a konténer a rendszer újraindításákor (boot időben) induljon el külön beavatkozás nélkül. Ebben van a Podman nagy előnye a Dockerrel szemben, ugyanis képesek vagyunk a konténereket systemd service-ként futtatni.
Különbséget kell tegyünk a "root" módban futtatott konténerek és más felhasználó nevében "rootless" futtatott konténerek közt. Ez utóbbi sokkal biztonságosabb megoldás. Ha lehet, csak ezt alkalmazzuk.

Root konténerek futtatása

Elsőnek vegyük a root módban futtatott konténereket. Ennek lépései a következőek. Elsőnek állítsuk be a loginctl-t. Ez a systemd login managere.

loginctl enable-linger

Ellenőrizzük a beállítást!

loginctl show-user root
...
Linger=no

Megjegyzés: A loginctl disable-linger paranccsal lehet letiltani, de ezt most nem használjuk.

Készítsük el a service fájlt. Erre van egy podman parancsunk ami elkészíti helyettünk megfelelő szintaktikával a konfig fájlt. Fontos, hogy a konténert most --rm paraméter nélkül kell futtatni, hogy létrejöjjön a konténerünk a megfelelő névvel, majd és le kell állítani. Ellenkező esetben a service nem fog ID-t találni, hiszen a --rm parancs a konténert leállításakor törli.

podman run -d --name torigweb1 -p 8080:80 -v ~/webdata:/var/www:Z localhost/torig-base
podman stop torigweb

Lépjünk be a Systemd könyvtárba!

cd /etc/systemd/system

Generáljuk le a Systemd fájlt a podman generate parancs használatával!

[root@container system]# podman generate systemd --name torigweb1 --files
/etc/systemd/system/container-torigweb1.service

Töltsük újra a Systemd konfigurációt, hogy az új konfigurációs fájlt felvegye a rendszer.

systemctl daemon-reload

Indítsuk el a konténert a Systemd-vel!

systemctl start container-torigweb1

Kérjük le a státuszát!

systemctl status container-torigweb1

Rögzítsük a konfigurációt, hogy rendszer induláskor elinduljon.

systemctl enable container-torigweb1

A továbbiakban a konténer indítása, leállítása a Systemd-vel végezhető.

systemctl stop container-torigweb1

Ha nem akarjuk, hogy rendszerindításkor elinduljon, akkor a következő paranccsal kell megtiltsuk, de ezt most hagyjuk ki a tesztünkhöz.

systemctl disable container-torigweb1

Indítsuk újra a gépünket!

reboot

podman ps -el ellenőrizzük, hogy areboot után a konténer fut-e. Láthatjuk, hogy a rendszer indításával egy időben a konténer elindult és a szolgáltatásunk is elérhető kívülről.

Akkor most csináljuk meg ugyanezt rootless konténerrel!

Rootless konténer futtatása

Készítsünk rootless konténert. Nagyon fontos! Ezt mindenképpen úgy kell készítsük, hogy bejelentkezünk a gépbe. Nem úgy, hogy bejelentkezünk valakinek a nevében aztán su - devops vagy sudo su, mert úgy nem fog működni.
További érdekesség, hogy a létrehozott konténer akkor indul majd el, amikor a felhasználó belép a profiljába.
A lépések nagyjából ugyanazok mint fentebb, ezért külön nem magyarázom őket, csak a különbségeket emelem ki.

Lépünk be root felhasználóval, majd készítsünk egy felhasználót akinek a nevében a konténer futni fog, majd adjunk neki jelszót mjad lépjünk ki a root fiókból!

useradd -m devops
passwd
exit

Most lépjünk be konzolon vagy ssh-n a devops felhasználó nevében. Itt most ssh-t fogok használni.

ssh Ez az e-mail-cím a szpemrobotok elleni védelem alatt áll. Megtekintéséhez engedélyeznie kell a JavaScript használatát.

Készítsük el újra a working-container-t!

buildah from scratch

Lényeges, hogy most a mountot, a devops felhasználó nevében kellene kiadni, csakhogy a mountot kizárólag a root vagy root jogú (sudoers) felhasználó csinálhatja. Azért, hogy a mountot meg tudjuk csinálni az unshare paramétert kell használjuk. A parancs kiadása után figyeljük meg, hogy root konzolba kerülünk.

buildah unshare --mount working-container

Kérdezzük le a mountokat!

df -h

Itt már látszik a mount pont, azt kell másolni a könyvtár útvonalára. Figyeljük meg, hogy ez már a devops felhasználó home könyvtárunkba mutat!
/home/devops/.local/share/containers/storage/overlay/a444...ID...7494f/merged

A lépések innen ugyanazok mint feljebb.

yum install --installroot /home/devops/.local/share/containers/storage/overlay/a444...ID...7494f/merged bash coreutils httpd --releasever 8 --setopt install_weak_deps=false
yum clean all --installroot /home/devops/.local/share/containers/storage/overlay/a444...ID...7494f/merged --releasever 8
buildah config --entrypoint "/usr/sbin/httpd -DFOREGROUND" working-container
buildah config --cmd /bin/bash working-container
buildah config --label name=torig-base working-container
buildah unmount working-container
buildah commit working-container torig-base

buildah images
podman inspect localhost/torig-base

mkdir -p ~/webdata/html
echo "Webszerver 1 OK" > ~/webdata/html/index.html

podman run --rm -d --name torigweb -p 8080:80 -v ~/webdata:/var/www:Z localhost/torig-base

podman ps

curl http://localhost:8080
Webszerver 1 OK

firewall-cmd --add-port=8080/tcp
firewall-cmd --reload

Curl-al ellenőrizzük kívülről is, hogy működik-e! Ha igen, akkor mindent jól csináltunk.

podman stop torigweb

Csináljuk meg a szervizt úgy mint fentebb! Figyeljük meg, hogy a systemd konfigurációs fájl, most a felhasználó könyvtárába kerül! Megjegyezném, hogy user a könyvtár neve és nem devops.
A podman generate parancs a felhasználó könyvtárába fogja létrehozni a konfigurációs fájlt, amennyiben a könyvtár létezik. ~/.config/systemd/user/

podman run -d --name torigweb -p 8080:80 -v ~/webdata:/var/www:Z localhost/torig-base
0983b48ec5a102361827bba362dec02661ec8eb16bf62e005fc70b184ff3ce23
podman stop torigweb
0983b48ec5a102361827bba362dec02661ec8eb16bf62e005fc70b184ff3ce23

mkdir -p ~/.config/systemd/user/
cd ~/.config/systemd/user/

podman generate systemd --name torigweb --files

Állítsuk be a felhasználónak a loginctl-t!

loginctl enable-linger devops
loginctl show-user devops
...
Linger=yes

Lépjünk ki a root konzolból!

exit

És újra a devops felhasználó profiljában találjuk magunkat.

A devops felhasználó profiljába belépve mindig indul egy konténer. Ha több terminálon jelentkezünk be, akkor a podman ps-el láthatjuk, hogy minden bejelentkezés indít egy konténert. Amikor kilépünk, a konténer leáll. Ezt is ellenőrizhetjük a podman ps-el.

Remélem sikerült segítenem ahhoz,. hogy elkezdhess egy kicsit játszani a Podman konténerekkel.