Blog

Infraštruktúra 9 min čítania

Docker pre PHP vo výrobe: praktický sprievodca nastavením pre podnikové aplikácie

Docker umožňuje, aby aplikácia PHP bežala rovnakým spôsobom na prenosnom počítači, pri testovaní a vo výrobe, a namiesto stresu robí rutinné vydania a návraty. Pridáva tiež pohyblivé časti a neopatrné nastavenie je horšie ako obyčajný server. Táto príručka ukazuje základnú líniu pripravenú na výrobu so skutočnou konfiguráciou a kedy by ste sa nemali obťažovať.

Ilustrácia článku: Docker pre PHP vo výrobe: praktický sprievodca nastavením pre podnikové aplikácie

V skratke

  • Docker stojí za to, keď chcete rovnaké prostredia, rýchle vrátenie späť a jednoduché začlenenie. Pre jednu malú brožúru na zdieľanom hostingu je to zvyčajne zbytočné.
  • Vytvorte nemenný obraz v CI: viacstupňová zostava, iba produkčné závislosti, používateľ bez oprávnenia root, zapnutá OPcache, chyby sa zaznamenávajú a nikdy sa nezobrazujú.
  • Uvoľnite pomocou značky obrázka (hash commit Git), po spustení skontrolujte stav a v prípade zlyhania kontroly sa automaticky vráťte k predchádzajúcej značke.
  • Kontajnery sú na jedno použitie, údaje nie: uchovávajte databázu a nahrávané súbory vo zväzkoch alebo spravovaných službách a zálohujte ich mimo Docker.
  • Najčastejšie chyby pri výrobe: tajomstvá v obraze, zverejnené databázové porty, neobmedzené protokoly a limity php-fpm, ktoré nezodpovedajú pamäti, ktorú máte.

Pri mnohých podnikových aplikáciách skutočnými nákladmi na hosting nie je server, ale ľudia. Nastavenie, ktorému rozumie iba jeden vývojár, nasadenie vykonávané ručne cez FTP a pracovné prostredie, ktoré sa správa inak ako produkčné, sú z dlhodobého hľadiska drahé. Kontajnery to riešia balením aplikácie s jej presnou verziou PHP a rozšíreniami. Prevádzkujeme naše vlastné stránky PHP a klientske systémy na zásobníku založenom na Dockeri a táto príručka popisuje základnú líniu, z ktorej vychádzame.

Kedy sa Docker oplatí a kedy nie

  • Stojí za to: niekoľko služieb (web, PHP, databáza, front), viac ako jeden vývojár, potreba opakovateľných vydaní a rýchlych návratov alebo plán prechodu medzi poskytovateľmi.
  • Nie je potrebné: jednoduchý obsahový web, ktorý sa na spravovanom hostingu len zriedka mení. Pridaná zložitosť si vyžaduje odplatu.
  • Nie je náhradou za dobré operácie: stále potrebujete opravy, zálohy a monitorovanie. Pozrite si nášho sprievodcu zálohovaním a monitorovaním.

Cieľová architektúra

Pevné a jednoduché nastavenie pre aplikáciu PHP na jednom serveri:

  • Reverzný proxy a TLS na okraji ( Nginx alebo Caddy na hostiteľovi alebo CDN, ako je Cloudflare, pozrite si nášho sprievodcu nastavením Cloudflare).
  • Webový kontajner ( Nginx), ktorý obsluhuje statické súbory a prenáša požiadavky PHP ďalej.
  • PHP-FPM kontajner s vaším kódom zabudovaným do obrazu.
  • Databáza vo vlastnom kontajneri s trvalým objemom, alebo lepšie riadená databázová služba pre kritické dáta.
  • Objemy len pre údaje, ktoré musia prežiť: databázové súbory a nahrané súbory používateľov.

Viacstupňový súbor Dockerfile

Viacstupňová zostava nainštaluje závislosti v jednej fáze a skopíruje iba výsledok do tenkého runtime obrazu. Konečný obrázok nemá žiadny Composer, kompilátory ani testovacie nástroje, čo ho robí menším a útočníkom umožňuje menej použitia:

# ---- 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

Zámerne si vyberte verziu PHP a skontrolujte, či je stále podporovaná. Náš sprievodca inováciou PHP 8 vysvetľuje, ako to naplánovať. Pripnite verzie základných obrázkov a aktualizujte ich podľa plánu, pretože obrázok, ktorý nikdy neprebudujete, hromadí známe zraniteľnosti. Udržujte .dockerignore, ktorý vylučuje .git, .env, testy a lokálne údaje, takže v obraze neskončí nič citlivé.

Produkcia PHP a konfigurácia php-fpm

# 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

Nastavenie opcache.validate_timestamps = 0 poskytuje najlepší výkon pre nemenný obrázok, ale funguje to iba vtedy, ak nikdy neupravujete súbory v spustenom kontajneri: namiesto toho uvoľníte nový obrázok. Veľkosť skupiny z reálnych čísel: zmerajte priemernú pamäť jedného pracovníka PHP pri zaťažení, rozhodnite sa, koľko pamäte môže PHP použiť na serveri, a rozdeľte. Ak pracovník používa 60 MB a vy môžete dať PHP 1 GB, pm.max_children je približne 16. Nastavenie oveľa vyššie spôsobí, že proces výmeny servera alebo proces zabíjania jadra počas špičky prevádzky. Príliš nízka a fronta žiadostí. Skontrolujte protokol php-fpm, či neobsahuje upozornenia „max_children reach“.

Vytvoriť súbor so správnymi predvolenými hodnotami

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:

web obrázok je malý obrázok Nginx so skopírovaným public/ priečinkom a konfiguráciou lokality, ktorý je zabudovaný v rovnakom postupe ako obrázok PHP. Kľúčové body: naviazať publikované porty na 127.0.0.1, nikdy nepublikovať databázu, nastaviť politiky reštartovania, obmedziť pamäť, aby jeden kontajner nemohol odstrániť hostiteľa, a obmedziť veľkosť protokolu. Pamätajte, že porty publikované Docker môžu obísť pravidlá brány firewall hostiteľa, ako vysvetľujeme v príručke Cloudflare. Nikdy nepripájajte zásuvku Docker do kontajnera aplikácie, pretože to dáva tomuto kontajneru kontrolu nad hostiteľom.

Uvoľnenia a návraty

Najlepšou vlastnosťou nastavenia založeného na obrázkoch je, že každé vydanie je značka a vrátenie je „začať predchádzajúcu značku“. Označte obrázky pomocou hash odovzdania Git, nikdy sa nespoliehajte na latest a nechajte skript vydania overiť stav:

#!/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

Zmeny databázy vyžadujú starostlivosť: migrácie zapíšte, aby predchádzajúca verzia kódu stále fungovala s novou schémou (najprv pridajte stĺpce, odstráňte ich v neskoršom vydaní). Práve to robí rýchly návrat bezpečným. Pred každým vydaním, ktoré zmení schému, urobte zálohu databázy.

Stavba a doprava z CI

Zostavte obraz raz v CI a nasaďte presne tento artefakt. Minimálny pracovný postup GitHub Actions:

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 }}"

Spustite svoje testy a statickú analýzu v rovnakom kanáli pred vytvorením obrazu a použite kľúč nasadenia, ktorý dokáže spustiť iba skript vydania. Ak to váš rizikový profil vyžaduje, pridajte skenovanie zraniteľnosti obrázkov.

Protokoly, údaje a bezpečnosť

  • Záznamy idú na stdout a stderr, sú rotované Docker a pre čokoľvek dôležité sú odoslané na centrálne miesto, aby prežili kontajner.
  • Dáta žijú mimo kontajnera. Zväzok nie je záloha. Použite prístup v našom sprievodcovi zálohovaním: šifrované, mimo lokality, testované na obnovenie.
  • Tajomstvá sa nikdy nespracúvajú do obrázkov. Odovzdávajte ich za behu prostredníctvom súborov env alebo správcu tajomstiev a uchovávajte ich mimo Gitu.
  • Spustite ako užívateľ typu non-root, používajte súborový systém len na čítanie tam, kde je to možné, a zahoďte to, čo nepotrebujete.
  • Udržujte obrázky čerstvé. Pravidelne prestavujte, aby ste získali bezpečnostné opravy v základnom obraze a PHP.
  • Použite ovládacie prvky na úrovni aplikácie z nášho kontrolného zoznamu zabezpečenia PHP, pretože kontajnery neopravujú nezabezpečený kód.

Kontrolný zoznam pripravenosti výroby

  1. Viacstupňový obrázok iba s produkčnými závislosťami, pripnutý základný obrázok, používateľ bez oprávnenia root.
  2. OPcache povolená, zaznamenané chyby sa nezobrazujú, veľkosť php-fpm z nameranej pamäte.
  3. Vytvorte súbor s politikami reštartu, zdravotnými kontrolami, limitmi pamäte, rotáciou protokolov a žiadnym verejným databázovým portom.
  4. Vydania pomocou tagu commit-hash s automatickou kontrolou stavu a návratom späť.
  5. Zálohy a testované obnovenie databázy a nahrávania.
  6. Monitorovanie a upozornenia na zdravie, disk, chyby a certifikáty.

Ako môžeme pomôcť

Kontajnerizujeme aplikácie PHP, nastavujeme kanály a vydania CI a prepájame ich s platbami, CRM a správami. Pozrite si našu integračnú službu alebo si rezervujte hovor a my skontrolujeme váš aktuálny proces hosťovania a vydania.

Časté otázky

Je Docker dobrý na spustenie PHP vo výrobe?

Áno, pri dobrom použití. Poskytuje identické prostredia, opakovateľné vydania a rýchle návraty. Potrebuje správnu konfiguráciu: nemenné obrázky, kontroly stavu, limity zdrojov, rotáciu protokolov, správu tajomstiev a zálohy údajov mimo kontajnera.

Mala by databáza bežať v Docker vo výrobe?

Môže to byť pre malé a stredné systémy, ak používa trvalý zväzok, nikdy nie je verejne prístupný a má testované zálohy. Pre kritické údaje mnohé tímy uprednostňujú spravovanú databázovú službu, ktorá sa postará o núdzové prepnutie, aktualizácie a zálohy za vás.

Ako vrátim späť vydanie Docker ?

Označte každý obrázok hashom odovzdania Git a ponechajte predchádzajúcu značku. Ak chcete vrátiť späť, začnite kontajnery s predchádzajúcou značkou. Napíšte migrácie databázy, aby starší kód stále fungoval s novšou schémou.

Koľko pracovníkov php-fpm by som mal nakonfigurovať?

Zmerajte priemernú pamäť jedného pracovníka pri zaťažení, rozhodnite, koľko pamäte môže PHP použiť, a rozdeľte. Nastavenie príliš vysokej hodnoty spôsobí swapovanie, zatiaľ čo príliš nízke spôsobuje požiadavky vo fronte. Pozrite si denník php-fpm, kde nájdete upozornenia max_children.

Aká je najväčšia bezpečnostná chyba Docker s aplikáciami PHP ?

Vloženie tajomstiev do obrazu alebo Git a publikovanie databázových portov na internet. Vyhnite sa tiež spúšťaniu ako root, pripájaniu soketu Docker do kontajnerov a nikdy neaktualizovaniu základného obrazu.

Bezplatný objavovací hovor

Prineste chaotický stack alebo zaseknutú integráciu - Integrono namapuje najmúdrejší prvý krok.

Dostanete seniorský pohľad na rozpočtové pasce, závislosti a na to, či kúpiť, zlepiť alebo postaviť - kým nezačne platená práca. CEO ostáva v okruhu.