0Pricing
PHP Academy · Lezione

Containerizzare un'applicazione PHP

Scriva un Dockerfile PHP pronto per la produzione

Containerizzare un'applicazione PHP è una lezione PHP Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento PHP Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso PHP Academy include 4 lezioni in totale.

Perché usare i container per PHP

Distribuire PHP in modo riproducibile significa fissare la versione esatta dell'interprete, le estensioni e le librerie del sistema operativo insieme al codice. Un'immagine Docker offre a ogni ambiente — computer dello sviluppatore, CI e produzione — lo stesso php -v e lo stesso insieme di ext-*.

In questa lezione costruiamo un'immagine pronta per la produzione: PHP-FPM, solo le estensioni necessarie, configurazioni ottimizzate, un utente non root e un controllo dello stato.

FPM rispetto alla base Apache

Le immagini ufficiali di PHP sono disponibili in diverse varianti. Per un'applicazione web in produzione dietro nginx/traefik, preferisca php:8.3-fpm-alpine (più piccola) oppure php:8.3-fpm (Debian, glibc: meno sorprese con le librerie native).

  • cli — worker, code e cron
  • fpm — gestore dei processi FastCGI, da abbinare a nginx
  • apache — Apache integrato, comodo ma più pesante

Blocchi la versione minor. Non usi mai :latest in produzione.

# Base image choice in your Dockerfile
FROM php:8.3-fpm-alpine AS base

# Why alpine? ~30MB base vs ~140MB Debian.
# Tradeoff: musl libc, occasional native-extension friction.

Installare le estensioni

Non esegua mai apt install php-xxx all'interno di queste immagini: utilizzi gli helper inclusi docker-php-ext-install, docker-php-ext-configure e pecl. Lo script install-php-extensions (mlocati) è la scorciatoia de facto che recupera per voi le intestazioni di sviluppo corrette.

FROM php:8.3-fpm-alpine

# Grab the helper that resolves build deps automatically
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/

RUN chmod +x /usr/local/bin/install-php-extensions && \
    install-php-extensions \
        pdo_mysql \
        opcache \
        intl \
        zip \
        redis \
        bcmath

Composer nell'immagine

Copi il binario di Composer dalla sua immagine ufficiale invece di scaricare un installer con curl. Esegua composer install con --no-dev e --optimize-autoloader per la produzione e copi solo composer.json/composer.lock per primi, così il layer delle dipendenze viene memorizzato nella cache indipendentemente dalle modifiche al codice sorgente.

COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

WORKDIR /app

# Cache-friendly: deps layer invalidates only when lock changes
COPY composer.json composer.lock ./
RUN composer install \
        --no-dev \
        --no-scripts \
        --no-autoloader \
        --prefer-dist

COPY . .
RUN composer dump-autoload --optimize --classmap-authoritative

Ottimizzare php.ini

L'immagine di base include i template php.ini-production e php.ini-development. Attivi quello per la produzione, poi inserisca le proprie sovrascritture in conf.d: questa directory viene unita per ultima, quindi prevale.

Valori di produzione fondamentali: opcache.enable=1, opcache.validate_timestamps=0 (codice immutabile nell'immagine) e un memory_limit ragionevole.

# Activate production ini
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

# Custom overrides win because conf.d loads last
COPY docker/php/zz-app.ini $PHP_INI_DIR/conf.d/zz-app.ini

Il file di sovrascrittura di OPcache

Questa è la singola ottimizzazione più importante per la produzione. Con validate_timestamps=0, PHP non esegue mai lo stat dei file a ogni richiesta; tuttavia, ciò significa che DOVETE ricostruire l'immagine per distribuire le modifiche, esattamente ciò che desideriamo per i container immutabili.

; docker/php/zz-app.ini
memory_limit = 256M
expose_php = Off

opcache.enable = 1
opcache.enable_cli = 0
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 0
opcache.preload = /app/preload.php
opcache.preload_user = www-data

Eseguire come utente non root

L'immagine definisce già www-data. Eseguire FPM come root aumenta inutilmente la superficie di attacco. Imposti la proprietà dei percorsi scrivibili (cache e log) e cambi utente con USER prima di CMD.

Il processo master di FPM si associa comunque a porte privilegiate? No: FPM ascolta sulla porta 9000 (non privilegiata), quindi eseguirlo come utente non root è semplice.

# Make runtime-writable dirs owned by the runtime user
RUN chown -R www-data:www-data /app/var /app/storage 2>/dev/null || true

USER www-data

EXPOSE 9000
CMD ["php-fpm"]

Controlli dello stato

Gli orchestratori hanno bisogno di un segnale che indichi che FPM è effettivamente attivo, non solo che il processo esiste. cgi-fcgi può eseguire il ping dell'endpoint FPM /status o /ping. Prima abiliti pm.status_path e ping.path nel pool FPM.

# In www.conf pool config:
;   ping.path = /ping
;   ping.response = pong

# Dockerfile HEALTHCHECK using cgi-fcgi
RUN install-php-extensions @composer >/dev/null 2>&1 || true

HEALTHCHECK --interval=10s --timeout=3s --retries=3 \
  CMD SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET \
      cgi-fcgi -bind -connect 127.0.0.1:9000 || exit 1

Comporre il Dockerfile

Ecco un Dockerfile di produzione coerente a singolo stage. Nella prossima lezione lo suddivideremo in più stage per eliminare gli strumenti di build. Noti l'ordine: dipendenze → configurazione → sorgente → autoload → cambio utente.

FROM php:8.3-fpm-alpine

ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions && \
    install-php-extensions pdo_mysql opcache intl zip redis

COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /app

RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY docker/php/zz-app.ini $PHP_INI_DIR/conf.d/

COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist
COPY . .
RUN composer dump-autoload --optimize --classmap-authoritative && \
    chown -R www-data:www-data /app/var

USER www-data
EXPOSE 9000
CMD ["php-fpm"]

Verificare la build

Dopo la build, esegua un controllo di integrità su ciò che è effettivamente finito nell'immagine: versione di PHP, estensioni caricate e convalida di OPcache disattivata. Un rapido script CLI conferma il contratto di runtime da cui dipende l'applicazione.

<?php
// Run inside the container: php verify.php
echo 'PHP ' . PHP_VERSION . PHP_EOL;

$required = ['pdo_mysql', 'opcache', 'intl', 'zip'];
foreach ($required as $ext) {
    printf("%-12s %s\n", $ext, extension_loaded($ext) ? 'OK' : 'MISSING');
}

var_dump((bool) ini_get('opcache.enable'));
?>

Pulizia del contesto di build

Un .dockerignore mantiene ridotte le dimensioni del contesto di build e impedisce che segreti e contenuti superflui di vendor finiscano nell'immagine e invalidino la cache. Escluda vendor, VCS, file env e strumenti locali.

# .dockerignore
.git
.gitignore
vendor/
node_modules/
.env
.env.*
tests/
*.md
docker-compose*.yml
storage/logs/*
var/cache/*

Controllo rapido

Perché impostare opcache.validate_timestamps=0 in un'immagine di produzione?

Riepilogo

Ha creato un'immagine PHP-FPM per la produzione: base 8.3-fpm-alpine con versione fissata, installazione delle sole estensioni necessarie tramite lo script di installazione, copia di Composer e delle dipendenze memorizzate nella cache in un layer dedicato, attivazione del php.ini di produzione con un override di OPcache, passaggio all'utente www-data e aggiunta di un health check FPM.

Abitudini fondamentali: fissare le versioni, memorizzare nella cache il layer delle dipendenze, eseguire come utente non-root, disattivare la convalida dei timestamp e mantenere snello il contesto di build con .dockerignore.

Domande Frequenti

La lezione «Containerizzare un'applicazione PHP» è gratuita?

Sì — il testo completo di «Containerizzare un'applicazione PHP» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso PHP Academy, passa a CoddyKit PRO. Il corso PHP Academy include 4 lezioni in totale.

Cosa imparerò in «Containerizzare un'applicazione PHP»?

Scriva un Dockerfile PHP pronto per la produzione Eserciti PHP Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare PHP Academy?

Non è richiesta alcuna esperienza precedente. PHP Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.

Quanto tempo richiede la lezione «Containerizzare un'applicazione PHP»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione PHP Academy?

Sì. Ogni lezione PHP Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Containerizzare un'applicazione PHP
  2. Build multi-stage e ottimizzazione
  3. Docker Compose per gli stack locali
  4. CI/CD con GitHub Actions
← Torna a PHP Academy