Blog

Infrastruktúra 9 perc olvasás

Docker for PHP élesben: gyakorlati beállítási útmutató üzleti alkalmazásokhoz

Docker a PHP alkalmazásokat ugyanúgy futtatja laptopon, tesztelésben és élesben, és a kiadások és visszaállítások rutinszerűvé teszik a stressz helyett. Mozgó alkatrészeket is ad hozzá, és a gondatlan beállítás rosszabb, mint egy sima szerver. Ez az útmutató bemutatja a gyártásra kész kiindulási helyzetet valós konfigurációval, és azt, hogy mikor nem kell bajlódnia.

Borítókép: Docker for PHP élesben: gyakorlati beállítási útmutató üzleti alkalmazásokhoz

Röviden

  • Docker megéri, ha azonos környezetre, gyors visszaállításra és egyszerű beépítésre vágyik. Egyetlen kis brosúraoldal esetében a megosztott tárhelyről általában szükségtelen.
  • Készítsen változatlan képet a CI-ben: többlépcsős összeállítás, csak éles függőségek, nem root felhasználó, OPcache bekapcsolva, hibák naplózva és soha nem jelennek meg.
  • Képcímke által történő kiadás (a Git commit hash), ellenőrizze az állapotot az indítás után, és automatikusan visszalépjen az előző címkére, ha az ellenőrzés sikertelen.
  • A tárolók eldobhatók, az adatok nem: tartsa meg az adatbázist és a feltöltéseket kötetekben vagy felügyelt szolgáltatásokban, és készítsen biztonsági másolatot Docker kívül.
  • A leggyakoribb gyártási hibák: titkok a képben, közzétett adatbázis-portok, korlátlan naplók és php-fpm korlátok, amelyek nem egyeznek a memóriával.

Sok üzleti alkalmazás esetében a hosting valódi költségét nem a szerver, hanem az emberek jelentik. Hosszú távon költségesek az olyan beállítások, amelyeket csak egy fejlesztő ért, a kézi FTP-n keresztül történő telepítés és az élestől eltérően viselkedő átmeneti környezet. A konténerek ezt úgy oldják meg, hogy becsomagolják az alkalmazást a pontos PHP verzióval és bővítményekkel. Saját PHP webhelyeinket és kliensrendszereinket Docker-alapú veremben futtatjuk, és ez az útmutató leírja, hogy miből indulunk ki.

Mikor éri meg Docker, és mikor nem

  • Megéri: több szolgáltatás (web, PHP, adatbázis, sor), több fejlesztő, megismételhető kiadások és gyors visszaállítások igénye, vagy a szolgáltatók közötti váltás terve.
  • Nem szükséges: egy egyszerű tartalmi webhely, amely ritkán változik felügyelt tárhely esetén. A megnövelt komplexitás megtérülést igényel.
  • Nem helyettesíti a jó műveleteket: továbbra is szükség van javításra, biztonsági mentésre és felügyeletre. Tekintse meg biztonsági mentési és megfigyelési útmutatónkat.

A cél architektúra

Szilárd, egyszerű beállítás egy PHP alkalmazáshoz egy szerveren:

  • Fordított proxy és TLS a szélén ( Nginx vagy Caddy a gazdagépen, vagy CDN, például Cloudflare, lásd Cloudflare beállítási útmutatónkat).
  • Webtároló ( Nginx), amely statikus fájlokat szolgál ki, és PHP kéréseket továbbít.
  • PHP-FPM tároló a kódjával, a képbe beépítve.
  • Adatbázis a saját tárolójában állandó kötettel, vagy jobb esetben egy felügyelt adatbázis-szolgáltatás a kritikus adatokhoz.
  • Csak olyan adatok kötetei, amelyeknek életben kell maradniuk: adatbázisfájlok és felhasználói feltöltések.

Többlépcsős Dockerfile

A többlépcsős összeállítás egy szakaszban telepíti a függőségeket, és csak az eredményt másolja át egy vékony futásidejű képfájlba. A végső kép nem tartalmaz Composer, fordítókat vagy teszteszközöket, ami kisebbé teszi, és kevesebbet használhatnak a támadók:

# ---- stage 1: PHP dependencies ----
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --prefer-dist --no-interaction --optimize-autoloader

# ---- stage 2: runtime ----
FROM php:8.3-fpm-alpine

RUN apk add --no-cache icu-libs libzip \
 && apk add --no-cache --virtual .build icu-dev libzip-dev $PHPIZE_DEPS \
 && docker-php-ext-install -j"$(nproc)" pdo_mysql intl zip opcache \
 && apk del .build

COPY docker/php.ini  /usr/local/etc/php/conf.d/zz-app.ini
COPY docker/www.conf /usr/local/etc/php-fpm.d/zz-www.conf

WORKDIR /var/www/app
COPY --from=vendor /app/vendor ./vendor
COPY --chown=www-data:www-data . .

USER www-data
EXPOSE 9000

Szándékosan válassza ki a PHP verziót, és ellenőrizze, hogy továbbra is támogatott-e. A PHP 8 frissítési útmutatónk elmagyarázza, hogyan kell ezt megtervezni. Rögzítse az alapképek verzióit, és ütemezetten frissítse őket, mivel a soha újra nem épített képfájlok ismert sebezhetőségeket halmoznak fel. Tartson egy .dockerignore amely kizárja .git, .env, teszteket és helyi adatokat, így semmi érzékeny nem kerül a képbe.

Gyártási PHP és php-fpm konfiguráció

# docker/php.ini
expose_php = 0
display_errors = 0
log_errors = 1
memory_limit = 256M
upload_max_filesize = 10M
post_max_size = 12M

opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 0   ; the code in an image never changes while it runs

# docker/www.conf
[www]
pm = dynamic
pm.max_children = 12
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 500
request_terminate_timeout = 30s
catch_workers_output = yes
decorate_workers_output = no

opcache.validate_timestamps = 0 beállítása biztosítja a legjobb teljesítményt egy megváltoztathatatlan kép esetén, de ez csak akkor működik, ha soha nem szerkeszt fájlokat egy futó tárolóban: helyette új képet ad ki. Mérje meg a készletet valós számokból: mérje meg egy PHP munkás átlagos memóriáját terhelés alatt, döntse el, mennyi memóriát használhat PHP a szerveren, és ossza el. Ha egy dolgozó 60 MB-ot használ, és 1 GB-ot tudsz adni PHP, akkor pm.max_children körülbelül 16. Ha sokkal magasabbra állítod, akkor a forgalom kiugrása során a szerver csere vagy a kernel leállítása következik be. Túl alacsony, és a kérések sorba állnak. Ellenőrizze a php-fpm naplóban a "max_children reach" figyelmeztetéseket.

Egy Compose fájl a megfelelő alapértelmezett értékekkel

x-logging: &default-logging
  driver: json-file
  options: { max-size: "10m", max-file: "5" }     # logs cannot fill the disk

services:
  web:
    image: ghcr.io/your-org/app-web:${TAG}
    ports: ["127.0.0.1:8080:80"]                  # only the local reverse proxy can reach it
    depends_on: [php]
    restart: unless-stopped
    logging: *default-logging
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1/health.php"]
      interval: 15s
      timeout: 3s
      retries: 3

  php:
    image: ghcr.io/your-org/app:${TAG}
    env_file: .env                                 # secrets stay on the server, not in the image
    restart: unless-stopped
    read_only: true
    tmpfs: [/tmp]
    mem_limit: 512m
    volumes: [uploads:/var/www/app/storage/uploads]
    logging: *default-logging

  db:
    image: mysql:8.4
    env_file: .env.db
    restart: unless-stopped
    volumes: [db_data:/var/lib/mysql]              # no "ports:" - the database is not public
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
      interval: 15s
      retries: 5
    logging: *default-logging

volumes:
  uploads:
  db_data:

A web egy kis Nginx kép, amelybe be van másolva public/ mappája és a webhely konfigurációja, és ugyanabban a folyamatban van beépítve, mint a PHP kép. Főbb pontok: kösse össze a közzétett portokat 127.0.0.1 hez, soha ne tegye közzé az adatbázist, állítson be újraindítási házirendeket, korlátozza a memóriát, hogy egyetlen tároló ne tudja levenni a gazdagépet, és korlátozza a naplóméretet. Ne feledje, hogy Docker által közzétett portok megkerülhetik a gazdagép tűzfalszabályait, amint azt a Cloudflare útmutatóban is elmagyarázzuk. Soha ne szerelje be a Docker foglalatot egy alkalmazástárolóba, mert ez biztosítja a tároló vezérlését a gazdagép felett.

Kiadások és visszaállítások

A képalapú beállítás legjobb tulajdonsága, hogy minden kiadás egy címke, a visszaállítás pedig az "előző címke indítása". Jelölje meg a képeket a Git commit hash-sel, soha ne hagyatkozzon a latest, és állítsa be a kiadási szkriptet az állapot ellenőrzésére:

#!/usr/bin/env bash
# /srv/app/release.sh <git-sha>
set -euo pipefail
TAG="${1:?usage: release.sh <git-sha>}"
cd /srv/app
PREV="$(cat .current_tag 2>/dev/null || true)"

export TAG
docker compose pull php web
docker compose up -d --no-deps php web

for i in $(seq 1 30); do
  if curl -fsS http://127.0.0.1:8080/health.php > /dev/null; then
    echo "$TAG" > .current_tag
    echo "healthy: $TAG"; exit 0
  fi
  sleep 2
done

echo "unhealthy after release, rolling back to ${PREV:-none}" >&2
if [ -n "$PREV" ]; then TAG="$PREV" docker compose up -d --no-deps php web; fi
exit 1

Az adatbázis-módosítások körültekintést igényelnek: írjon migrációt, hogy a kód előző verziója továbbra is működjön az új sémával (először adjon hozzá oszlopokat, majd távolítsa el őket egy későbbi kiadásban). Ez az, ami biztonságossá teszi a gyors visszaállítást. Készítsen adatbázis biztonsági másolatot minden olyan kiadás előtt, amely módosítja a sémát.

Építés és szállítás a CI-től

Egyszer készítse el a képet a CI-ben, és telepítse pontosan azt a műterméket. Egy minimális GitHub Actions munkafolyamat:

name: build-and-release
on:
  push:
    branches: [main]
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ghcr.io/your-org/app:${{ github.sha }}
      - name: Release over SSH
        env:
          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
        run: |
          install -m 600 /dev/null key && echo "$DEPLOY_KEY" > key
          ssh -i key -o StrictHostKeyChecking=accept-new deploy@your-server "/srv/app/release.sh ${{ github.sha }}"

Futtassa le a teszteket és a statikus elemzést ugyanabban a folyamatban a lemezkép felépítése előtt, és használjon olyan telepítési kulcsot, amely csak a kiadási parancsfájlt tudja futtatni. Adjon hozzá egy kép sebezhetőségi vizsgálatát, ha kockázati profilja ezt megköveteli.

Naplók, adatok és biztonság

  • A naplók az stdout és az stderr mappába kerülnek, Docker forgatja őket, és minden fontos dolog esetén egy központi helyre szállítják, hogy túléljék a tárolót.
  • Az adatok a tárolón kívül élnek. A kötet nem tartalék. Használja a biztonsági mentési útmutatónkban található megközelítést: titkosított, külső, visszaállítással tesztelt.
  • A titkok soha nem sülnek bele képekbe. Futás közben vigye át őket env-fájlokon vagy egy titokkezelőn keresztül, és tartsa távol őket a Gittől.
  • Futtasson nem root felhasználóként, használjon csak olvasható fájlrendszert, ahol lehetséges, és dobja el azt, amire nincs szüksége.
  • Tartsa frissen a képeket. Rendszeresen építse újra, hogy az alapkép és PHP biztonsági javításait vegye fel.
  • Alkalmazza a PHP biztonsági ellenőrzőlistánk alkalmazásszintű vezérlőit, mivel a tárolók nem javítják a nem biztonságos kódot.

Gyártási készenléti ellenőrző lista

  1. Többlépcsős kép csak éles függőséggel, rögzített alapkép, nem root felhasználó.
  2. OPcache engedélyezve, a naplózott hibák nem jelennek meg, php-fpm méret a mért memóriából.
  3. Fájl létrehozása újraindítási házirendekkel, állapotellenőrzéssel, memóriakorlátokkal, naplóforgatással és nyilvános adatbázis-port nélkül.
  4. Kiadások commit-hash címkével, automatikus állapotellenőrzéssel és visszaállítással.
  5. Biztonsági mentések és tesztelt visszaállítás az adatbázishoz és a feltöltéshez.
  6. Monitoring és riasztások állapotról, lemezről, hibákról és tanúsítványokról.

Hogyan segíthetünk

Konténerbe helyezzük PHP alkalmazásokat, beállítjuk a CI-folyamatokat és kiadásokat, és összekapcsoljuk őket a fizetésekkel, a CRM-mel és az üzenetkezeléssel. Tekintse meg integrációs szolgáltatásunkat, vagy foglaljon telefonhívást, és felülvizsgáljuk a jelenlegi tárhely- és kiadási folyamatát.

Gyakori kérdések

Docker alkalmas PHP éles futtatására?

Igen, ha jól használják. Azonos környezeteket, megismételhető kiadásokat és gyors visszaállításokat biztosít. Megfelelő konfigurációt igényel: változtathatatlan képek, állapotellenőrzések, erőforráskorlátok, naplózás, titkok kezelése és a tárolón kívüli adatok biztonsági mentése.

Az adatbázisnak Docker kell futnia éles környezetben?

Kis és közepes rendszerek esetén is használható, ha állandó kötetet használ, soha nem teszik közzé nyilvánosan, és tesztelték a biztonsági másolatokat. A kritikus adatokhoz sok csapat a felügyelt adatbázis-szolgáltatást részesíti előnyben, amely kezeli a feladatátvételt, a frissítéseket és a biztonsági mentéseket.

Hogyan állíthatok vissza egy Docker kiadást?

Minden képhez jelölje meg a Git commit hash-t, és tartsa meg az előző címkét. A visszaállításhoz indítsa el a tárolókat az előző címkével. Írjon adatbázis-áttelepítéseket, hogy a régebbi kód továbbra is működjön az újabb sémával.

Hány php-fpm dolgozót kell beállítani?

Mérje meg egy dolgozó átlagos memóriáját terhelés alatt, döntse el, mennyi memóriát használhat PHP, és ossza fel. A túl magas érték cserét, míg a túl alacsony érték sorban állást okoz. Nézze meg a php-fpm naplót a max_children figyelmeztetésekért.

Mi a legnagyobb Docker biztonsági hiba a PHP alkalmazásokkal?

Titkok elhelyezése a képben vagy a Gitben és az adatbázis-portok közzététele az interneten. Kerülje továbbá a root felhasználóként való futtatást, a Docker foglalat konténerekbe való beszerelését és az alapkép frissítését.

Ingyenes felfedező hívás

Hozzon kaotikus stacket vagy elakadt integrációt - az Integrono feltérképezi a legokosabb első lépést.

Senior rálátást kap a költségvetési csapdákra, a függőségekre és arra, hogy vásároljon, ragasszon vagy építsen - mielőtt a fizetett munka elindul. A CEO a körben marad.