PHP Academy · Урок

Контейнеризация PHP-приложения

Напишите готовый к эксплуатации PHP Dockerfile

Урок 1 из 413 шагов

«Контейнеризация PHP-приложения» — бесплатный урок PHP Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения PHP Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс PHP Academy содержит 4 уроков всего.

Зачем контейнеризировать PHP

Предсказуемая поставка PHP означает фиксацию точной версии интерпретатора, расширений и библиотек ОС вместе с кодом. Образ Docker предоставляет каждой среде — ноутбуку, среде непрерывной интеграции и рабочей среде — одинаковый результат php -v и одинаковый набор ext-*.

В этом уроке мы создадим образ, готовый к эксплуатации: PHP-FPM, только нужные расширения, настроенные конфигурации, пользователя без прав суперпользователя и проверку работоспособности.

FPM или базовый образ Apache

Официальные образы PHP выпускаются в разных вариантах. Для рабочего веб-приложения за nginx или traefik выбирайте php:8.3-fpm-alpine (компактный) или php:8.3-fpm (Debian, glibc — меньше неожиданностей с нативными библиотеками).

  • cli — рабочие процессы, очереди, планировщик заданий
  • fpm — менеджер процессов FastCGI, работает в паре с nginx
  • apache — встроенный Apache, удобно, но тяжелее

Зафиксируйте минорную версию. Никогда не используйте :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.

Установка расширений

Никогда не выполняйте apt install php-xxx внутри этих образов — используйте встроенные вспомогательные средства docker-php-ext-install, docker-php-ext-configure и pecl. Скрипт install-php-extensions от mlocati — фактический стандартный способ, который сам загружает нужные заголовочные файлы для разработки.

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 в образе

Копируйте исполняемый файл Composer из его официального образа, а не загружайте установщик напрямую. Для рабочей среды запускайте composer install с параметрами --no-dev и --optimize-autoloader, а сначала копируйте только composer.json и composer.lock, чтобы слой зависимостей кэшировался независимо от изменений исходного кода.

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

Настройка php.ini

Базовый образ содержит шаблоны php.ini-production и php.ini-development. Активируйте производственный вариант, затем добавьте собственные переопределения в conf.d: этот каталог объединяется последним, поэтому его значения имеют приоритет.

Основные значения для рабочей среды: opcache.enable=1, opcache.validate_timestamps=0 (неизменяемый код в образе) и разумное ограничение 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.ini

Файл переопределения OPcache

Это самое значительное улучшение для рабочей среды. При значении validate_timestamps=0 PHP не проверяет метаданные файлов при каждом запросе, но это означает, что вы MUST пересобирать образ для развёртывания изменений — именно этого мы и хотим от неизменяемых контейнеров.

; 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

Запуск без прав суперпользователя

В образе уже определён пользователь www-data. Запуск FPM от имени суперпользователя без необходимости увеличивает поверхность атаки. Назначьте владельца для доступных на запись путей (кэша и журналов) и переключите пользователя с помощью USER перед CMD.

Главный процесс FPM всё ещё привязывается к привилегированным портам? Нет — FPM прослушивает порт 9000 (непривилегированный), поэтому запуск без прав суперпользователя прост.

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

Проверки работоспособности

Оркестраторам нужен сигнал о том, что FPM действительно работает, а не просто что процесс существует. cgi-fcgi может отправить запрос конечной точке FPM /status или /ping. Сначала включите pm.status_path и ping.path в пуле 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

Составление Dockerfile

Вот цельный рабочий Dockerfile с одним этапом. На следующем уроке мы разделим его на несколько этапов, чтобы исключить инструменты сборки. Обратите внимание на порядок: зависимости → конфигурация → исходный код → автозагрузчик → смена пользователя.

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

Проверка сборки

После сборки проверьте, что действительно попало в образ: версию PHP, загруженные расширения и отключённую проверку OPcache. Небольшой сценарий для CLI подтверждает контракт среды выполнения, от которого зависит ваше приложение.

<?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'));
?>

Гигиена контекста сборки

.dockerignore уменьшает контекст сборки и не позволяет секретам и разросшимся зависимостям из vendor попасть в образ и нарушить кэширование. Исключите vendor, VCS, файлы env и локальные инструменты.

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

Быстрая проверка

Зачем устанавливать opcache.validate_timestamps=0 в рабочем образе?

Итоги

Вы создали рабочий образ PHP-FPM: закрепили базовый образ 8.3-fpm-alpine, установили только необходимые расширения с помощью сценария установки, скопировали Composer и кэшированные зависимости в отдельный слой, активировали рабочий php.ini с переопределением настроек OPcache, переключились на www-data и добавили проверку работоспособности FPM.

Главные привычки: закрепляйте версии, кэшируйте слой зависимостей, запускайте процессы от имени непривилегированного пользователя, отключайте проверку временных меток и уменьшайте контекст сборки с помощью .dockerignore.

Можно начать бесплатно

Изучай PHP с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
49
Уроки
195

Часто задаваемые вопросы

Урок «Контейнеризация PHP-приложения» бесплатный?

Да — полный текст урока «Контейнеризация PHP-приложения» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс PHP Academy, подпишись на CoddyKit PRO. Курс PHP Academy содержит 4 уроков всего.

Чему я научусь в уроке «Контейнеризация PHP-приложения»?

Напишите готовый к эксплуатации PHP Dockerfile Ты практикуешь PHP Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать PHP Academy?

Предыдущий опыт не требуется. PHP Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Контейнеризация PHP-приложения»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке PHP Academy?

Да. Каждый урок PHP Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Контейнеризация PHP-приложения
  2. Многоэтапная сборка и оптимизация
  3. Docker Compose для локальных стеков
  4. CI/CD с GitHub Actions
← Назад к PHP Academy