Több PHP verzió futtatása egyszerre a Docker segítségével

Ismerős a helyzet? Egy régebbi projektet kell karbantartanod, ami még PHP 7.4-en fut, miközben az új alkalmazásodat már PHP 8.3-ra fejleszted. Vagy tesztelni szeretnél egy könyvtárat, hogy kompatibilis-e a legújabb PHP verzióval, anélkül, hogy a fő fejlesztői környezetedet tönkretennéd. A PHP verziók közötti állandó váltogatás, a rendszerre telepített PHP módosítása nemcsak időigényes, hanem gyakran hibákhoz és konfliktusokhoz vezet. Szerencsére létezik egy elegáns, hatékony és korszerű megoldás: a Docker. Ebben a cikkben alaposan körbejárjuk, hogyan használhatod a Dockert arra, hogy egyszerre több PHP verziót futtass zökkenőmentesen, egy stabil és izolált fejlesztői környezetben.

Miért probléma a PHP verzióinkkal zsonglőrködni?

A PHP, mint dinamikusan fejlődő nyelv, rendszeresen ad ki új verziókat, melyek teljesítménybeli javulásokat, új funkciókat és biztonsági frissítéseket hoznak. Ez nagyszerű, de egyúttal kihívás elé is állítja a fejlesztőket. Egy projekt, amely PHP 7.4-en készült, valószínűleg nem fog azonnal hibátlanul futni PHP 8.3 alatt. Ugyanígy, egy 8.3-ra írt kód sem fut majd régebbi verziókon a deprecált funkciók vagy az új szintaktika miatt.

  • Kompatibilitási problémák: Függőségek, függvények és szintaktikai elemek változhatnak, törlődhetnek, ami „fatal error”-ökhöz vezethet.
  • Fejlesztői környezet szennyezése: Ha több PHP verziót is telepítesz a helyi gépedre (pl. `apt`, `brew` segítségével), azok könnyen ütközhetnek, és nehézkes lehet a közöttük való váltás (pl. Apache vagy Nginx konfigurációk módosítása).
  • Tesztelés és minőségbiztosítás: Gyakran szükség van arra, hogy egy alkalmazást különböző PHP verziókon teszteljünk, hogy biztosítsuk a széles körű kompatibilitást. Ez natív környezetben rendkívül bonyolult.
  • Csapatmunka: Egy csapaton belül mindenki más-más verziókat használhat, ami „az én gépemen működik” típusú problémákhoz vezet.

Ez a frusztráló helyzet lassítja a fejlesztést, növeli a hibák számát és ronthatja a fejlesztői élményt. De ne aggódj, a Docker a megoldás!

A Docker a Megoldás Kulcsa: Izoláció és Hordozhatóság

A Docker forradalmasította a szoftverfejlesztést és -telepítést azáltal, hogy lehetővé tette alkalmazások és azok függőségeinek konténerekbe való csomagolását. Egy konténer egy könnyűsúlyú, önálló, futtatható szoftvercsomag, amely mindent tartalmaz, amire az alkalmazásnak szüksége van a futáshoz: kód, futásidejű környezet, rendszereszközök, könyvtárak és beállítások.

Ennek a megközelítésnek az előnye, hogy a konténer mindig ugyanúgy fog viselkedni, függetlenül attól, hogy milyen környezetben fut. Íme, miért tökéletes a Docker a PHP verziók problémájának megoldására:

  • Izoláció: Minden PHP verzió a saját konténerében fut, teljesen elszigetelve a többi PHP verziótól és a hoszt rendszertől. Nincsenek ütközések!
  • Hordozhatóság: A Docker konténerek és konfigurációk (pl. docker-compose.yml) platformfüggetlenek. Ami az egyik gépen fut, az a másikon is működni fog.
  • Egyszerűség: Könnyedén elindíthatsz, leállíthatsz és törölhetsz konténereket. Nincs szükség bonyolult telepítési vagy eltávolítási folyamatokra.
  • Verziókövetés: A Dockerfile-ok és a Docker Compose fájlok verziókövethetők (pl. Git-tel), így a fejlesztői környezet is a projekt része lesz.

Docker Alapok: Egy Gyors Ismétlés

Mielőtt belemerülnénk a több PHP verzió konfigurálásába, elevenítsünk fel néhány alapvető Docker fogalmat:

  • Image (Kép): Egy sablon, amely tartalmazza az alkalmazás futtatásához szükséges mindent. Például a php:8.2-fpm egy kép.
  • Container (Konténer): Egy kép futó példánya. Ezt indítjuk el, állítjuk le.
  • Dockerfile: Egy szkript, amely leírja, hogyan építsünk fel egy egyedi képet.
  • Volume (Kötet): Lehetővé teszi a hoszt gép és a konténer közötti fájlmegosztást, így a konténer törlésekor sem vesznek el az adatok.
  • Network (Hálózat): Lehetővé teszi a konténerek közötti kommunikációt.

Első Lépések: Egyedi PHP Konténerek

A legegyszerűbb módja egy PHP verzió futtatásának Dockerrel, ha elindítunk egy PHP-FPM (FastCGI Process Manager) konténert. Az FPM a PHP egy implementációja, amely külső web szerverekkel (pl. Nginx, Apache) való hatékony kommunikációra van optimalizálva.

Próbáljuk ki a PHP 8.2-t:

docker run --name my-php82 -p 9000:9000 -v $(pwd)/src:/var/www/html php:8.2-fpm-alpine

Ez a parancs:

  • Letölti a php:8.2-fpm-alpine képet (ha még nincs meg).
  • Elindít belőle egy konténert my-php82 néven.
  • A 9000-es portot a hoszt gépről a konténer 9000-es portjára irányítja.
  • A jelenlegi könyvtárban lévő src mappát a konténerben lévő /var/www/html mappába csatolja (volume mount).

Most már fut a PHP 8.2 FPM szerver. De hogyan kérdezhetjük le? Ehhez kell egy web szerver, ami továbbítja a kéréseket az FPM-nek. Itt jön képbe a Docker Compose.

A Nagy Fegyver: Docker Compose – Több Szolgáltatás Egyszerre

Amikor több konténerrel dolgozunk együtt (például Nginx, több PHP-FPM verzió, adatbázis), a docker run parancsok kezelése gyorsan áttekinthetetlenné válik. Erre nyújt elegáns megoldást a Docker Compose. Egyetlen YAML fájlban (docker-compose.yml) leírhatjuk az egész alkalmazásunk szolgáltatásait, azok függőségeit és konfigurációját.

Hozzuk létre a következő könyvtárszerkezetet:

my-multi-php-project/
├── docker-compose.yml
├── nginx/
│   └── default.conf
└── src/
    ├── php74-info.php
    └── php82-info.php

Első lépés: Egy Nginx és egy PHP-FPM szolgáltatás

Kezdjük egy egyszerű konfigurációval, ahol egy Nginx és egy PHP 8.2-FPM konténer fut.
Hozd létre a docker-compose.yml fájlt a gyökérkönyvtárban:

# docker-compose.yml
version: '3.8'

services:
  nginx:
    image: nginx:stable-alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
      - ./src:/var/www/html
    depends_on:
      - php82-fpm # Az Nginx függ a PHP 8.2 FPM-től
    networks:
      - app-network

  php82-fpm:
    image: php:8.2-fpm-alpine
    volumes:
      - ./src:/var/www/html
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Most pedig az Nginx konfigurációja. Hozd létre az nginx/default.conf fájlt:

# nginx/default.conf
server {
    listen 80;
    index index.php index.html;
    root /var/www/html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ .php$ {
        fastcgi_pass php82-fpm:9000; # Ez a sor a kulcs!
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

Indítsuk el: docker-compose up -d.
Hozd létre a src/index.php fájlt egy egyszerű phpinfo(); paranccsal, és látnod kellene a PHP 8.2-es információkat a böngésződben a localhost címen.

Több PHP Verzió Hozzáadása

Most jön a lényeg! Bővítsük a docker-compose.yml fájlunkat egy PHP 7.4-es szolgáltatással. A célunk az, hogy az Nginx a kérés URL-jétől függően más-más PHP FPM-hez irányítsa a kéréseket. Például a php74.localhost a PHP 7.4-et, a php82.localhost pedig a PHP 8.2-t használja.

Módosítsuk a docker-compose.yml fájlt:

# docker-compose.yml (Kibővített verzió)
version: '3.8'

services:
  nginx:
    image: nginx:stable-alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
      - ./src:/var/www/html # A közös kód
    depends_on:
      - php74-fpm
      - php82-fpm
    networks:
      - app-network

  php74-fpm:
    image: php:7.4-fpm-alpine
    volumes:
      - ./src:/var/www/html
    networks:
      - app-network

  php82-fpm:
    image: php:8.2-fpm-alpine
    volumes:
      - ./src:/var/www/html
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Láthatod, hogy most már két PHP-FPM szolgáltatásunk van, mindegyik a saját verziójával. Fontos, hogy mindkettő ugyanazt a ./src mappát csatolja a /var/www/html útvonalra, így a kódunk megosztott marad.

Nginx Konfiguráció a Több PHP Verzió Kezeléséhez

Az Nginx konfigurációja a kulcsa annak, hogy a bejövő kéréseket a megfelelő PHP-FPM konténerhez irányítsuk. Ezt több módon is megtehetjük:

  1. Subdomain (aldomain) alapján: Pl. php74.projekt.test és php82.projekt.test.
  2. URL útvonal alapján: Pl. projekt.test/php74/ és projekt.test/php82/.
  3. Szerver port alapján: Kevésbé rugalmas, de lehetséges.

A leggyakoribb és legtisztább módszer az aldomain alapú megközelítés. Ehhez módosítanod kell a hoszt géped hosts fájlját (Linux/macOS: /etc/hosts, Windows: C:WindowsSystem32driversetchosts), hogy a php74.localhost és php82.localhost is a 127.0.0.1-re mutasson:

127.0.0.1       localhost
127.0.0.1       php74.localhost
127.0.0.1       php82.localhost

Most módosítsuk az nginx/default.conf fájlt, hogy két különböző virtuális szervert definiáljunk, mindegyik a saját fastcgi_pass irányításával:

# nginx/default.conf (Kibővített verzió)
upstream php74 {
    server php74-fpm:9000;
}

upstream php82 {
    server php82-fpm:9000;
}

server {
    listen 80;
    server_name php74.localhost; # Virtuális szerver a PHP 7.4-hez
    root /var/www/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ .php$ {
        fastcgi_pass php74; # Itt adjuk meg a PHP 7.4 FPM-et
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

server {
    listen 80;
    server_name php82.localhost; # Virtuális szerver a PHP 8.2-höz
    root /var/www/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ .php$ {
        fastcgi_pass php82; # Itt adjuk meg a PHP 8.2 FPM-et
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

Ne felejtsd el újraindítani a konténereket a módosítások után: docker-compose down && docker-compose up -d.
Most hozz létre két fájlt a src mappában:

  • src/php74-info.php tartalommal: <?php phpinfo();
  • src/php82-info.php tartalommal: <?php phpinfo();

Látogass el a böngésződben a http://php74.localhost/php74-info.php és http://php82.localhost/php82-info.php címekre. Látnod kell, hogy az Nginx sikeresen továbbította a kéréseket a megfelelő PHP-FPM szolgáltatásnak, és különböző PHP verzióinformációkat kapsz! Sikerült egyszerre két különböző PHP verziót futtatni!

Adatbázisok és Egyéb Szolgáltatások Hozzáadása

A Docker Compose ereje abban rejlik, hogy könnyedén adhatsz hozzá más szolgáltatásokat is a fejlesztői környezetedhez. Például egy MySQL adatbázist:

# ... (előző docker-compose.yml kiegészítése)
services:
  # ... nginx, php74-fpm, php82-fpm szolgáltatások
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: my_database
    volumes:
      - db_data:/var/lib/mysql # Perzisztens adatmentéshez
    networks:
      - app-network

volumes:
  db_data: # Adatbázis kötet definíciója

A konténerek az azonos hálózaton belül (app-network) név alapján tudnak kommunikálni egymással. Például a PHP konténerek a mysql hostname-t használva érik el az adatbázist.

A Projekt Kódjának Megosztása

A volumes: - ./src:/var/www/html sor biztosítja, hogy a hoszt gépeden lévő src mappa tartalma valós időben elérhető legyen a konténerek /var/www/html útvonalán. Ez kulcsfontosságú a fejlesztés során, hiszen bármilyen változtatás, amit a hoszt gépen eszközölsz, azonnal megjelenik a konténerekben anélkül, hogy újra kellene építened vagy újraindítanod őket.

Függőségek Kezelése: Composer Dockerben

A PHP projektek függőségeit a Composer kezeli. Ahelyett, hogy a Composert a hoszt gépedre telepítenéd, ajánlott a konténeren belül futtatni. Így biztosítod, hogy a függőségek pontosan az adott PHP verzióhoz és környezethez legyenek telepítve.

Például, ha a PHP 8.2-es projektedhez szeretnél függőségeket telepíteni:

docker-compose run --rm php82-fpm composer install

Ez a parancs:

  • Elindít egy ideiglenes konténert a php82-fpm szolgáltatásból.
  • Futtatja benne a composer install parancsot.
  • A --rm flag gondoskodik arról, hogy a konténer automatikusan törlődjön a parancs befejezése után.

Ugyanezt megteheted a PHP 7.4-es projekteddel is, egyszerűen a php82-fpm helyett php74-fpm-et írva.

Fejlesztési Környezet Optimalizálása

A Docker alapú fejlesztői környezet tovább optimalizálható:

  • XDebug: Beállíthatod az XDebug-ot az egyes PHP-FPM konténerekben. Ehhez általában egyedi Dockerfile-okra van szükség, amelyek telepítik az XDebug bővítményt és konfigurálják azt a megfelelő portra. Mivel minden PHP FPM konténer külön fut, mindegyiknek lehet saját XDebug konfigurációja.
  • .env fájlok: A környezeti változókat (pl. adatbázis hozzáférések) kezelheted egy .env fájlban a docker-compose.yml mellett. A Docker Compose automatikusan betölti ezeket a változókat a konténerekbe.
  • Named volumes: Adatbázisokhoz, logfájlokhoz érdemes elnevezett köteteket (named volumes) használni a perzisztens tároláshoz, így a konténer törlésekor sem vesznek el az adatok.
  • Healthchecks: A docker-compose.yml-ben beállíthatsz egészségellenőrzéseket (healthchecks), amelyek segítségével a Docker figyeli, hogy egy szolgáltatás (pl. PHP-FPM) valóban működőképes-e.

Gyakori Problémák és Megoldások

  • Portkonfliktusok: Ha a hoszt gépeden már fut valami a 80-as vagy 9000-es porton, a Docker nem tudja használni azt. Módosítsd a docker-compose.yml-ben a portleképezést (pl. 8080:80 az Nginx-nél, vagy 9001:9000 a PHP-FPM-nél).
  • Kötet engedélyek: Gyakori probléma, hogy a konténerben futó felhasználónak nincs írási/olvasási joga a csatolt kötetekre. Ezt a Dockerfile-ban vagy a docker-compose.yml-ben lehet kezelni, beállítva a megfelelő felhasználó (pl. www-data) UID/GID-jét.
  • Hálózati problémák: Győződj meg róla, hogy minden szolgáltatás ugyanazon a Docker hálózaton van (pl. app-network), és a szolgáltatásnevek (pl. php82-fpm) helyesen vannak használva a fastcgi_pass irányításban.
  • Debugging: Használd a docker-compose logs -f <service_name> parancsot a konténerek naplóinak valós idejű megtekintéséhez. A docker-compose exec <service_name> bash paranccsal beléphetsz egy futó konténerbe hibakeresés céljából.

Előnyök Összefoglalása

A több PHP verzió futtatása Dockerrel számos előnnyel jár:

  • Nagyobb produktivitás: Kevesebb időt töltesz környezeti problémák megoldásával, többet a fejlesztéssel.
  • Stabilitás és konzisztencia: A fejlesztői, teszt- és akár a produkciós környezet is azonos lehet, minimalizálva az „az én gépemen működik” szituációkat.
  • Könnyű onboarding: Az új csapattagok pillanatok alatt be tudják állítani a fejlesztői környezetet.
  • Jövőállóság: Könnyedén frissíthetsz vagy válthatsz PHP verziót anélkül, hogy a meglévő projekteket érintené.
  • Robusztus tesztelés: Lehetővé teszi, hogy különböző PHP verziókon tesztelj, biztosítva a széles körű kompatibilitást.

Konklúzió

A Docker egy rendkívül erős eszköz, amely gyökeresen megváltoztatja a PHP fejlesztői környezet kezelését. Azáltal, hogy képesek vagyunk egyszerre több PHP verziót izolált konténerekben futtatni, búcsút inthetünk a verziókonfliktusok okozta fejfájásoknak és jelentősen növelhetjük a hatékonyságunkat. A docker-compose pedig tovább egyszerűsíti a több szolgáltatásból álló alkalmazások konfigurálását és menedzselését.

Ne habozz belevágni! A kezdeti tanulási görbe megéri a befektetést, hiszen hosszú távon sok időt és energiát takaríthatsz meg. Fedezd fel a Docker nyújtotta szabadságot, és építs olyan fejlesztői környezetet, amely valóban támogatja a munkádat, nem pedig hátráltatja! Vágj bele még ma, és élvezd a tiszta, hatékony és rugalmas PHP fejlesztést!

Leave a Reply

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük