Gyakorlati példákon keresztül bemutatom, hogyan lehet konténereket létrehozni és mi a különbség konténer és virtuális gép között. Mivel szeretném, ha mindenki számára nyilvánvaló lenne, hogy nem csak Docker konténerek léteznek, ezért az LXD-t fogom telepíteni, amivel LXC konténerket és virtuális gépeket is lehet kezelni.
De mégis mi a kapcsolat ezek között?
- Az LXC a Linux Containers rövidítése és a Linux kernel képességeit kihasználva lehet létrehozni vele konténereket.
- Az LXD a saját dokumentációja állítása szerint az LXC-hez ad egy új felhasználói élményt, köztük felhasználóbarátabb parancssori felületet. A segítségével virtuális gépeket és azok alternatívájaként olyan konténereket lehet indítani, amikben szinte egy teljes operációs rendszer fut annak minden háttérszolgáltatásávál.
- Kezdetben a Docker is az LXC-t használta a háttérben, de azóta leváltották. Inkább alkalmazás konténereket indítunk benne minden további, felesleges szolgáltatás nélkül. Itt is van lehetőség viszont mindezt egy plusz virtualizált rétegen belül tenni.
Mivel az LXD-vel nagyjából ugyanaz fut egy konténerben, mint egy virtuális gépben, ez a legjobb módja annak, hogy összehasonlítsuk a kettőt.
LXD telepítése
Az LXD-t a snap csomagkezelővel tudom telepíteni, ami Ubuntun előre telepítve van, de más disztribúciókra is telepíthető.
A --channel
paraméter fontos, mert így lehet megadni, hogy a jelenlegi hosszan támogatott LTS verzió legyen telepítve, azon belül is a stabil verzió, nem pedig egy fejlesztői.
A következő az lxd init
parancs futtatása, ami kérdéseket fog feltenni a konfigurációhoz. Ki fogja írni az alapértelmezett értéket, és ha az megfelelő, akkor azt az enterrel el is tudjuk fogadni. A legtöbb esetben egyébként jó az alapértelmezett érték.
Alább láthatók a kérdések és válaszok, ahol az alapértelmezett értéket vastag betűvel emeltem ki, ahol pedig eltértem az alapértelmezéstől, az új választ pirossal jelöltem.
- Would you like to use LXD clustering? (yes/no) [default=no]:
- Do you want to configure a new storage pool? (yes/no) [default=yes]:
- Name of the new storage pool [default=default]:
- Name of the storage backend to use (lvm, zfs, ceph, btrfs, dir) [default=zfs]:
- Create a new ZFS pool? (yes/no) [default=yes]:
- Would you like to use an existing empty block device (e.g. a disk or partition)? (yes/no) [default=no]:
- Size in GB of the new loop device (1GB minimum) [default=18GB]:
- Would you like to connect to a MAAS server? (yes/no) [default=no]:
- Would you like to create a new local network bridge? (yes/no) [default=yes]:
- What should the new bridge be called? [default=lxdbr0]:
- What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
- What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
- Would you like the LXD server to be available over the network? (yes/no) [default=no]:
- Would you like stale cached images to be updated automatically? (yes/no) [default=yes] no
- Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]: yes
A storage pool adja majd a konténerek alatti fájlrendszert. A ZFS az alapértelmezett, amitől el lehet térni, de minden fájlrendszernek megvannak a maga előnyei és hátrányai, ami viszont ebbe a cikkbe már nem fér bele. Ha viszont nem zavar, hogy nem tudsz limitet adni a felhasználható fájlrendszerhez és ezzel túl sok helyet tudnál elfoglalni a hoszt rendszeren, akkor a "dir" is választható, amivel egyszerűen csak egy mappába kerül minden. A ZFS esetén viszont egy img kiterjesztésű fájl jön létre, ami ZFS pool-ként lesz használva. Ez a ZFS pool viszont lehet, hogy már létre lett hozva, ezért opcionális a telepítés közben, illetve módosítani lehet a nevét is.
Konfigurálni kell a hálózatot is, amihez léterjön egy bridge, így a konténerek és virtuális gépek az ezen elérhető IPv4 és IPv6 tartományból kaphatnak IP címeket.
A távoli szerver elérését a hálózaton akár be is lehet kapcsolni, ha másik gépről szeretnéd kezelni az LXD-t, de ha van SSH hozzáférésed a géphez, akkor ez nem szükséges.
Én az image-ek automatikus frissítését is le szoktam tiltani, bár ez általában nem szabad, hogy problémát okozzon, de szeretem elkerülni a meglepetéseket. Ha pedig mégis tudatosan frissítem az image-eket és az ezután létrehozott gépem nem úgy működik, ahogy vártam, legalább tudom az okát.
Végül pedig ki lehet írni a generált konfigurációt yaml formátumban. Ezt el is lehet menteni és egy későbbi újratelepítéskor például az alábbi módon vissza lehet telepíteni az LXD-t:
A fenti kérdésekre válaszolva én például az alábbi konfigurációt generáltam:
images.auto_update_interval: "0"
networks:
- config:
ipv4.address: auto
ipv6.address: auto
description: ""
name: lxdbr0
type: ""
storage_pools:
- config:
size: 18GB
description: ""
name: default
driver: zfs
profiles:
- config: {}
description: ""
devices:
eth0:
name: eth0
network: lxdbr0
type: nic
root:
path: /
pool: default
type: disk
name: default
cluster: null
Itt egy "profiles" blokk is látható, ahol egy "default" nevű profilt is létrehoztunk, ami tartalmazza azokat az infókat, amiket minden indítandó konténerre alkalmazni kell. Ez most a hálózati beállításokat és a konténerek fájlrendszerét érinti, ami a "default" nevű storage pool-ból lesz a konténerekhez rendelve.
Távoli tárolók
A konténerekhez szükség van template-re, ami tartalmazza a konténer fájlrendszerét. Ezt hívjuk image-nek. Ezeket távoli tárolókból lehet letölteni. A tárolókat pedig az alábbi paranccsal lehet listázni:
Az "image" nevű tárolóban a "linuxcontainers.org" domain alatt kisebb image-ek vannak, mivel nem tartalmaznak bizonyos elemeket, amik konténerben általában feleslegesek. Mint például a "snap". Az "ubuntu" nevű tárolóban viszont a hagyományos, nem konténerben futó Ubuntu rendszerekhez sokkal hasonlóbbakat lehet találni.
A "local" nevű tároló egy speciális eset, mivel gyakorlatilag nem távoli, hanem azon a gépen található, ahol az LXD szerver, tehát a már letöltött image-eket tartalmazza, viszont ez az alapértelmezett, aminek hamarosan jelentösége lesz.
Keresés az image-ek között
Kereshetünk az image-ek között is az alábbi paranccsal
Ahol az "ubuntu" a keresőkifejezés, de mivel az alapértelmezett tároló a local, ami üres, nem találunk semmit. A tároló megadásához a tároló neve után kettőspontot kell írni. Véletlenül az "ubuntu" egy tároló neve is, ezért a következő parancs már működik:
Az "ubuntu:" után már tényleg a kereső kulcsszavak jönnek, így rákereshetek még az amd64-es 20.04 verziójú Ubuntu image-ekre:
A "-c
" paraméterrel felsoroltam az oszlopokat is abban a sorrendben, ahogy a listában látni szeretném.
- L: Aliasok egymás alatt
- f: Fingerprint, azaz "ujjlenyomat" rövid verziója, ami az egyedi azonosító"
- a: Architektúra
- t: Típus, ami vagy CONTAINER vagy VIRTUAL-MACHINE
- s: Méret
- d: Leírás
Image információk lekérdezése
Akár egy aliast használva, akár egy fingerprintet megadva egy konkrét image adatai is lekérhetók. Alább például a 20.04 aliast birtokló image infóit kérdezem le:
Ha pedig ugyanezt a --vm
paraméterrel együtt használom, akkor a konténer verzió helyett a virtuális gép adatait kapom meg. Itt viszont már fontos, hogy a kettőspont után nem akármilyen keresőkifejezés jön, hanem tényleg csak alias vagy fingerprint!
Konténer indítása
Konténer indításához a "launch" parancsot kell használni, átadva az image nevét (tároló és alias vagy tároló és fingerprint), illetve opcionálisan egy nevet a konténernek. Ha nevet nem adok meg, akkor egy automatikus fantázianevet fog kapni.
A konténereket az alábbi paranccsal lehet kilistázni:
Illetve az "exec" használatával parancsokat lehet futtatni a konténerben. Ha viszont a "bash" parancsot futtatom, akkor gyakorlatilag belépek a konténerbe.
Kilépni pedig egyszerűen az "exit" beírásával lehet.
Virtuális gép indítása
A virtuális gép indítása nagyon hasonló, de a --vm
paramétert is meg kell adni. A --console
paraméter opcionális, de ezzel követhető a boot folyamat is.
A virtuális gépbe is be lehet lépni az "exec" használatával:
Ehhez vszont a gépben futnia kell az "lxd-agent" szolgáltatásnak. Ha egy hiba miatt nem fut, de van a géphez beállítva már jelszó, akkor utólag is lehet konzolt kérni:
Kilépni ilyenkor az "exit"-tel csak a bejelentkező promptig lehet, de a CTRL+a
, majd a "q
" billentyű lenyomásával a konzolról is le lehet csatlakozni:
Konténer és virtuális gép összehasonlítása
Kernel
Először is a konténerben nincs saját kernel, a hoszt rendszer kernelét fogja használni, mivel épp a kernel, ami a Linux névterek segítségével elszeparálja a konténerben levő processzeket a gazda rendszertől. A gazda gépen kiírva a kernel verzióját
majd a konténerben ezt megismételve
Ugyanazt a verziót kell kapjuk, de nem csak a verzió egyezik. A virtuális gép kernelének verziójából viszont az is egyértelműen látszik, hogy nem használhatja a hoszt kernelét, mivel teljesen más a verzió is.
A hosztról láthatók a konténerben futó processzek
A konténerben és a virtuális gépben is egy webszerver elindításával tesztelhető, hogy valóban beláthatunk a konténerbe, azaz láthatjuk a gazda rendszerről a konténerben futó processzeket is, de ugyanezt nem tehetjük meg a virtuális gépben levő processzekkel
Webszerver indítása a konténerben
lxc exec ubuntu-container -- bash -c 'echo "container" > webroot-container/index.html'
lxc exec ubuntu-container -- python3 -m http.server --directory webroot-container 80
Webszerver indítása a virtuális gépben
lxc exec ubuntu-vm -- bash -c 'echo "vm" > webroot-vm/index.html'
lxc exec ubuntu-vm -- python3 -m http.server --directory webroot-vm 80
A konténerben futó processzek lekérdezése a hoszt rendszerről
ps a # Minden felhasználó procsszének listája
ps au # Felhasználónév megjelenítése
ps auf # Fa struktúrában megjelenítés
Szűrés a konténerben és VM-ben levő webszerver processzre
ps au | grep webroot-vm
A fenti kódból az első sort lefuttatva nem csak az lxc exec
parancsot találjuk meg, de a konténerben futtatott, "python3
"-mal kezdődő sort is. A virtuális gép esetén viszont ezt már nem lehet látni.
Mit látnak a gépek a hoszt rendszerből?
A konténeren belül a hoszt operációs rendszer hardvereit látjuk, míg a virtuális gépben virtualizált hardvereket. Az LXD alapértelmezetten egy vCPU-t ad a virtuális gépnek, a többit nem is láthatom. A konténer viszont még akkor is látná a teljes processzort, ha korlátoznánk, mennyit használhat belőle. Az alábbi paranccsal összehasonlítható, mit lát a konténer és mit látunk a hosztról. Ha nem ad semmilyen eredményt, az azt jelenti, hogy nincs különbség. Mivel a CPU frekvencia folyamatosan változó érték és minden futattásnál mást adna, így ezt szűrtem a kimenetből.
Ugyanezt a virtuális gépre futtatva már látszik, hogy van különbség
De nyugodtan lehet ellenőrizni külön is szabad szemmel.
User névtér
A konténerekben futó processzek izolációja a linux a névterekkel történik. Ebből egyik a "user" névtér. Ennek köszönhető, hogy amikor a konténerben futtattam a webszervert, a hoszt rendszerről az azonosítója "1000000" volt. Biztonsági okokból az LXD-vel indított konténerekben a hosztról nézve minden felhasználónak ennyivel nagyobb azonosítója van. Ha létrehoztam volna egy új felhasználót, ami az 1000-t kapja azonosítóként, a hosztról 1001000-ként láthatnánk. Így a konténerben levő felhasználóknak akkor sem lesz véletlenül joga például rendszerfájlokhoz, ha amúgy a konténeren belül nézve az azonosítókat lenne. Ezt a működést meg lehet változtatni a user névtér kikapcsolásával:
Ha most itt is indítok egy webszervert
ezt a processzt már úgy látom a hosztról is, hogy a "root" felhasználó futtatja.
Net névtér
Alapértelmezetten a konténereknek saját , egyedi IP címeik lesznek, és csak a saját interfészüket látják a "loopback" interfészen kívül. Ha viszont szeretném, hogy ne kelljen portokat átirányítani a konténerre, és a konténer IP címét se kelljen tudnom, akkor a hoszt IP címét ismerve vagy a "localhost" címet használva is elérhetem akár a webszervert, ha a konténert az alábbi módon indítom, miután töröltem az előző példányt az lxc delete --force ubuntu-nstest
:
Most az "ubuntu-container" konténerben futtatva az "ip addr" parancsot csak a saját interfészét látjuk, de az "ubuntu-nstest" konténerben már a host összes interfészét.
Ezek után érdemes még megnézni a konténerlistát is, ahol most csak a neveket és az IPv4 címeket jelenítem meg:
Ha indítok ismét egy szervert ebben a konténerben
Az "ubuntu-nstest" konténer mellett látott bármelyik IP címet választhatom, el fogom érni a webszervert. Én most például a Dockernek létrehozott interfész IP címét adtam meg:
Takarítás
Ha már nem kell az LXD, törölhető, de néhány dologra figyelni kell. Mivel ZFS-sel hoztam létre a storage poolt, amikor törlöm az LXD-t, a ZFS pool továbbra is megmarad. Ha legközelebb újratelepíteném az LXD-t, már nem választhatnám a "default" nevet a poolnak. Bár utólag is megoldható, érdemes előre törölni. Ehhez viszont előbb a konténereket mind le kell állítani, különben nem lehet kivenni alóla a poolt sem.
Mielőtt a poolt törlöm, még szerkeszteni kell a default LXD profilt is az alábbi paranccsal:
Ez hivatkozik a default storage poolra, így addig nem lehet törölni. A "profiles" alatt a "root" blokkot kell megkeresni és a teljes blokkot törölni. Ezután már futtatható a pool törlés is:
Végül pedig az LXD törlése
Itt az --purge
paraméter miatt a törléskor nem fog snapshotként adatokat elmenteni a snap, ezért gyorsabban is végez és nem is foglal feleslegesen helyet. Ha viszont mégis sikerült a --purge
nélkül futtatni a törlést, akkor lekérdezhetők a snapshotok az alábbi paranccsal:
Majd a megjelenő listában az első oszlopban levő azonosítót használva el lehet feledtetni a snapshotot:
Ahol az $id
helyére a választott snapshot számát kell írni. Ha pedig még a poolt is elfelejtetted törölni, akkor utólag ubuntun a "zfsutils-linux" csomag telepítése után az alábbi módon lehet törölni a ZFS poolt:
Befejezés
Ennyi volt tehát a konténerek és virtuális gépek összehasonlítása. Természetesen ennél sokkal többet is lehetett volna mutatni, de arra lesz még lehetőség a jövőben. Az már ebből is kiderülhetett, hogy az alapvető küönbség a processzek izolációjának módjában rejlik és ebből adódnak további lehetőségek. A konténereket viszont nem csak önmagukban lehet használni, hanem ha a szükség úgy hozza, extra biztonságot adhat, ha azokat virtuális gépben futtatjuk. Ez minidg az adott programtól és a környezettől függ.
Mint mindig, kommenteket, like-okat, kritikákat várom. Az oldal Youtube csatornája és a Facebook oldala is mindenkit tárt karokkkal vár, ahol szintén lehet reagálni. Mi tetszett, mi nem tetszettt, mit olvasnál, látnál szívesebben legközelebb?