Konteneryzacja aplikacji PHP
Napisz gotowy do produkcji plik Dockerfile dla PHP
Konteneryzacja aplikacji PHP to bezpłatna lekcja PHP Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej PHP Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs PHP Academy zawiera 4 lekcji w sumie.
Dlaczego warto umieścić PHP w kontenerze
Powtarzalne wdrażanie PHP oznacza zamrożenie dokładnej wersji interpretera, rozszerzeń i bibliotek systemu operacyjnego razem z kodem. Obraz Docker zapewnia każdemu środowisku — komputerowi dewelopera, CI i produkcji — ten sam wynik php -v oraz ten sam zestaw ext-*.
W tej lekcji zbudujemy obraz gotowy do produkcji: PHP-FPM, tylko potrzebne rozszerzenia, dostrojone konfiguracje, użytkownika niebędącego rootem oraz kontrolę poprawności działania.
Obraz bazowy FPM a Apache
Oficjalne obrazy PHP są dostępne w kilku wariantach. W przypadku produkcyjnej aplikacji internetowej działającej za nginx/traefik należy preferować php:8.3-fpm-alpine (mały) lub php:8.3-fpm (Debian, glibc — mniej niespodzianek związanych z bibliotekami natywnymi).
cli— procesy robocze, kolejki, cronfpm— menedżer procesów FastCGI, używany z nginxapache— wbudowany Apache, wygodny, ale cięższy
Należy przypiąć wersję minor. W produkcji nigdy nie należy używać :latest.
# 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.Instalowanie rozszerzeń
W tych obrazach nigdy nie należy wykonywać apt install php-xxx — trzeba używać dołączonych pomocników docker-php-ext-install, docker-php-ext-configure oraz pecl. Skrypt install-php-extensions (mlocati) to skrót będący de facto standardem, który pobiera odpowiednie nagłówki deweloperskie.
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 \
bcmathComposer w obrazie
Należy skopiować plik binarny Composer z jego oficjalnego obrazu zamiast pobierać instalator za pomocą curl. W produkcji trzeba uruchamiać composer install z opcjami --no-dev i --optimize-autoloader, a najpierw skopiować wyłącznie composer.json/composer.lock, aby warstwa zależności była buforowana niezależnie od zmian w kodzie źródłowym.
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-authoritativeDostosowywanie php.ini
Obraz bazowy zawiera szablony php.ini-production i php.ini-development. Należy włączyć wariant produkcyjny, a następnie umieścić własne nadpisania w katalogu conf.d — ten katalog jest scalany jako ostatni, więc jego ustawienia mają pierwszeństwo.
Najważniejsze wartości produkcyjne to: opcache.enable=1, opcache.validate_timestamps=0 (niezmienny kod w obrazie) oraz rozsądna wartość memory_limit.
# 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.iniPlik nadpisujący konfigurację OPcache
To największa pojedyncza korzyść w środowisku produkcyjnym. Przy ustawieniu validate_timestamps=0 PHP nie sprawdza już metadanych plików przy każdym żądaniu — oznacza to jednak, że wdrożenie zmian WYMAGA ponownego zbudowania obrazu (dokładnie tego oczekujemy od niezmiennych kontenerów).
; 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-dataUruchamianie jako użytkownik niebędący rootem
Obraz już definiuje użytkownika www-data. Uruchamianie FPM jako root niepotrzebnie zwiększa powierzchnię ataku. Należy ustawić właściciela zapisywalnych ścieżek (pamięci podręcznej i logów), a następnie przełączyć użytkownika za pomocą USER przed CMD.
Czy proces główny FPM nadal wiąże się z uprzywilejowanymi portami? Nie — FPM nasłuchuje na porcie 9000 (nieuprzywilejowanym), więc uruchomienie jako użytkownik niebędący rootem jest proste.
# 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"]Kontrole poprawności działania
Orkiestratory potrzebują sygnału, że FPM rzeczywiście działa, a nie tylko informacji, że proces istnieje. cgi-fcgi może wysłać ping do punktu końcowego FPM /status lub /ping. Najpierw należy włączyć pm.status_path i ping.path w puli 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 1Kompletowanie Dockerfile
Oto spójny, produkcyjny Dockerfile wykorzystujący jeden etap. W następnej lekcji podzielimy go na wiele etapów, aby usunąć narzędzia potrzebne tylko podczas budowania. Proszę zwrócić uwagę na kolejność: zależności → konfiguracja → kod źródłowy → autoload → przełączenie użytkownika.
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"]Weryfikacja procesu budowania
Po zbudowaniu obrazu należy sprawdzić, co faktycznie się w nim znalazło: wersję PHP, załadowane rozszerzenia oraz to, czy walidacja OPcache jest wyłączona. Krótki skrypt CLI potwierdza wymagania środowiska uruchomieniowego, od których zależy aplikacja.
<?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'));
?>Higiena kontekstu budowania
Plik .dockerignore ogranicza rozmiar kontekstu budowania i zapobiega przedostawaniu się sekretów oraz zbędnych danych z katalogu vendor do obrazu, a także unieważnianiu pamięci podręcznej. Należy wykluczyć vendor, systemy kontroli wersji, pliki środowiskowe i lokalne narzędzia.
# .dockerignore
.git
.gitignore
vendor/
node_modules/
.env
.env.*
tests/
*.md
docker-compose*.yml
storage/logs/*
var/cache/*Szybkie sprawdzenie
Dlaczego w obrazie produkcyjnym należy ustawić opcache.validate_timestamps=0?
Podsumowanie
Zbudowano produkcyjny obraz PHP-FPM: użyto przypiętej do wersji bazy 8.3-fpm-alpine, zainstalowano tylko potrzebne rozszerzenia za pomocą skryptu instalatora, skopiowano Composer i buforowane zależności do osobnej warstwy, włączono produkcyjny plik php.ini z nadpisaniem konfiguracji OPcache, przełączono użytkownika na www-data i dodano kontrolę zdrowia FPM.
Najważniejsze zasady: przypinać wersje, buforować warstwę zależności, uruchamiać procesy bez uprawnień roota, wyłączać walidację znaczników czasu oraz utrzymywać niewielki kontekst budowania za pomocą .dockerignore.
Często zadawane pytania
Czy lekcja „Konteneryzacja aplikacji PHP” jest bezpłatna?
Tak — pełny tekst „Konteneryzacja aplikacji PHP” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu PHP Academy, przejdź na CoddyKit PRO. Kurs PHP Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Konteneryzacja aplikacji PHP”?
Napisz gotowy do produkcji plik Dockerfile dla PHP Ćwiczysz PHP Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć PHP Academy?
Nie wymagamy żadnego doświadczenia. PHP Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.
Ile czasu zajmuje lekcja „Konteneryzacja aplikacji PHP”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji PHP Academy?
Tak. Każda lekcja PHP Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Konteneryzacja aplikacji PHP
- Kompilacje wieloetapowe i optymalizacja
- Docker Compose dla lokalnych stosów
- CI/CD z GitHub Actions