A PodSpace, mint platform szolgáltatás arra való, hogy a forráskódból gyorsan és egyszerűen állítsunk össze működőképes futtatókörnyezetet. Az sem árt, ha mindezt megismételhetően és automatizálhatóan tesszük, így könnyen automatizálhatóvá válik a teljes fejlesztési folyamat. Ebben a cikkben egy Laravel alapú PHP alkalmazás példáján keresztül megnézzük, hogyan lehet forráskódból futtatható Docker image-et előállítani, és mellé rakni egy szintén Docker alapú adatbázis szervert.

A példánkban a quickstart-intermediate Laravel minta-alkalmazás forráskódját fogjuk használni, ami egy egyszerű feladatlista kezelő alkalmazás, felhasználói regisztrációval és autentikációval. Az alkalmazás működéséről részletes leírás található a Laravel dokumentációjában, forráskódja megtalálható a GitHub-on. Ezt az alkalmazást fogjuk telepíteni a PodSpace beépített PHP 5.6-os futtatókörnyezetébe, a webes menedzsment konzol használatával.

A forráskód

Az alkalmazásunk forráskódja a GitHub-on van, a Laravel csoport alatti quickstart-intermediate repóban.

Ezen a repón egy apró konfigurációs változtatást kell eszközöljünk ahhoz, hogy tökéletesen működjön PodSpace alatt: mivel a PHP alkalmazáskörnyezetben a DocumentRoot a telepített GIT repó gyökérkönyvtára lesz, ezért egy megfelelően kialakított .htaccess fájlt kell elhelyezni a repóban, ami átirányítja a kéréseket a Laravel alkalmazás belépési pontjára a public könyvtárba.

Ha az olvasónak nincs GitHub-os accountja, vagy csak kihagyná ezt a lépést, akkor használja az alábbi, PodSpace-es quickstart-intermediate repository-t a következő lépésekben: https://github.com/podspace/quickstart-intermediate Ebben a repóban már elvégeztük a szükséges beállítást.

Ehhez nincs más dolgunk, mint bejelentkezni a GitHub-ra, és a quickstart-intermediate repót forkolni a "Fork" gomb megnyomásával, majd a saját accountunk alatt lévő, forkolt repóban létrehozni egy új, .htaccess nevű fájlt, a következő tartalommal:

<IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteRule    ^$    public/      [L]
    RewriteRule    (.*)  public/$1    [L]
</IfModule>

Ezt is megtehetjük a GitHub webes felületén a "Create new file" gombra való kattintással, majd miután bemásoltuk a fájl tartalmát, az oldal alján lévő "Commit new file" gombbal menthetjük a változtatásokat.

Azért is célszerű saját GitHub accountról végigmenni ezen a tutorialon, mert a végén megnézzük, hogy hogyan lehet az automatikus buildelést és kihelyezést beállítani: amint módosítunk valamit a repón, a PodSpace automatikusan előállít az alkalmazásunkból egy új Docker image-et. Ez nem csak GitHub-bal működik, de a GitHub-on csak akkor tudjuk beállítani, ha regisztrált felhasználók vagyunk.

Projekt és alkalmazás létrehozása

Miután készen áll a forráskód, hozzunk létre egy projektet a PodSpace-ben: jelentkezzünk be a webes menedzsment konzolon, és kattintsunk az "Új Projekt" gombra, majd adjunk nevet a projektünknek:

php laravel tutorial 1
Figure 1. Projekt létrehozása

A következő lépésben az "Új alkalmazás" képernyőn válasszuk ki a php:5.6 futtatókörnyezetet, majd adjunk egy nevet az alkalmazásnak (pl.: laravel), és adjuk meg azt a GitHub repository-t, amiben az elvégeztük a módosításokat.

php laravel tutorial 2
Figure 2. Alkalmazás létrehozása

Kattintsunk a "Létrehozás" gombra, majd menjünk tovább az áttekintő képernyőhöz. Ezen a ponton a rendszer megkezdi az alkalmazás forráskódjából egy futtatható Docker image előállítását - ez első alkalommal 2-3 percig is eltarthat, a Napló megjelenítése linkre kattintva nyomon követhetjük a haladást.

php laravel tutorial 3
Figure 3. Az alkalmazás létrehozása során automatikusan elindul a build
Ezen a ponton az ún. S2I eljárással készül el a forráskódból a futtatható Docker image. Azt, hogy ez pontosan hogyan történik, azt a futtatókörnyezetet is tartalmazó ún. builder image (esetünkben az alkalmazás létrehozásakor kiválasztott _php:5.6) határozza meg, ami maga is egy Docker image, és mint ilyen, a felhasználó által tetszőlegesen testreszabható. Ha egy alapból nem támogatott programozási nyelvet, vagy futtatókörnyezetet akarunk használni, akkor mi magunk is viszonylag egyszerűen összeállíthatunk egy ilyen builder image-et. Tulajdonképpen a PodSpace-ben a futtatókörnyezeteket is ugyanúgy tudjuk buildelni, mint az alkalmazásokat.

Miután a build lefutott, az alkalmazás automatikusan elindul egy példányban. Az apps.podspace.hu végződésű linkre kattintva meg is jelenik a kezdőképernyő.

php laravel tutorial 4
Figure 4. Elindult az alkalmazás

Közben körbenézhetünk a menedzsment felületen: kilistázhatjuk a futó podokat (a pod a PodSpace-ben a Docker konténert jelenti), megnézhetjük a naplóit, beléphetünk a konténer parancssori felületére, stb. Illetve skálázhatjuk az alkalmazásunkat: az Áttekintés képernyőn a fel / le nyilakra való kattintással további példányokat indíthatunk az alkalmazásból. A PodSpace terheléselosztói automatikusan elosztják az alkalmazásra érkező forgalmat a különböző példányok között.

Adatbázis létrehozása

Az alkalmazásunkat tehát lefordítottuk, és telepítettük. De nincs hozzá adatbázis szerverünk, és ha megpróbálunk valamilyen értelmes műveletet az alkalmazáson (pl. regisztrálás vagy bejelentkezés), akkor látni is fogjuk hogy nem működik az adatbázis hiánya miatt.

Telepítsünk hozzá egy adatbázist! Kattintsunk az Új alkalmazás gombra a menedzsment felületen, és válasszuk ki az oldal aljáról a mysql-ephemeral adatbázist. Az adatbázis létrehozásakor a felhasználónevet, a jelszót és az adatbázis nevet töltsük ki az itt láthatóhoz hasonlóan:

php laravel tutorial 5
Figure 5. Adatbázis szerver létrehozása

Majd kattintsunk a Létrehozás gombra. Az áttekintő képernyőn láthatjuk, hogy megjelent egy újabb alkalmazás:

php laravel tutorial 6
Figure 6. Elindult az adatbázis szerver

De honnan fogja tudni a PHP-s alkalmazásunk, hogy ehhez az adatbázishoz csatlakozzon. A válasz egyszerű: a PodSpace a mysql alkalmazáshoz létrehozott egy mysql nevű szolgáltatást, amitől a projekten belül futó összes másik pod eléri a mysql szervert a mysql hosztnéven keresztül. Vagyis csak azt kell beállítani a Laravel-ben, hogy a mysql hoszton futó adatbázishoz csatlakozzon, azzal a felhasználónév és jelszó párossal amit a mysql létrehozásakor megadtunk.

Ha az alkalmazás forráskódjában megvizsgáljuk a config/database.php fájl tartalmát, akkor látni fogjuk, hogy az adatbázis elérhetősége környezeti változók definiálásával megadható:

php laravel tutorial 7
Figure 7. Adatbázis kapcsolat paraméterei az alkalmazás forráskódjában

Annyi a dolgunk tehát, hogy beállítsuk a DB_HOST, DB_DATABASE, DB_USERNAME és DB_PASSWORD környezeti változók értékét a laravel alkalmazásban. A környezeti változókat definiálhatjuk build szinten, illetve deployment szinten is. Mi most build szinten fogjuk definiálni - ez azt jelenti, hogy a létrejött Docker image-ben már beállításra kerülnek.

Ehhez navigáljunk a laravel build config kezdőképernyőjére a menedzsment konzolon (Tallózás / Buildek / laravel), és a Műveletek gomb alatt válasszuk ki a Szerkesztés opciót. A megjelenő űrlap alján vegyük fel a négy környezeti változónkat azzal az értékkel, amiket a mysql alkalmazás létrehozásakor is megadtunk, valahogy így:

php laravel tutorial 8
Figure 8. Környezeti változók beállítása a PHP alkalmazásban

Majd kattintsunk a Mentés gombra, és a következő képernyőn a Build indítás gombra. Ezzel elindítunk egy új buildet ami 1-2 perc alatt végrehajtódik, és a végén az előállt Docker image alapján létre is jönnek az új podok (ezt a folyamatot a PodSpace-ben deployment-nek nevezik).

Ha most újra megnyitjuk az alkalmazást, és megpróbálunk regisztrálni, akkor továbbra is hibát fogunk kapni. De már nem azért, mert nem tud csatlakozni az adatbázis szerverhez, hanem azért, mert nem léteznek azok az adatbázis táblák, amiket használna.

Ez várható is volt, hiszen jelenleg üres az adatbázis: végre kell hajtsunk egy adatbázis migrációt ahhoz, hogy a Laravel inicializálja az adatbázist. Ehhez az áttekintő képernyőn kattintsunk a laravel alkalmazás kék karikájába a podok listájához, majd kattintsunk egy tetszőleges podra (valószínűleg csak egy futó podunk lesz, hacsak nem skáláztuk az alkalmazást a nyilakkal). A pod kezdőlapján pedig válasszuk ki a Konzol fület, és adjuk ki a php artisan migrate parancsot:

php laravel tutorial 9
Figure 9. Adatbázis migráció végrehajtása parancssorból

Ha ez sikeresen lefutott, az azt jelenti, hogy tudott csatlakozni az adatbázishoz, és létre is hozta a szükséges táblákat. Ettől kezdve már ténylegesen használható az alkalmazás. Próbáljuk ki!

php laravel tutorial 10
Figure 10. Alkalmazásunk tesztelése: regisztráció, feladatok létrehozása

Automatikus adatbázis migrációk

Azt láttuk, hogy a konténerből manuálisan végre tudjuk hajtani a migrációt, de ez nem túl elegáns: nem szeretjük a manuális folyamatokat. A PodSpace-ben - ha csak egy logikai környezettel dolgozunk, mint ebben a példában - a verziókihelyezés folyamata az alábbi módon történik:

php laravel tutorial 11
Figure 11. Alkalmazás-kihelyezés folyamata a projektünkben

A fejlesztő módosítja a forráskódot, majd bepusholja a GIT repóba, aminek hatására elindul egy Build. A build végén előáll egy Docker image, ami bekerül a registry-be, és ekkor elindul egy új deployment. A deployment során a régi verziójú image-et futtató podok leállnak, és elindulnak az új verziójú image-ek.

A deployment egy intelligens folyamat. Például, ha felskáláztuk több példányra az alkalmazást, akkor beállíthatjuk, hogy egyesével állítsa le és indítsa újra az egyes példányokat, így leállás nélkül végrehajtva a verziókihelyezést. De ha olyan a változtatás, hogy csak leállással lehetséges, akkor azt is megadhatjuk, hogy állítsa le egyszerre az összes példányt.

Mi azt szeretnénk, ha az adatbázis migráció automatikusan megtörténne akkor, amikor lefordult az új alkalmazás, és folyamatban van az új verzió kihelyezése. Ezt a DeploymentConfig módosításával tehetjük meg. Az admin felületen válasszuk ki a Tallózás / Deploymentek menüpontot, majd a laravel deploymentet kiválasztva kattintsunk a jobb felső sarokban a Műveletek / Yaml szerkesztése opcióra.

A megjelenő ablakban YAML formátumban szerkeszthetjük a DeploymentConfig-ot. Írjunk be egy pre blokkot a rollingParams attríbutum alá, az alábbi tartalommal:

    strategy:
      type: Rolling
      rollingParams:
        pre:
          failurePolicy: Retry
          execNewPod:
            containerName: laravel
            command: [ "php", "artisan", "migrate" ]

Figyeljünk az indentációra! A végeredmény valahogy így nézzen ki:

php laravel tutorial 12
Figure 12. Adatbázis migráció végrehajtásának beállítása a DeploymentConfig-ban

Ellenőrzésképpen nyomjuk meg a Deploy gombot - ha minden jól csináltunk, akkor a deployment sikerülni fog. Mivel az adatbázis szerverünk alatt nincs perzisztens tárhely, ezért ha leállítjuk és újraindítjuk azt, akkor az adattáblák is törlődni fognak. Egy új deployment végrehajtására azonban a migráció újra-inicializálja az adatbázist.

Az egyszerűség kedvéért ebben a leírásban nem raktunk perzisztens tárhelyet az adatbázis alá. A perzisztens tárhely használatát a Redmine telepítéséről szóló leírásban bemutattuk, annak beállítását - szükség esetén - az olvasóra bízzuk. Jelenleg nincs szükségünk perzisztens tárhelyre az adatbázis szerver alatt.

Automatikus fordítás és kihelyezés

Végezetül még egy dolog van hátra ahhoz hogy igazán automatizálttá tegyük ezt az egyszerű fejlesztői környezetünket: beállíthatjuk, hogy a PodSpace Git repóban történő változás esetén automatikusan fordítsa le és deployolja az alkalmazást.

Ehhez nincs más dolgunk, mint a GitHub-on beállítani egy ún. webhook-ot. Ehhez nyissuk meg a repository oldalát a GitHub-on (ez az a lépés, amit csak akkor tudunk elvégezni, ha Fork-oltuk a quickstart-intermediate repót a cikk elején leírt módon), navigáljunk a Settings / Webhooks & services lapra, és ott kattintsunk az Add webhook gombra.

Az egyszerűség kedvéért a GitHub-ot használva mutatjuk be ezt a funkcionalitást, de természetesen bármilyen más Git repository használható, sőt, a PodSpace-en mi magunk is telepíthetünk egy saját Git repository-t és dolgozhatunk abban is.

A webhook beállításakor meg kell adnunk egy Payload URL-t. Ezt a PodSpace előállította számunkra, csak annyi a dolgunk, hogy az admin konzolon a Tallózás opció alatt megkeressük a laravel buildet, és ott a Beállítások lapon megjelenik a webhook URL:

php laravel tutorial 13
Figure 13. A rendszer által generált Webhook URL kimásolása

Ezt az URL-t másoljuk ki és adjuk meg a GitHub webhook létrehozásakor, mint Payload URL. A többi mezőt hagyjuk üresen, és kattintsunk az Add webhook gombra.

Meg is vagyunk! Próbáljuk ki: módosítsunk valamit a repóban, és git push után autmatikusan elindul a PodSpace-ben egy új build, végrehajtódik az adatbázis migráció és elindul az új verzió.

Konklúzió

Ezen tutorial során létrehoztunk egy olyan alkalmazáskörnyezetet, amiben:

  • Forráskódból automatikusan futtatható Docker image-et állítottunk elő a felhőben

  • A létrejött image-eket deployoltuk a felhőben

  • Új verzió kihelyezésekor automatikus adatbázis migrációt hajtottunk végre

Mindezt úgy, hogy a forráskód módosítása esetén a fenti folyamat automatikusan végrehajtódik. Tulajdonképpen ez még csak egy nagyon rövid ízelítő a PodSpace képességeiből - de már nagyjából láthatjuk, hogy milyen építőelemeink vannak az alkalmazáskörnyezetek összeállítására, és ezek hogyan működnek együtt.

A való életben persze ennél jóval összetetteb folyamatokra van szükség: egy igazi continuous delivery stratégia megvalósításához az itt bemutatott elveket ki kell terjeszteni úgy, hogy több logikai alkalmazáskörnyezetet (úgy mint: fejlesztői, teszt, éles, stb.) lefedve, és azok közt automatikus átmeneteket végrehajtva képes legyen a rendszer arra, hogy bármelyik változtatást automatikusan és leállásmentesen kihelyezze az éles környezetre, ha az átment az automatizált teszteken.

A PodSpace erre mind képes, ráadásul egy olyan Docker alapú platform fölött valósítja ezt meg, amiben a futtatókörnyezeteink fölött teljes kontrollunk van, vagy akár mi magunk is létrehozhatunk tetszőleges futtatókörnyezetet az alkalmazásaink számára.