Konfiguráció menedzsment eszközök

A Unix/Linux szerverek üzemeltetése wikiből
A lap korábbi változatát látod, amilyen ÁronM (vitalap | szerkesztései) 2011. január 10., 20:48-kor történt szerkesztése után volt.

Előre felhívom a figyelmet, hogy ez a szócikk arra nem elegendő, hogy meg lehessen belőle tanulni a konfiguráció menedzsment eszközök használatát. Arra viszont remélem, elegendő lesz, hogy kiinduló pontot nyújtson az ezek használatáról való döntéshez.

Tartalomjegyzék

1 A probléma

Van n db. számítógép, amik nagyon hasonló feladatot látnak el, így nagyon hasonlóan is kellene őket adminisztrálni. Külön adminisztrálni mindegyiket kényelmetlen, és meglehetősen nagy káoszhoz vezetne.

2 A naív hozzáállás

Az ötlet hihetetlenül egyszerű. Összeállítunk egy shellscriptet, ami elvégzi a gépen a szükséges módosításokat, összecsomagoljuk a számára szükséges file-okkal, majd az adminisztrálni kívánt gépekre valahogyan eljuttatjuk a csomagot, és lefuttatjuk rajtuk a shellscriptet. Ezt pl. egy cron job segítségével automatizálni is lehet valamennyire. Az ötlettel azonban van néhány probléma. Mi van pl., ha néhány gépen sikeresen lefut az így összeállított shell script, néhányon pedig nem? A központilag adminisztrálni próbált gépek konfigurációja ez által el fog térni egymástól, és így megnehezítettük a saját dolgunkat. Arról nem is beszélve, hogy az ilyen céllal összedobott shellscriptek könnyen elérhetik az átláthatatlanság, és ez által a karbantarthatatlanság határát.

3 cfengine

3.1 Mi az a cfengine?

A problémára kitalált első "komoly" megoldás. Sok, különböző, Unix-szerű platformon képes működni. Az alapvető elv az, hogy nem ugyanazt az egy rendszert akarjuk sok példányban replikálni, és nem ugyanazokat a parancsokat akarjuk minden gépnek kiadni, csupán azt akarjuk, hogy teljesítsék ugyanazokat az elvárásokat. Szabályokat lehet benne definiálni, mely szabályoknak megfelelő állapotba hozza a menedzselt gépeket. Ezek a szabályok nem azt írják elő, milyen lépéseket kell tennie a cfengine-nek, csupán azt, milyen állapotban kell lenniük a menedzselt hosztoknak. Arra nincs garancia, hogy tényleg az előírt állapotban lesznek a hosztok, azonban biztosan tartani fognak az előírt állapot felé.

3.2 Komponensek

  • cf-promises - Ellenőrzi, hogy a rendszer megfelel -e a szabályoknak.
  • cf-agent - Módosításokat végez a rendszeren.
  • cf-serverd - Kéréseket fogad létező szabályok alkalmazására.
  • cf-execd - Ütemező.
  • cf-runagent - Kéréseket lehet vele küldeni a cf-serverd-nek.
  • cf-report - Jelentést készít.
  • cf-know - Dokumentációt generál a szabályokról.

3.3 Szabályok felépítése

A szabályok ú.n. ígéretekből állnak. Az ígéreteket fel lehet bontani egy objektumra, melynek teljesítenie kell az ígéretet, opcionálisan egy objektumra, melynek érdeke ez az ígéret (dokumentációs szempontból), valamint a testre. A test balérték => jobbérték (ahol balérték egy foglalt szava a nyelvnek) kijelentések sorozata. Ezen kijelentések sablonokra is hivatkozhatnak, melyek az alábbi formájúak:

body bal jobb
{
bal1 => jobb1;
bal2 => jobb2;
}

Egy ígéret pedig az alábbi formájú:

"ígéretet tevő objektum"
  bal => jobb;

Az ágenseknek van egy speciális, control nevű sablonuk, amin át a viselkedésük befolyásolható. Az ígéretek kötegekbe gyűjthetők. A kötegek ahoz az ágenshez tartoznak, mely a benne foglalt ígéretek betartásával foglalkozik. A sablonok képesek paramétereket fogadni, melyeket a sablonon belül aztán változóként lehet használni. A paramétereket a sablon neve után zárójelek között kell megadni. A változónevek formája $(változónév). Valójában a változók is ígéretek: arra vonatkozó ígéretek, hogy az lesz az értékük, ami meg van adva.

3.4 Döntések

Az ágens az indulásakor meghatározza, milyen paraméterekkel rendelkezik a host, amin fut. Ennek alapján osztályokba sorolja a gépet. Emellett saját osztályozási elvek is definiálhatóak kötegek segítségével. Erre egy példa:

bundle agent osztaly
{
 classes:
  "dhcp_szerver" or => {fileexist("/etc/dhcp/dhcpd.conf"), fileexist("/etc/dhcp/dhcpd6.conf")};
 dhcp_szerver::
  #ide jönnek azok az ígéretek, amik teljesülését akkor szeretnénk, ha a gép egy dhcp szerver
}

Ebben a példában annak alapján döntöttük el (nem igazán helyes módon, de most jobb ötletem nem volt), hogy dhcp szerver -e a gép, hogy van -e /etc/dhcp/dhcpd.conf, vagy /etc/dhcp/dhcpd6.conf nevű fájl. Ha igen, akkor a dhcp_szerver osztályba tartozó gépekre vonatkozó szabályok végrehajtódnak. A :: operátor előtt több osztály nevét is fel lehet sorolni köztük logikai operátorokkal, így a gépek egy tetszőlegesen bonyolult módon meghatározott halmazára vonatkozó szabály alkotható.

3.5 Ígéretek típusai

  • vars - változó, mely adott értéket fog felvenni
  • classes - a rendszer jellemzőire és állapotára vonatkozó kijelentés. Ezek alapján lehet döntéseket hozni.
  • reports - Üzenetek jelentésbe írása.
  • commands - utasítás végrehajtása.
  • databases - adatbázisokra vonatkozó ígéretek.
  • files - fájlra vonatkozó ígéretek. Vonatkozhatnak a létezésére, attributumaira, és tartalmára.
  • interfaces - hálózati interfészek konfigurációjára vonatkozó ígéretek.
  • methods - további ígéretek kötegeire vonatkozó ígéret.
  • packages - csomag telepítettségére vonatkozó ígéret.
  • storage - csatolt tárolókra vonatkozó ígéretek.

3.6 Bővebb dokumentáció

4 Puppet

4.1 Felépítés

A puppet név alapvetően a kliens oldali programot takarja. Szerver oldali párja a puppet-server nevű csomagban található a disztribuciók többségében, és puppetmasterd névre hallgat. Mind a kliens, mind a szerver ruby programnyelven íródott, és GPL licensz alatt érhető el. A fejlesztőktől a két programot egyetlen forráscsomagban tölthetjük le. A szerver a 8140-es TCP porton, SSL titkosított kapcsolaton érhető el. A manifest fájlok a szerver /etc/puppet/manifests/ útvonalán, .pp névvégződésű fájlokban találhatóak. Közülük a nodes.pp az, ami a hostok neve szerint szétválasztva dönti el, mely hostra mely konfigurációs elvárások vonatkoznak. include utasításokkal ebbe további konfigurációs fájlok illeszthetők. Mikor a puppetd elindul, csatlakozik a puppet szerver 8140-es portjára, lekérdezi a rá vonatkozó manifest-et, és a host konfigurációját úgy módosítja, hogy az eleget tegyen a manifest-ben írt elvárásoknak. Ha eleve eleget tesz nekik, akkor természetesen semmit nem tesz. A módosításokról aztán jelentést küldhet a kliens a szerver felé, majd ugyanezt alapértelmezés szerint fél óránként újra megteszi.

4.2 Manifest példa

nodes.pp

node bootszerver {
    include tftp
}

tftp.pp

class tftp {
    package { "tftpd":
        ensure => installed,
        ensure => latest
    }
    package { "xinetd":
        ensure => installed,
        ensure => latest
    }
    yumrepo { "sajat":
        baseurl => "http://repo.sajatdomain/yumrepo",
        descr => "Sajat yum repository-m, melyben a tftpboot-konyvtar csomag talalhato.",
        enabled => 1,
        gpgcheck => 0
    }
    package { "tftpboot-konyvtar":
        ensure => installed,
        ensure => latest
    }
    file { "/etc/tftpd.map":
        source => "puppet://tftp_konf/tftpd.map"
    }
    service { "xinetd":
        ensure => running
    }
}

Amit ebből a (gyakorlati felhasználásra túl rövid, wiki szócikkbe túl hosszú) példából rögtön láthatunk, az az, hogy a manifest-ek resource-okból állnak, amiknek típusa (pl. package, service, file, exec), neve (a ':' karakter előtt), valamint attributumai vannak. Az attributum nevéhez annak értékét a '=>' operátor segítségével lehet hozzárendelni. Az attributumoknak lehetnek alapértelmezett értékei. Ezen alapértelmezett értékeket típusonként be lehet állítani. Pl. az exec típus path attributumához az alábbi módon rendelhetünk alapértelmezett értéket:

Exec { path => '/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin' }

Ami itt rögtön feltűnik, hogy az exec típus nevét nagy kezdőbetűvel írtuk. Ennek az az oka, hogy a kezdőbetű alapján tudja a puppet, hogy deklarációról van -e szó. A kis kezdőbetű deklarációt jelent. Márpedig most nem deklarálni akarunk egy resource-t, hanem alapértelmezett értéket akarunk megadni egy típusra. Azt, hogy milyen paraméterek vannak, a resource típusa határozza meg, azonban léteznek metaparaméterek, amik minden resource esetében megtalálhatóak. Ilyen a subscribe és a require. Mindkettejük egy resource-ra való referenciát, vagy resource referenciák listáját veheti fel értékéül. Referenciát úgy adhatunk meg, hogy nagy kezdőbetűvel megadjuk a resource típusát, majd '[]' között a nevét. A puppet képes változókat is kezelni. A változók neve '$' karakterrel kezdődik. Példa változó értéke alapján való döntésre:

path => $operatingsystem ? {
    solaris => "/usr/local/etc/sudoers",
    default => "/etc/sudoers"
}

A puppet által ismert típusokról, metaparaméterekről, beépített függvényekről, és minden egyébről korrekt dokumentáció érhető el a hivatalos weblapján: http://projects.puppetlabs.com/projects/puppet/wiki/Reference_Index Érdemes továbbá megemlíteni, hogy a puppet saját típusokat és függvényeket megvalósító, ruby nyelven írt modulokkal is bővíthető, így a fentebb említett dokumentációban adott típusok viszonylag kis száma nem korlátozza az eszköz használhatóságát. Ezen modulok megalkotásának módjáról is olvasható dokumentáció a fentebbi címen.

5 ISconf

Az ISconf mögötti elv meglehetősen egyszerű: Ha két host-on pontosan ugyanazokat a változtatásokat pontosan ugyanabban a sorrendben végzik el, pontosan ugyanúgy fognak viselkedni. Az, hogy a két rendszer garantáltan, pontosan ugyanúgy viselkedjen, a legalacsonyabb költséggel az előző mondatban ismertetett módszerrel oldható meg. A cfengine által alkalmazott elképzelésekhez képest tehát az a fő különbség, hogy a változtatások sorrendje is szigorúan kötött. Így az ISconf nem azt garantálja, hogy a vele adminisztrált rendszerek tartani fognak az előírt állapothoz, hanem azt, hogy egyik, pontosan az előírtnak megfelelő állapotból a másik, pontosan a később előírtnak megfelelő állapotba kerül anélkül, hogy bármikor is nem az előírtnak megfelelő állapotba kerülne. Amennyiben az előírttól eltérő állapotot tapasztalunk, az meghibásodás, vagy a rendszer ellen intézett támadás eredménye, így ebben az esetben ki kell deríteni, mi okozta a problémát. Amennyiben biztonsági hiba az ok, javítani kell a biztonsági hibát, majd az érintett rendszereket újratelepíteni, és hagyni, hogy az ISconf a legutolsó előírt állapotba hozza a rendszert. A helyreállításhoz szükséges idő rövidíthető, ha van egy olyan állapotnak megfelelő image, melyből már viszonylag kevés (néhány óra alatt elvégezhető mennyiségű) műveletet kell végrehajtania az ISconf-nak. Rollback-et tehát soha nem végzünk. Ha hiba miatt tértünk el a helyes állapottól, újratelepítjük a rendszert. Persze, ez azt is jelenti, hogy az adminisztrációra kizárólag az ISconf használandó, hiszen minden, nem az ISconf által elkövetett változtatás az ISconf által előírttól eltérő állapotot eredményezne.

Személyes eszközök