Docker pro PHP ve výrobě: praktický průvodce nastavením pro podnikové aplikace
Docker umožňuje, aby aplikace PHP běžela stejným způsobem na přenosném počítači, při testování i v produkci, a namísto stresu je vydávání a navracení rutinou. Přidává také pohyblivé části a neopatrné nastavení je horší než obyčejný server. Tato příručka ukazuje výchozí stav připravený k výrobě se skutečnou konfigurací a situace, kdy byste se neměli obtěžovat.
Ve zkratce
- Docker stojí za to, když chcete stejná prostředí, rychlé vrácení zpět a snadné začlenění. Pro jednu malou brožuru na sdíleném hostingu je to obvykle zbytečné.
- Vytvořte neměnný obraz v CI: vícestupňové sestavení, pouze produkční závislosti, uživatel bez oprávnění root, zapnutá OPcache, chyby se zaznamenávají a nikdy se nezobrazují.
- Uvolněte pomocí značky obrázku (hash commit Git), po spuštění zkontrolujte stav a v případě selhání kontroly se automaticky vraťte k předchozí značce.
- Kontejnery jsou na jedno použití, data nikoli: databázi a nahrané položky uchovávejte ve svazcích nebo spravovaných službách a zálohujte je mimo Docker.
- Nejčastější produkční chyby: tajemství v obraze, publikované databázové porty, neomezené logy a limity php-fpm, které neodpovídají paměti, kterou máte.
U mnoha podnikových aplikací není skutečnými náklady na hosting server, ale lidé. Nastavení, kterému rozumí pouze jeden vývojář, nasazení prováděné ručně přes FTP a pracovní prostředí, které se chová odlišně od produkčního, jsou z dlouhodobého hlediska drahé. Kontejnery to řeší zabalením aplikace s její přesnou verzí PHP a rozšířeními. Své vlastní stránky PHP a klientské systémy provozujeme na zásobníku založeném na Dockeru a tato příručka popisuje základní linii, ze které vycházíme.
Kdy se Docker vyplatí a kdy ne
- Vyplatí se: několik služeb (web, PHP, databáze, fronta), více než jeden vývojář, potřeba opakovatelných verzí a rychlých návratů nebo plán na přesun mezi poskytovateli.
- Není nutné: jednoduchý obsahový web, který se na spravovaném hostingu mění jen zřídka. Přidaná složitost vyžaduje odplatu.
- Není náhradou za dobré operace: stále potřebujete opravy, zálohování a monitorování. Podívejte se na našeho průvodce zálohováním a monitorováním.
Cílová architektura
Solidní a jednoduché nastavení pro aplikaci PHP na jednom serveru:
- Reverzní proxy a TLS na okraji ( Nginx nebo Caddy na hostiteli nebo CDN, jako je Cloudflare, viz průvodce nastavením Cloudflare).
- Webový kontejner ( Nginx), který obsluhuje statické soubory a předává PHP požadavky dál.
- PHP-FPM kontejner s vaším kódem, zabudovaným do obrazu.
- Databáze ve vlastním kontejneru s trvalým svazkem, nebo lépe spravovaná databázová služba pro kritická data.
- Svazky pouze pro data, která musí přežít: databázové soubory a nahrání uživatelů.
Vícefázový Dockerfile
Vícestupňové sestavení nainstaluje závislosti v jedné fázi a zkopíruje pouze výsledek do tenkého runtime obrazu. Finální obrázek neobsahuje žádný Composer, kompilátory ani testovací nástroje, což jej zmenšuje a útočníkům umožňuje méně použití:
# ---- 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áměrně vyberte verzi PHP a zkontrolujte, zda je stále podporována. Náš průvodce upgradem PHP 8 vysvětluje, jak to naplánovat. Připněte si verze základních obrazů a aktualizujte je podle plánu, protože obraz, který nikdy neobnovíte, hromadí známé chyby zabezpečení. Udržujte .dockerignore, který vylučuje .git, .env, testy a místní data, takže v obrazu neskončí nic citlivého.
Produkční konfigurace PHP a 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
Nastavení opcache.validate_timestamps = 0 poskytuje nejlepší výkon pro neměnný obraz, ale funguje pouze tehdy, pokud nikdy neupravujete soubory uvnitř běžícího kontejneru: místo toho uvolníte nový obraz. Určete velikost fondu z reálných čísel: změřte průměrnou paměť jednoho pracovníka PHP při zatížení, rozhodněte, kolik paměti může PHP na serveru použít, a rozdělte. Pokud pracovník používá 60 MB a vy můžete dát PHP 1 GB, pm.max_children je asi 16. Nastavení mnohem vyšší způsobí, že proces swapování serveru nebo zabíjení jádra během špičky provozu. Příliš nízká a fronta požadavků. Zkontrolujte protokol php-fpm, zda neobsahuje varování „max_children reach“.
Vytvořit soubor se správnými výchozí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ázek je malý obrázek Nginx se zkopírovanou vaší public/ složkou a konfigurací webu, zabudovaný ve stejném kanálu jako obrázek PHP. Klíčové body: svázat publikované porty na 127.0.0.1, nikdy nepublikovat databázi, nastavit zásady restartování, omezit paměť, aby jeden kontejner nemohl odstranit hostitele, a omezit velikost protokolu. Pamatujte, že porty publikované Docker mohou obejít pravidla brány firewall hostitele, jak vysvětlujeme v příručce Cloudflare. Nikdy nepřipojujte soket Docker do aplikačního kontejneru, protože tomuto kontejneru dává kontrolu nad hostitelem.
Vydání a vrácení zpět
Nejlepší funkcí nastavení založeného na obrázcích je, že každé vydání je značka a vrácení zpět je „zahájit předchozí značku“. Označte obrázky pomocí hash commitu Git, nikdy se nespoléhejte na latest a nechte skript vydání ověřit 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
Změny databáze vyžadují péči: zapište migrace, aby předchozí verze kódu stále fungovala s novým schématem (nejprve přidejte sloupce, v pozdější verzi je odstraňte). To je to, co dělá rychlý návrat bezpečným. Proveďte zálohu databáze před vydáním, které změní schéma.
Stavba a expedice od CI
Vytvořte obraz jednou v CI a nasaďte přesně tento artefakt. Minimální 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 }}"
Před vytvořením obrazu spusťte testy a statickou analýzu ve stejném kanálu a použijte klíč nasazení, který může spustit pouze skript vydání. Přidejte skenování zranitelnosti obrázků, pokud to váš rizikový profil vyžaduje.
Protokoly, data a zabezpečení
- Protokoly jdou do stdout a stderr, jsou rotovány Docker a pro cokoliv důležitého jsou odeslány na centrální místo, aby přežily kontejner.
- Data žijí mimo kontejner. Svazek není záloha. Použijte přístup v našem průvodci zálohováním: šifrované, off-site, testováno obnovením.
- Tajemství se nikdy nezapečou do obrazů. Předejte je za běhu prostřednictvím souborů env nebo správce tajemství a udržujte je mimo Git.
- Spusťte jako uživatel bez oprávnění root, používejte souborový systém pouze pro čtení, kde je to možné, a zahoďte to, co nepotřebujete.
- Udržujte snímky čerstvé. Pravidelně přestavujte, abyste získali opravy zabezpečení v základním obrazu a PHP.
- Použijte ovládací prvky na úrovni aplikace z našeho kontrolního seznamu zabezpečení PHP, protože kontejnery neopravují nezabezpečený kód.
Kontrolní seznam připravenosti výroby
- Vícestupňový obraz pouze s produkčními závislostmi, připnutý základní obraz, uživatel bez oprávnění root.
- OPcache povolena, chyby se nezobrazují, velikost php-fpm z naměřené paměti.
- Vytvořte soubor se zásadami restartování, zdravotními kontrolami, limity paměti, rotací protokolů a žádným veřejným databázovým portem.
- Vydání pomocí tagu commit-hash s automatickou kontrolou stavu a vrácením zpět.
- Zálohy a testovaná obnova databáze a nahrávání.
- Monitorování a upozornění na stav, disk, chyby a certifikáty.
Jak můžeme pomoci
Kontejnerizujeme aplikace PHP, nastavujeme kanály a verze CI a propojujeme je s platbami, CRM a zasíláním zpráv. Podívejte se na naši integrační službu nebo si zavolejte a my zkontrolujeme váš aktuální proces hostování a vydávání.
Časté otázky
Je Docker dobrý pro spuštění PHP v produkci?
Ano, když se dobře používá. Poskytuje identická prostředí, opakovatelné verze a rychlé vrácení zpět. Potřebuje správnou konfiguraci: neměnné obrazy, kontroly stavu, limity zdrojů, rotaci protokolů, správu tajemství a zálohování dat mimo kontejner.
Měla by databáze běžet v Docker v produkci?
U malých a středních systémů může, pokud používá trvalý svazek, není nikdy veřejně přístupný a má otestované zálohy. Pro kritická data mnoho týmů upřednostňuje spravovanou databázovou službu, která se postará o převzetí služeb při selhání, aktualizace a zálohy za vás.
Jak vrátím vydání Docker ?
Označte každý obrázek hashem Git commit a ponechte předchozí značku. Chcete-li se vrátit zpět, začněte kontejnery s předchozí značkou. Napište migrace databáze, aby starší kód stále fungoval s novějším schématem.
Kolik pracovníků php-fpm bych měl nakonfigurovat?
Změřte průměrnou paměť jednoho pracovníka při zatížení, rozhodněte, kolik paměti může PHP používat, a rozdělte. Nastavení příliš vysoké hodnoty způsobí odkládání, zatímco příliš nízké způsobí požadavky ve frontě. Podívejte se na php-fpm log pro max_children varování.
Jaká je největší bezpečnostní chyba Docker s aplikacemi PHP ?
Vkládání tajemství do obrazu nebo Git a publikování databázových portů na internet. Také se vyhněte spouštění jako root, připojování soketu Docker do kontejnerů a nikdy neaktualizujte základní obraz.
Volání bezplatného zjišťování
Přineste chaotický stack nebo zaseknutou integraci - Integrono namapuje nejchytřejší první krok.
Dostanete seniorský pohled na rozpočtové pasti, závislosti a na to, zda koupit, slepit nebo postavit - než začne placená práce. CEO zůstává v okruhu.